blob: 788dda5bd7deffc7c08c99d836810d75fffdc441 [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#
drhdde85d92003-03-01 19:45:34 +000014# $Id: tester.tcl,v 1.25 2003/03/01 19:45:35 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
drhbec2bf42000-05-29 23:48:22 +000043# Create a test database
44#
drh254cba22001-09-20 01:44:42 +000045catch {db close}
46file delete -force test.db
47file delete -force test.db-journal
drh5edc3122001-09-13 21:53:09 +000048sqlite db ./test.db
drhcd61c282002-03-06 22:01:34 +000049if {[info exists ::SETUP_SQL]} {
50 db eval $::SETUP_SQL
51}
drhbec2bf42000-05-29 23:48:22 +000052
53# Abort early if this script has been run before.
54#
55if {[info exists nTest]} return
56
57# Set the test counters to zero
58#
drh348784e2000-05-29 20:41:49 +000059set nErr 0
60set nTest 0
drhdb25e382001-03-15 18:21:22 +000061set nProb 0
drh767c2002000-10-19 14:10:08 +000062set skip_test 0
drha1b351a2001-09-14 16:42:12 +000063set failList {}
drh348784e2000-05-29 20:41:49 +000064
65# Invoke the do_test procedure to run a single test
66#
67proc do_test {name cmd expected} {
drh767c2002000-10-19 14:10:08 +000068 global argv nErr nTest skip_test
69 if {$skip_test} {
70 set skip_test 0
71 return
72 }
73 if {[llength $argv]==0} {
drh348784e2000-05-29 20:41:49 +000074 set go 1
75 } else {
76 set go 0
77 foreach pattern $argv {
78 if {[string match $pattern $name]} {
79 set go 1
80 break
81 }
82 }
83 }
84 if {!$go} return
85 incr nTest
drh5edc3122001-09-13 21:53:09 +000086 puts -nonewline $name...
drh348784e2000-05-29 20:41:49 +000087 flush stdout
88 if {[catch {uplevel #0 "$cmd;\n"} result]} {
89 puts "\nError: $result"
90 incr nErr
drha1b351a2001-09-14 16:42:12 +000091 lappend ::failList $name
92 if {$nErr>10} {puts "*** Giving up..."; finalize_testing}
drh348784e2000-05-29 20:41:49 +000093 } elseif {[string compare $result $expected]} {
94 puts "\nExpected: \[$expected\]\n Got: \[$result\]"
95 incr nErr
drha1b351a2001-09-14 16:42:12 +000096 lappend ::failList $name
97 if {$nErr>10} {puts "*** Giving up..."; finalize_testing}
drh348784e2000-05-29 20:41:49 +000098 } else {
99 puts " Ok"
100 }
101}
102
drhdb25e382001-03-15 18:21:22 +0000103# Invoke this procedure on a test that is probabilistic
104# and might fail sometimes.
105#
106proc do_probtest {name cmd expected} {
107 global argv nProb nTest skip_test
108 if {$skip_test} {
109 set skip_test 0
110 return
111 }
112 if {[llength $argv]==0} {
113 set go 1
114 } else {
115 set go 0
116 foreach pattern $argv {
117 if {[string match $pattern $name]} {
118 set go 1
119 break
120 }
121 }
122 }
123 if {!$go} return
124 incr nTest
drh5edc3122001-09-13 21:53:09 +0000125 puts -nonewline $name...
drhdb25e382001-03-15 18:21:22 +0000126 flush stdout
127 if {[catch {uplevel #0 "$cmd;\n"} result]} {
128 puts "\nError: $result"
129 incr nErr
130 } elseif {[string compare $result $expected]} {
131 puts "\nExpected: \[$expected\]\n Got: \[$result\]"
132 puts "NOTE: The results of the previous test depend on system load"
133 puts "and processor speed. The test may sometimes fail even if the"
134 puts "library is working correctly."
135 incr nProb
136 } else {
137 puts " Ok"
138 }
139}
140
drhdaffd0e2001-04-11 14:28:42 +0000141# The procedure uses the special "sqlite_malloc_stat" command
drh8c82b352000-12-10 18:23:50 +0000142# (which is only available if SQLite is compiled with -DMEMORY_DEBUG=1)
143# to see how many malloc()s have not been free()ed. The number
144# of surplus malloc()s is stored in the global variable $::Leak.
145# If the value in $::Leak grows, it may mean there is a memory leak
146# in the library.
147#
148proc memleak_check {} {
drhdaffd0e2001-04-11 14:28:42 +0000149 if {[info command sqlite_malloc_stat]!=""} {
150 set r [sqlite_malloc_stat]
151 set ::Leak [expr {[lindex $r 0]-[lindex $r 1]}]
152 }
drh8c82b352000-12-10 18:23:50 +0000153}
154
drh348784e2000-05-29 20:41:49 +0000155# Run this routine last
156#
157proc finish_test {} {
drha1b351a2001-09-14 16:42:12 +0000158 finalize_testing
159}
160proc finalize_testing {} {
drh94e92032003-02-16 22:21:32 +0000161 global nTest nErr nProb sqlite_open_file_count
drha1b351a2001-09-14 16:42:12 +0000162 if {$nErr==0} memleak_check
drh6e142f52000-06-08 13:36:40 +0000163 catch {db close}
drh348784e2000-05-29 20:41:49 +0000164 puts "$nErr errors out of $nTest tests"
drha1b351a2001-09-14 16:42:12 +0000165 puts "Failures on these tests: $::failList"
drhdb25e382001-03-15 18:21:22 +0000166 if {$nProb>0} {
167 puts "$nProb probabilistic tests also failed, but this does"
168 puts "not necessarily indicate a malfunction."
169 }
drh94e92032003-02-16 22:21:32 +0000170 if {$sqlite_open_file_count} {
171 puts "$sqlite_open_file_count files were left open"
172 incr nErr
173 }
drhdb25e382001-03-15 18:21:22 +0000174 exit [expr {$nErr>0}]
drh348784e2000-05-29 20:41:49 +0000175}
176
drh348784e2000-05-29 20:41:49 +0000177# A procedure to execute SQL
178#
drhc4a3c772001-04-04 11:48:57 +0000179proc execsql {sql {db db}} {
drhacbcdc42001-01-22 00:31:53 +0000180 # puts "SQL = $sql"
drhc4a3c772001-04-04 11:48:57 +0000181 return [$db eval $sql]
drh348784e2000-05-29 20:41:49 +0000182}
drh3aadb2e2000-05-31 17:59:25 +0000183
drhadbca9c2001-09-27 15:11:53 +0000184# Execute SQL and catch exceptions.
185#
186proc catchsql {sql {db db}} {
187 # puts "SQL = $sql"
188 set r [catch {$db eval $sql} msg]
189 lappend r $msg
190 return $r
191}
192
drh04096482001-11-09 22:41:44 +0000193# Do an VDBE code dump on the SQL given
194#
195proc explain {sql {db db}} {
196 puts ""
197 puts "addr opcode p1 p2 p3 "
198 puts "---- ------------ ------ ------ ---------------"
199 $db eval "explain $sql" {} {
200 puts [format {%-4d %-12.12s %-6d %-6d %s} $addr $opcode $p1 $p2 $p3]
201 }
202}
203
drh3aadb2e2000-05-31 17:59:25 +0000204# Another procedure to execute SQL. This one includes the field
205# names in the returned list.
206#
207proc execsql2 {sql} {
208 set result {}
209 db eval $sql data {
210 foreach f $data(*) {
211 lappend result $f $data($f)
212 }
213 }
214 return $result
215}
drh17a68932001-01-31 13:28:08 +0000216
drhdde85d92003-03-01 19:45:34 +0000217# Use the non-callback API to execute multiple SQL statements
218#
219proc stepsql {dbptr sql} {
220 set sql [string trim $sql]
221 set r 0
222 while {[string length $sql]>0} {
223 if {[catch {sqlite_compile $dbptr $sql sqltail} vm]} {
224 return [list 1 $vm]
225 }
226 set sql [string trim $sqltail]
227 while {[sqlite_step $vm N VAL COL]=="SQLITE_ROW"} {
228 foreach v $VAL {lappend r $v}
229 }
230 if {[catch {sqlite_finalize $vm} errmsg]} {
231 return [list 1 $errmsg]
232 }
233 }
234 return $r
235}
236
drh17a68932001-01-31 13:28:08 +0000237# Delete a file or directory
238#
239proc forcedelete {filename} {
240 if {[catch {file delete -force $filename}]} {
241 exec rm -rf $filename
242 }
243}
drh21504322002-06-25 13:16:02 +0000244
245# Do an integrity check of the entire database
246#
247proc integrity_check {name} {
248 do_test $name {
249 execsql {PRAGMA integrity_check}
250 } {ok ok}
251}