Richard Suchenwirth 2005-12-12 - Earlier versions of this "testing framework" are found in several pages of mine, but this latest result of evolution (or intelligent design ;-) just has to be shared. It's about adding self-tests to a file of Tcl code. When the file is loaded as part of a library, just the proc definitions are executed.
If however you feed this file directly to a tclsh, that fact is detected, and the e.g. calls are executed. If the result is not the one expected, this is reported on stdout; and in the end, you even get a little statistics, somehow like tcltest.
# PROLOG -- self-test: if this file is sourced at top level if {[info exists argv0]&&[file tail [info script]] eq [file tail $argv0]} { set Ntest 0; set Nfail 0 proc e.g. {cmd -> expected} { incr ::Ntest catch {uplevel 1 $cmd} res if {$res ne $expected} { puts "$cmd -> $res, expected $expected" incr ::Nfail } } } else {proc e.g. args {}} ;# does nothing, compiles to nothing ##------------- Your code goes here, with e.g. tests following proc sum {a b} {expr {$a+$b}} e.g. {sum 3 4} -> 7 proc mul {a b} {expr {$a*$b}} e.g. {mul 7 6} -> 42 # testing a deliberate error (this way, it passes): e.g. {expr 1/0} -> "divide by zero" ## EPILOG -- show statistics: e.g. {puts "[info script] : tested $::Ntest, failed $::Nfail"} -> ""
escargo 12 Dec 2005 - It might be interesting to refactor the code to put the predicate about if this file is sourced at top level as a separate piece of code. Other code could then use that predicate to decide about other actions to take in that case. (I think e.g. is very clever, just by itself.)
escargo 20 Mar 2006 - I just thought of another reason for isolating the predicate. This would one of those cases where the author wants to put in a small demonstration. It's perhaps interesting to note that it might be difficult to include both unit tests and a demonstration when you can only tell if a file has been sourced at top level. It looks like you either do both or neither; there's no obvious way to decide which to do otherwise. (Unless you check for some global variable, maybe.)
RS 2008-09-04 - For that requirement, one could use temporary environment variables:
if [info exists env(XTEST)] { # activate e.g. ... } if [info exists env(XDEMO)] { # perform demo here } $ XTEST=1 XDEMO=1 myscript.tcl
or, even more flexible: put the following line at a suitable position into the file:
if [info exists env(DO)] {eval $env(DO)} $ DO='puts hello; do this; do that' myscript.tcl