blob: eb754595170fd5c874222b20f0b3f7fcf8fd6cca [file] [log] [blame]
drhb19a2bc2001-09-16 00:13:26 +00001# 2001 September 15
drh348784e2000-05-29 20:41:49 +00002#
drhb19a2bc2001-09-16 00:13:26 +00003# The author disclaims copyright to this source code. In place of
4# a legal notice, here is a blessing:
drh348784e2000-05-29 20:41:49 +00005#
drhb19a2bc2001-09-16 00:13:26 +00006# May you do good and not evil.
7# May you find forgiveness for yourself and forgive others.
8# May you share freely, never taking more than you give.
drh348784e2000-05-29 20:41:49 +00009#
10#***********************************************************************
11# This file implements some common TCL routines used for regression
12# testing the SQLite library
13#
drh9eb9e262004-02-11 02:18:05 +000014# $Id: tester.tcl,v 1.27 2004/02/11 02:18:07 drh Exp $
drhfbc3eab2001-04-06 16:13:42 +000015
16# Make sure tclsqlite was compiled correctly. Abort now with an
17# error message if not.
18#
19if {[sqlite -tcl-uses-utf]} {
20 if {"\u1234"=="u1234"} {
21 puts stderr "***** BUILD PROBLEM *****"
22 puts stderr "$argv0 was linked against an older version"
23 puts stderr "of TCL that does not support Unicode, but uses a header"
24 puts stderr "file (\"tcl.h\") from a new TCL version that does support"
25 puts stderr "Unicode. This combination causes internal errors."
26 puts stderr "Recompile using a TCL library and header file that match"
27 puts stderr "and try again.\n**************************"
28 exit 1
29 }
30} else {
31 if {"\u1234"!="u1234"} {
32 puts stderr "***** BUILD PROBLEM *****"
33 puts stderr "$argv0 was linked against an newer version"
34 puts stderr "of TCL that supports Unicode, but uses a header file"
35 puts stderr "(\"tcl.h\") from a old TCL version that does not support"
36 puts stderr "Unicode. This combination causes internal errors."
37 puts stderr "Recompile using a TCL library and header file that match"
38 puts stderr "and try again.\n**************************"
39 exit 1
40 }
41}
drh348784e2000-05-29 20:41:49 +000042
drh9eb9e262004-02-11 02:18:05 +000043# Use the pager codec if it is available
44#
45if {[sqlite -has-codec] && [info command sqlite_orig]==""} {
46 rename sqlite sqlite_orig
47 proc sqlite {args} {
48 if {[llength $args]==2 && [string index [lindex $args 0] 0]!="-"} {
49 lappend args -key {xyzzy}
50 }
51 uplevel 1 sqlite_orig $args
52 }
53}
54
55
drhbec2bf42000-05-29 23:48:22 +000056# Create a test database
57#
drh254cba22001-09-20 01:44:42 +000058catch {db close}
59file delete -force test.db
60file delete -force test.db-journal
drh5edc3122001-09-13 21:53:09 +000061sqlite db ./test.db
drhcd61c282002-03-06 22:01:34 +000062if {[info exists ::SETUP_SQL]} {
63 db eval $::SETUP_SQL
64}
drhbec2bf42000-05-29 23:48:22 +000065
66# Abort early if this script has been run before.
67#
68if {[info exists nTest]} return
69
70# Set the test counters to zero
71#
drh348784e2000-05-29 20:41:49 +000072set nErr 0
73set nTest 0
drhdb25e382001-03-15 18:21:22 +000074set nProb 0
drh767c2002000-10-19 14:10:08 +000075set skip_test 0
drha1b351a2001-09-14 16:42:12 +000076set failList {}
drh348784e2000-05-29 20:41:49 +000077
78# Invoke the do_test procedure to run a single test
79#
80proc do_test {name cmd expected} {
drh767c2002000-10-19 14:10:08 +000081 global argv nErr nTest skip_test
82 if {$skip_test} {
83 set skip_test 0
84 return
85 }
86 if {[llength $argv]==0} {
drh348784e2000-05-29 20:41:49 +000087 set go 1
88 } else {
89 set go 0
90 foreach pattern $argv {
91 if {[string match $pattern $name]} {
92 set go 1
93 break
94 }
95 }
96 }
97 if {!$go} return
98 incr nTest
drh5edc3122001-09-13 21:53:09 +000099 puts -nonewline $name...
drh348784e2000-05-29 20:41:49 +0000100 flush stdout
101 if {[catch {uplevel #0 "$cmd;\n"} result]} {
102 puts "\nError: $result"
103 incr nErr
drha1b351a2001-09-14 16:42:12 +0000104 lappend ::failList $name
105 if {$nErr>10} {puts "*** Giving up..."; finalize_testing}
drh348784e2000-05-29 20:41:49 +0000106 } elseif {[string compare $result $expected]} {
107 puts "\nExpected: \[$expected\]\n Got: \[$result\]"
108 incr nErr
drha1b351a2001-09-14 16:42:12 +0000109 lappend ::failList $name
110 if {$nErr>10} {puts "*** Giving up..."; finalize_testing}
drh348784e2000-05-29 20:41:49 +0000111 } else {
112 puts " Ok"
113 }
114}
115
drhdb25e382001-03-15 18:21:22 +0000116# Invoke this procedure on a test that is probabilistic
117# and might fail sometimes.
118#
119proc do_probtest {name cmd expected} {
120 global argv nProb nTest skip_test
121 if {$skip_test} {
122 set skip_test 0
123 return
124 }
125 if {[llength $argv]==0} {
126 set go 1
127 } else {
128 set go 0
129 foreach pattern $argv {
130 if {[string match $pattern $name]} {
131 set go 1
132 break
133 }
134 }
135 }
136 if {!$go} return
137 incr nTest
drh5edc3122001-09-13 21:53:09 +0000138 puts -nonewline $name...
drhdb25e382001-03-15 18:21:22 +0000139 flush stdout
140 if {[catch {uplevel #0 "$cmd;\n"} result]} {
141 puts "\nError: $result"
142 incr nErr
143 } elseif {[string compare $result $expected]} {
144 puts "\nExpected: \[$expected\]\n Got: \[$result\]"
145 puts "NOTE: The results of the previous test depend on system load"
146 puts "and processor speed. The test may sometimes fail even if the"
147 puts "library is working correctly."
148 incr nProb
149 } else {
150 puts " Ok"
151 }
152}
153
drhdaffd0e2001-04-11 14:28:42 +0000154# The procedure uses the special "sqlite_malloc_stat" command
drh8c82b352000-12-10 18:23:50 +0000155# (which is only available if SQLite is compiled with -DMEMORY_DEBUG=1)
156# to see how many malloc()s have not been free()ed. The number
157# of surplus malloc()s is stored in the global variable $::Leak.
158# If the value in $::Leak grows, it may mean there is a memory leak
159# in the library.
160#
161proc memleak_check {} {
drhdaffd0e2001-04-11 14:28:42 +0000162 if {[info command sqlite_malloc_stat]!=""} {
163 set r [sqlite_malloc_stat]
164 set ::Leak [expr {[lindex $r 0]-[lindex $r 1]}]
165 }
drh8c82b352000-12-10 18:23:50 +0000166}
167
drh348784e2000-05-29 20:41:49 +0000168# Run this routine last
169#
170proc finish_test {} {
drha1b351a2001-09-14 16:42:12 +0000171 finalize_testing
172}
173proc finalize_testing {} {
drh94e92032003-02-16 22:21:32 +0000174 global nTest nErr nProb sqlite_open_file_count
drha1b351a2001-09-14 16:42:12 +0000175 if {$nErr==0} memleak_check
drh6e142f52000-06-08 13:36:40 +0000176 catch {db close}
drh348784e2000-05-29 20:41:49 +0000177 puts "$nErr errors out of $nTest tests"
drha1b351a2001-09-14 16:42:12 +0000178 puts "Failures on these tests: $::failList"
drhdb25e382001-03-15 18:21:22 +0000179 if {$nProb>0} {
180 puts "$nProb probabilistic tests also failed, but this does"
181 puts "not necessarily indicate a malfunction."
182 }
drh94e92032003-02-16 22:21:32 +0000183 if {$sqlite_open_file_count} {
184 puts "$sqlite_open_file_count files were left open"
185 incr nErr
186 }
drhdb25e382001-03-15 18:21:22 +0000187 exit [expr {$nErr>0}]
drh348784e2000-05-29 20:41:49 +0000188}
189
drh348784e2000-05-29 20:41:49 +0000190# A procedure to execute SQL
191#
drhc4a3c772001-04-04 11:48:57 +0000192proc execsql {sql {db db}} {
drhacbcdc42001-01-22 00:31:53 +0000193 # puts "SQL = $sql"
drhc4a3c772001-04-04 11:48:57 +0000194 return [$db eval $sql]
drh348784e2000-05-29 20:41:49 +0000195}
drh3aadb2e2000-05-31 17:59:25 +0000196
drhadbca9c2001-09-27 15:11:53 +0000197# Execute SQL and catch exceptions.
198#
199proc catchsql {sql {db db}} {
200 # puts "SQL = $sql"
201 set r [catch {$db eval $sql} msg]
202 lappend r $msg
203 return $r
204}
205
drh04096482001-11-09 22:41:44 +0000206# Do an VDBE code dump on the SQL given
207#
208proc explain {sql {db db}} {
209 puts ""
210 puts "addr opcode p1 p2 p3 "
211 puts "---- ------------ ------ ------ ---------------"
212 $db eval "explain $sql" {} {
213 puts [format {%-4d %-12.12s %-6d %-6d %s} $addr $opcode $p1 $p2 $p3]
214 }
215}
216
drh3aadb2e2000-05-31 17:59:25 +0000217# Another procedure to execute SQL. This one includes the field
218# names in the returned list.
219#
220proc execsql2 {sql} {
221 set result {}
222 db eval $sql data {
223 foreach f $data(*) {
224 lappend result $f $data($f)
225 }
226 }
227 return $result
228}
drh17a68932001-01-31 13:28:08 +0000229
drhdde85d92003-03-01 19:45:34 +0000230# Use the non-callback API to execute multiple SQL statements
231#
232proc stepsql {dbptr sql} {
233 set sql [string trim $sql]
234 set r 0
235 while {[string length $sql]>0} {
236 if {[catch {sqlite_compile $dbptr $sql sqltail} vm]} {
237 return [list 1 $vm]
238 }
239 set sql [string trim $sqltail]
240 while {[sqlite_step $vm N VAL COL]=="SQLITE_ROW"} {
241 foreach v $VAL {lappend r $v}
242 }
243 if {[catch {sqlite_finalize $vm} errmsg]} {
244 return [list 1 $errmsg]
245 }
246 }
247 return $r
248}
249
drh17a68932001-01-31 13:28:08 +0000250# Delete a file or directory
251#
252proc forcedelete {filename} {
253 if {[catch {file delete -force $filename}]} {
254 exec rm -rf $filename
255 }
256}
drh21504322002-06-25 13:16:02 +0000257
258# Do an integrity check of the entire database
259#
260proc integrity_check {name} {
261 do_test $name {
262 execsql {PRAGMA integrity_check}
drhed717fe2003-06-15 23:42:24 +0000263 } {ok}
drh21504322002-06-25 13:16:02 +0000264}