1 # vim: ft=tcl foldmethod=marker foldmarker=<<<,>>> ts=4 shiftwidth=4
3 if {[lsearch [namespace children] ::tcltest] == -1} {
4 package require tcltest 2.2.5
5 namespace import ::tcltest::*
8 package require TLC-base
10 test signals-1.1 {Create a Signal} -body { #<<<
11 tlc::Signal #auto signal
12 $signal isa tlc::Signal
14 if {[info exists signal] && [itcl::is object $signal]} {
20 test signals-1.2 {Test initial state is false} -body { #<<<
21 tlc::Signal #auto signal
24 if {[info exists signal] && [itcl::is object $signal]} {
30 test signals-1.3 {Setting state true} -body { #<<<
31 tlc::Signal #auto signal
35 if {[info exists signal] && [itcl::is object $signal]} {
41 test signals-1.4 {State normalization} -body { #<<<
42 tlc::Signal #auto signal
43 $signal set_state true
46 if {[info exists signal] && [itcl::is object $signal]} {
52 test signals-1.5 {Rejection of non booleans} -body { #<<<
53 tlc::Signal #auto signal
54 $signal set_state maybe
56 if {[info exists signal] && [itcl::is object $signal]} {
62 } -result {newstate must be a valid boolean}
64 test signals-1.6 {Toggle state} -body { #<<<
65 tlc::Signal #auto signal
69 if {[info exists signal] && [itcl::is object $signal]} {
75 test signals-1.7 {Auto lifecycle management} -body { #<<<
76 tlc::Signal #auto signal
78 set before [itcl::is object $hold]
80 set after [itcl::is object $hold]
83 if {[info exists signal] && [itcl::is object $signal]} {
87 if {[info exists hold]} {
92 test signals-1.8 {State change callback} -body { #<<<
93 tlc::Signal #auto signal
94 $signal attach_output {apply {
96 set ::state_from_callback $newstate
100 set ::state_from_callback
102 if {[info exists signal] && [itcl::is object $signal]} {
103 delete object $signal
106 if {[info exists ::state_from_callback]} {
107 unset ::state_from_callback
111 test signals-1.9 {State change callback, state initialization} -body { #<<<
112 tlc::Signal #auto signal
113 $signal attach_output {apply {
115 set ::state_from_callback $newstate
118 set ::state_from_callback
120 if {[info exists signal] && [itcl::is object $signal]} {
121 delete object $signal
124 if {[info exists ::state_from_callback]} {
125 unset ::state_from_callback
129 test signals-1.10 {State change callback, state propagation optimization} -body { #<<<
130 tlc::Signal #auto signal
131 $signal attach_output {apply {
133 lappend ::state_from_callback $newstate
140 set ::state_from_callback
142 if {[info exists signal] && [itcl::is object $signal]} {
143 delete object $signal
146 if {[info exists ::state_from_callback]} {
147 unset ::state_from_callback
151 test signals-1.11 {Detatch state change callback} -body { #<<<
152 tlc::Signal #auto signal
155 lappend ::state_from_callback $newstate
158 $signal attach_output $handler
160 $signal detach_output $handler
163 set ::state_from_callback
165 if {[info exists signal] && [itcl::is object $signal]} {
166 delete object $signal
169 if {[info exists ::state_from_callback]} {unset ::state_from_callback}
170 if {[info exists handler]} {unset handler}
173 test signals-1.12 {Detatch from outputs at death} -body { #<<<
174 tlc::Signal #auto signals(1)
175 tlc::Signal #auto signals(2)
176 tlc::Gate #auto signals(gate) -mode and
178 $signals(gate) attach_input $signals(1)
179 $signals(gate) attach_input $signals(2)
181 $signals(2) set_state 1
183 set before [$signals(gate) state]
184 array unset signals 1
185 set after [$signals(gate) state]
190 if {[info exists before]} {unset before}
191 if {[info exists after]} {unset after}
194 test signals-1.13 {Handling of -name} -body { #<<<
195 tlc::Signal #auto signals(1) -name "Test signal"
199 } -result {Test signal}
201 test signals-1.14 {explain_txt method} -body { #<<<
202 tlc::Signal sigtest-1.14 signals(1) -name "Test signal"
203 list [$signals(1) explain_txt] [$signals(1) explain_txt 2]
206 } -result {{::sigtest-1.14 "Test signal": 0
207 } { ::sigtest-1.14 "Test signal": 0
210 test signals-1.15 {waitfor, target state (false) already set} -body { #<<<
211 tlc::Signal #auto signals(1)
214 set afterid [after 100 [list apply {
221 $signals(1) waitfor false
222 list $killed [$signals(1) state]
224 if {[info exists afterid]} {
225 after cancel $afterid
228 if {[info exists killed]} {
234 test signals-1.16 {waitfor, target state (true) already set} -body { #<<<
235 tlc::Signal #auto signals(1)
238 $signals(1) set_state 1
240 set afterid [after 100 [list apply {
247 $signals(1) waitfor true
248 list $killed [$signals(1) state]
250 if {[info exists afterid]} {
251 after cancel $afterid
254 if {[info exists killed]} {
260 test signals-1.17 {waitfor, target state (false) not already set} -body { #<<<
261 tlc::Signal #auto signals(1)
262 $signals(1) set_state 1
264 set before [clock milliseconds]
266 set timebomb [after 1000 [list apply {
268 puts "signals-1.17: timebomb went off"
269 if {[itcl::is object $obj]} {
275 set afterid [after 200 [list apply {
281 $signals(1) waitfor false
282 set after [clock milliseconds]
283 expr {$after - $before > 180}
285 if {[info exists afterid]} {
286 after cancel $afterid
289 if {[info exists timebomb]} {
290 after cancel $timebomb
296 test signals-1.18 {waitfor, target state (true) not already set} -body { #<<<
297 tlc::Signal #auto signals(1)
299 set before [clock milliseconds]
301 set timebomb [after 1000 [list apply {
303 puts "signals-1.18: timebomb went off"
304 if {[itcl::is object $obj]} {
310 set afterid [after 200 [list apply {
316 $signals(1) waitfor true
317 set after [clock milliseconds]
318 expr {$after - $before > 180}
320 if {[info exists afterid]} {
321 after cancel $afterid
324 if {[info exists timebomb]} {
325 after cancel $timebomb
331 test signals-1.19 {waitfor timeout, timeout reached} -body { #<<<
332 tlc::Signal #auto signals(1) -name "Test signal"
334 set timebomb [after 1000 [list apply {
336 puts "signals-1.19: timebomb went off"
337 if {[itcl::is object $obj]} {
343 set before [clock milliseconds]
346 $signals(1) waitfor true 200
348 set options [dict merge {-errorcode ""} $options]
350 set after [clock milliseconds]
351 list [expr {$after - $before >= 200}] $errmsg [dict get $options -errorcode]
353 if {[info exists timebomb]} {
354 after cancel $timebomb
357 foreach var {before after} {
358 if {[info exists $var]} {
363 } -result {1 {Timeout waiting for signal "Test signal"} {timeout {Test signal}}}
365 test signals-1.20 {waitfor timeout, timeout not reached} -body { #<<<
366 tlc::Signal #auto signals(1) -name "Test signal"
368 set timebomb [after 1000 [list apply {
370 puts "signals-1.20: timebomb went off"
371 if {[itcl::is object $obj]} {
377 set afterid [after 100 [list $signals(1) set_state 1]]
379 set before [clock milliseconds]
380 $signals(1) waitfor true 200
381 set after [clock milliseconds]
383 list [expr {$after - $before < 150}] [$signals(1) state]
385 if {[info exists afterid]} {
386 after cancel $afterid
389 if {[info exists timebomb]} {
390 after cancel $timebomb
393 foreach var {before after} {
394 if {[info exists $var]} {
401 test signals-1.21 {waitfor timeout, died before timeout or state reached} -body { #<<<
402 tlc::Signal #auto signals(1) -name "Test signal"
404 set timebomb [after 100 [list apply {
406 if {[itcl::is object $obj]} {
412 set afterid [after 200 [list apply {
414 if {[itcl::is object $obj]} {
421 $signals(1) waitfor true 1000
423 set options [dict merge {-errorcode ""} $options]
425 list $errmsg [dict get $options -errorcode]
427 if {[info exists afterid]} {
428 after cancel $afterid
431 if {[info exists timebomb]} {
432 after cancel $timebomb
436 } -result {{Source died while waiting for signal "Test signal"} {source_died {Test signal}}}
438 test signals-1.22 {waitfor timeout, state flop race} -body { #<<<
439 tlc::Signal ::#auto signals(1) -name "Test signal"
441 set afterid [after 100 [list apply {
449 $signals(1) waitfor true 1000
451 set options [dict merge {-errorcode ""} $options]
453 list $errmsg [dict get $options -errorcode]
455 if {[info exists afterid]} {
456 after cancel $afterid
460 } -result {{Timeout waiting for signal "Test signal"} {timeout {Test signal}}} -match glob -errorOutput {*Woken up by transient spike while waiting for state true, waiting for more permanent change*}
462 test signals-1.23 {Avoid double-adding output handler} -body { #<<<
463 tlc::Signal #auto signals(1) -name "Test signal"
469 set first [$signals(1) attach_output $handler]
470 set second [$signals(1) attach_output $handler]
474 foreach var {first second} {
475 if {[info exists $var]} {
483 test signals-1.24 {Detect double-removing output handler} -body { #<<<
484 tlc::Signal #auto signals(1) -name "Test signal"
490 $signals(1) attach_output $handler
491 set first [$signals(1) detach_output $handler]
492 set second [$signals(1) detach_output $handler]
496 foreach var {first second} {
497 if {[info exists $var]} {
505 test signals-1.25 {Catch error in output handler} -body { #<<<
506 tlc::Signal #auto signals(1) -name "Test signal"
510 $signals(1) attach_output {apply {
516 $signals(1) attach_output {apply {
518 set ::good_output_ok 1
524 foreach var {good_output_ok} {
525 if {[info exists $var]} {
531 } -result {1} -match glob -errorOutput {*"Test signal" error updating output (0) handler: (apply *Test error*}
533 test signals-1.26 {Debug mode output} -body { #<<<
534 tlc::Signal #auto signals(1) -name "Test signal" -debugmode 1 -output_handler_warntime 200
536 $signals(1) register_handler debug {apply {
542 $signals(1) attach_output {apply {
546 set ::afterids(1) [after 700 {set ::foo 1}]
555 set afterids(2) [after 100 [list array unset signals 1]]
556 $signals(1) set_state 1
558 itcl::is object $hold
560 foreach {num handle} [array get afterids] {
567 foreach var {hold foo} {
568 if {[info exists $var]} {
572 } -result {0} -match glob -output {*tlc::Signal::scopevar_unset:
573 ::tlc::Signal::scopevar_unset(args signals 1 u)
575 tlc::Signal::destructor: ::signal* Test signal dieing
576 tlc::Signal::destructor: ::signal* dieing from:
577 ::tlc::Signal::destructor(<undefined> {})
578 ::tlc::Signal::scopevar_unset(args signals 1 u)
580 tlc::Signal::destructor: ------ twitch: (apply {
582 tlc::Signal::detach_output: (apply {
584 tlc::Signal::destructor: ::signal* truely dead
585 tlc::Signal::update_outputs: Flagging changewaits: ()
588 test signals-1.27 {Feedback for slow output handlers} -body { #<<<
589 tlc::Signal #auto signals(1) -name "Test signal" -debugmode 1 -output_handler_warntime 200
591 $signals(1) attach_output {apply {
595 set ::afterids(1) [after 700 {set ::foo 1}]
602 $signals(1) set_state 1
606 foreach {num handle} [array get afterids] {
614 if {[info exists $var]} {
618 } -result {1} -match glob -errorOutput {*name: (Test signal) obj: (*) taking way too long to update output for handler: (apply *}
621 ::tcltest::cleanupTests