#---------------------------------------------------------------- # # customMatch matchDouble # # Custom match routine that performs word-by-word comparisons # using expr's floating point comparison operation (!=) # for words that are [string is double]. # # This custom match routine is required for tests to # run on Microsoft Windows (and perhaps other) platforms # where floating point numbers get a three digit # exponent (i.e. 3.0e008 instead of 3.0e08). # # Note that this routines treats all white space (spaces, # tabs and newlines) as equal. # #---------------------------------------------------------------- customMatch matchDouble matchDoubleProc proc matchDoubleProc {expectedResult actualResult} { # split expected/actual into list of words set elist [split $expectedResult " \t\n"] set alist [split $actualResult " \t\n"] # perform word-by-word comparison foreach eword $elist aword $alist { if { [string is double $eword] && ! [string is integer $eword] } { # perform numeric comparison if { $eword != $aword } {return 0} } else { # perform string comparison if { $eword ne $aword } {return 0} } } return 1 }
jnc The above was not working in my test cases. What about this?
proc matchDoubleProc {expectedResult actualResult} { set expectedFormatted [format $expectedResult] set decimalCount [string length [lindex [split $expectedFormatted "."] 1]] set fmtCode "%.${decimalCount}f" set actualFormatted [format $fmtCode $actualResult] if { $expectedFormatted eq $actualFormatted } { return 1 } return 0 }
An interesting variant on matchDouble would use a sigma parameter for approximate comparisons.
glennj I just started with tcltest and one use for customMatch jumped out at me. When I write functions that return a boolean, they might return the string "true" or "false", or they might return the result of an [expr] command (1/0). I wrote this customMatch that ensures the expected and actual values are either both true or both false (uses [apply], so required Tcl 8.5):
# test passes if expected and actual are both true or both false customMatch boolean {apply {{e a} {expr { [string is boolean -strict $e] && [string is boolean -strict $a] && (($e && $a) || (!$e && !$a)) }}}}The applied [test] command looks like:
test test-name {boolean command should return true} \ -body {command that returns some boolean value} \ -match boolean \ -result true
EF The following customMatch will test equality of dictionaries. It also uses [apply], thus is for "modern" Tcl. Note that it assumes that the content of the keys are strings, which might not be appropriate in all cases.
customMatch dictionary {apply {{expected actual} { if {[dict size $expected] != [dict size $actual]} { return 0 } dict for {k v} $expected { if {![dict exists $actual $k]} { return 0 } if {[dict get $actual $k] ne $v} { return 0 } } return 1 }}}