2 #pragma ident "%Z%%M% %I% %E% SMI"
6 # The author disclaims copyright to this source code. In place of
7 # a legal notice, here is a blessing:
9 # May you do good and not evil.
10 # May you find forgiveness for yourself and forgive others.
11 # May you share freely, never taking more than you give.
13 #***********************************************************************
14 # This file implements some common TCL routines used for regression
15 # testing the SQLite library
17 # $Id: tester.tcl,v 1.28 2004/02/14 01:39:50 drh Exp $
19 # Make sure tclsqlite was compiled correctly. Abort now with an
20 # error message if not.
22 if {[sqlite
-tcl-uses
-utf
]} {
23 if {"\u1234"=="u1234"} {
24 puts stderr
"***** BUILD PROBLEM *****"
25 puts stderr
"$argv0 was linked against an older version"
26 puts stderr
"of TCL that does not support Unicode, but uses a header"
27 puts stderr
"file (\"tcl.h\") from a new TCL version that does support"
28 puts stderr
"Unicode. This combination causes internal errors."
29 puts stderr
"Recompile using a TCL library and header file that match"
30 puts stderr
"and try again.\n**************************"
34 if {"\u1234"!="u1234"} {
35 puts stderr
"***** BUILD PROBLEM *****"
36 puts stderr
"$argv0 was linked against an newer version"
37 puts stderr
"of TCL that supports Unicode, but uses a header file"
38 puts stderr
"(\"tcl.h\") from a old TCL version that does not support"
39 puts stderr
"Unicode. This combination causes internal errors."
40 puts stderr
"Recompile using a TCL library and header file that match"
41 puts stderr
"and try again.\n**************************"
46 # Use the pager codec if it is available
48 if {[sqlite
-has-codec
] && [info command sqlite_orig
]==""} {
49 rename sqlite sqlite_orig
51 if {[llength $args]==2 && [string index
[lindex $args 0] 0]!="-"} {
52 lappend args
-key {xyzzy
}
54 uplevel 1 sqlite_orig
$args
59 # Create a test database
62 file delete
-force test.db
63 file delete
-force test.db-journal
65 if {[info exists
::SETUP_SQL]} {
69 # Abort early if this script has been run before.
71 if {[info exists nTest
]} return
73 # Set the test counters to zero
81 # Invoke the do_test procedure to run a single test
83 proc do_test
{name cmd expected
} {
84 global argv nErr nTest skip_test
89 if {[llength $argv]==0} {
93 foreach pattern
$argv {
94 if {[string match
$pattern $name]} {
102 puts -nonewline $name...
104 if {[catch {uplevel #0 "$cmd;\n"} result]} {
105 puts "\nError: $result"
107 lappend ::failList $name
108 if {$nErr>100} {puts "*** Giving up..."; finalize_testing
}
109 } elseif
{[string compare
$result $expected]} {
110 puts "\nExpected: \[$expected\]\n Got: \[$result\]"
112 lappend ::failList $name
113 if {$nErr>100} {puts "*** Giving up..."; finalize_testing
}
119 # Invoke this procedure on a test that is probabilistic
120 # and might fail sometimes.
122 proc do_probtest
{name cmd expected
} {
123 global argv nProb nTest skip_test
128 if {[llength $argv]==0} {
132 foreach pattern
$argv {
133 if {[string match
$pattern $name]} {
141 puts -nonewline $name...
143 if {[catch {uplevel #0 "$cmd;\n"} result]} {
144 puts "\nError: $result"
146 } elseif
{[string compare
$result $expected]} {
147 puts "\nExpected: \[$expected\]\n Got: \[$result\]"
148 puts "NOTE: The results of the previous test depend on system load"
149 puts "and processor speed. The test may sometimes fail even if the"
150 puts "library is working correctly."
157 # The procedure uses the special "sqlite_malloc_stat" command
158 # (which is only available if SQLite is compiled with -DMEMORY_DEBUG=1)
159 # to see how many malloc()s have not been free()ed. The number
160 # of surplus malloc()s is stored in the global variable $::Leak.
161 # If the value in $::Leak grows, it may mean there is a memory leak
164 proc memleak_check
{} {
165 if {[info command sqlite_malloc_stat
]!=""} {
166 set r
[sqlite_malloc_stat
]
167 set ::Leak [expr {[lindex $r 0]-[lindex $r 1]}]
171 # Run this routine last
173 proc finish_test
{} {
176 proc finalize_testing
{} {
177 global nTest nErr nProb sqlite_open_file_count
178 if {$nErr==0} memleak_check
180 puts "$nErr errors out of $nTest tests"
181 puts "Failures on these tests: $::failList"
183 puts "$nProb probabilistic tests also failed, but this does"
184 puts "not necessarily indicate a malfunction."
186 if {$sqlite_open_file_count} {
187 puts "$sqlite_open_file_count files were left open"
190 exit [expr {$nErr>0}]
193 # A procedure to execute SQL
195 proc execsql
{sql
{db db
}} {
197 return [$db eval $sql]
200 # Execute SQL and catch exceptions.
202 proc catchsql
{sql
{db db
}} {
204 set r
[catch {$db eval $sql} msg
]
209 # Do an VDBE code dump on the SQL given
211 proc explain
{sql
{db db
}} {
213 puts "addr opcode p1 p2 p3 "
214 puts "---- ------------ ------ ------ ---------------"
215 $db eval "explain $sql" {} {
216 puts [format {%-4d %-12.12s
%-6d %-6d %s
} $addr $opcode $p1 $p2 $p3]
220 # Another procedure to execute SQL. This one includes the field
221 # names in the returned list.
223 proc execsql2
{sql
} {
227 lappend result
$f $data($f)
233 # Use the non-callback API to execute multiple SQL statements
235 proc stepsql
{dbptr sql
} {
236 set sql
[string trim
$sql]
238 while {[string length
$sql]>0} {
239 if {[catch {sqlite_compile
$dbptr $sql sqltail
} vm
]} {
242 set sql
[string trim
$sqltail]
243 while {[sqlite_step
$vm N VAL COL
]=="SQLITE_ROW"} {
244 foreach v
$VAL {lappend r
$v}
246 if {[catch {sqlite_finalize
$vm} errmsg
]} {
247 return [list 1 $errmsg]
253 # Delete a file or directory
255 proc forcedelete
{filename} {
256 if {[catch {file delete
-force $filename}]} {
257 exec rm
-rf $filename
261 # Do an integrity check of the entire database
263 proc integrity_check
{name
} {
265 execsql
{PRAGMA integrity_check
}