xref: /onnv-gate/usr/src/lib/libsqlite/test/tester.tcl (revision 4520:7dbeadedd7fe)
1*4520Snw141292
2*4520Snw141292#pragma ident	"%Z%%M%	%I%	%E% SMI"
3*4520Snw141292
4*4520Snw141292# 2001 September 15
5*4520Snw141292#
6*4520Snw141292# The author disclaims copyright to this source code.  In place of
7*4520Snw141292# a legal notice, here is a blessing:
8*4520Snw141292#
9*4520Snw141292#    May you do good and not evil.
10*4520Snw141292#    May you find forgiveness for yourself and forgive others.
11*4520Snw141292#    May you share freely, never taking more than you give.
12*4520Snw141292#
13*4520Snw141292#***********************************************************************
14*4520Snw141292# This file implements some common TCL routines used for regression
15*4520Snw141292# testing the SQLite library
16*4520Snw141292#
17*4520Snw141292# $Id: tester.tcl,v 1.28 2004/02/14 01:39:50 drh Exp $
18*4520Snw141292
19*4520Snw141292# Make sure tclsqlite was compiled correctly.  Abort now with an
20*4520Snw141292# error message if not.
21*4520Snw141292#
22*4520Snw141292if {[sqlite -tcl-uses-utf]} {
23*4520Snw141292  if {"\u1234"=="u1234"} {
24*4520Snw141292    puts stderr "***** BUILD PROBLEM *****"
25*4520Snw141292    puts stderr "$argv0 was linked against an older version"
26*4520Snw141292    puts stderr "of TCL that does not support Unicode, but uses a header"
27*4520Snw141292    puts stderr "file (\"tcl.h\") from a new TCL version that does support"
28*4520Snw141292    puts stderr "Unicode.  This combination causes internal errors."
29*4520Snw141292    puts stderr "Recompile using a TCL library and header file that match"
30*4520Snw141292    puts stderr "and try again.\n**************************"
31*4520Snw141292    exit 1
32*4520Snw141292  }
33*4520Snw141292} else {
34*4520Snw141292  if {"\u1234"!="u1234"} {
35*4520Snw141292    puts stderr "***** BUILD PROBLEM *****"
36*4520Snw141292    puts stderr "$argv0 was linked against an newer version"
37*4520Snw141292    puts stderr "of TCL that supports Unicode, but uses a header file"
38*4520Snw141292    puts stderr "(\"tcl.h\") from a old TCL version that does not support"
39*4520Snw141292    puts stderr "Unicode.  This combination causes internal errors."
40*4520Snw141292    puts stderr "Recompile using a TCL library and header file that match"
41*4520Snw141292    puts stderr "and try again.\n**************************"
42*4520Snw141292    exit 1
43*4520Snw141292  }
44*4520Snw141292}
45*4520Snw141292
46*4520Snw141292# Use the pager codec if it is available
47*4520Snw141292#
48*4520Snw141292if {[sqlite -has-codec] && [info command sqlite_orig]==""} {
49*4520Snw141292  rename sqlite sqlite_orig
50*4520Snw141292  proc sqlite {args} {
51*4520Snw141292    if {[llength $args]==2 && [string index [lindex $args 0] 0]!="-"} {
52*4520Snw141292      lappend args -key {xyzzy}
53*4520Snw141292    }
54*4520Snw141292    uplevel 1 sqlite_orig $args
55*4520Snw141292  }
56*4520Snw141292}
57*4520Snw141292
58*4520Snw141292
59*4520Snw141292# Create a test database
60*4520Snw141292#
61*4520Snw141292catch {db close}
62*4520Snw141292file delete -force test.db
63*4520Snw141292file delete -force test.db-journal
64*4520Snw141292sqlite db ./test.db
65*4520Snw141292if {[info exists ::SETUP_SQL]} {
66*4520Snw141292  db eval $::SETUP_SQL
67*4520Snw141292}
68*4520Snw141292
69*4520Snw141292# Abort early if this script has been run before.
70*4520Snw141292#
71*4520Snw141292if {[info exists nTest]} return
72*4520Snw141292
73*4520Snw141292# Set the test counters to zero
74*4520Snw141292#
75*4520Snw141292set nErr 0
76*4520Snw141292set nTest 0
77*4520Snw141292set nProb 0
78*4520Snw141292set skip_test 0
79*4520Snw141292set failList {}
80*4520Snw141292
81*4520Snw141292# Invoke the do_test procedure to run a single test
82*4520Snw141292#
83*4520Snw141292proc do_test {name cmd expected} {
84*4520Snw141292  global argv nErr nTest skip_test
85*4520Snw141292  if {$skip_test} {
86*4520Snw141292    set skip_test 0
87*4520Snw141292    return
88*4520Snw141292  }
89*4520Snw141292  if {[llength $argv]==0} {
90*4520Snw141292    set go 1
91*4520Snw141292  } else {
92*4520Snw141292    set go 0
93*4520Snw141292    foreach pattern $argv {
94*4520Snw141292      if {[string match $pattern $name]} {
95*4520Snw141292        set go 1
96*4520Snw141292        break
97*4520Snw141292      }
98*4520Snw141292    }
99*4520Snw141292  }
100*4520Snw141292  if {!$go} return
101*4520Snw141292  incr nTest
102*4520Snw141292  puts -nonewline $name...
103*4520Snw141292  flush stdout
104*4520Snw141292  if {[catch {uplevel #0 "$cmd;\n"} result]} {
105*4520Snw141292    puts "\nError: $result"
106*4520Snw141292    incr nErr
107*4520Snw141292    lappend ::failList $name
108*4520Snw141292    if {$nErr>100} {puts "*** Giving up..."; finalize_testing}
109*4520Snw141292  } elseif {[string compare $result $expected]} {
110*4520Snw141292    puts "\nExpected: \[$expected\]\n     Got: \[$result\]"
111*4520Snw141292    incr nErr
112*4520Snw141292    lappend ::failList $name
113*4520Snw141292    if {$nErr>100} {puts "*** Giving up..."; finalize_testing}
114*4520Snw141292  } else {
115*4520Snw141292    puts " Ok"
116*4520Snw141292  }
117*4520Snw141292}
118*4520Snw141292
119*4520Snw141292# Invoke this procedure on a test that is probabilistic
120*4520Snw141292# and might fail sometimes.
121*4520Snw141292#
122*4520Snw141292proc do_probtest {name cmd expected} {
123*4520Snw141292  global argv nProb nTest skip_test
124*4520Snw141292  if {$skip_test} {
125*4520Snw141292    set skip_test 0
126*4520Snw141292    return
127*4520Snw141292  }
128*4520Snw141292  if {[llength $argv]==0} {
129*4520Snw141292    set go 1
130*4520Snw141292  } else {
131*4520Snw141292    set go 0
132*4520Snw141292    foreach pattern $argv {
133*4520Snw141292      if {[string match $pattern $name]} {
134*4520Snw141292        set go 1
135*4520Snw141292        break
136*4520Snw141292      }
137*4520Snw141292    }
138*4520Snw141292  }
139*4520Snw141292  if {!$go} return
140*4520Snw141292  incr nTest
141*4520Snw141292  puts -nonewline $name...
142*4520Snw141292  flush stdout
143*4520Snw141292  if {[catch {uplevel #0 "$cmd;\n"} result]} {
144*4520Snw141292    puts "\nError: $result"
145*4520Snw141292    incr nErr
146*4520Snw141292  } elseif {[string compare $result $expected]} {
147*4520Snw141292    puts "\nExpected: \[$expected\]\n     Got: \[$result\]"
148*4520Snw141292    puts "NOTE: The results of the previous test depend on system load"
149*4520Snw141292    puts "and processor speed.  The test may sometimes fail even if the"
150*4520Snw141292    puts "library is working correctly."
151*4520Snw141292    incr nProb
152*4520Snw141292  } else {
153*4520Snw141292    puts " Ok"
154*4520Snw141292  }
155*4520Snw141292}
156*4520Snw141292
157*4520Snw141292# The procedure uses the special "sqlite_malloc_stat" command
158*4520Snw141292# (which is only available if SQLite is compiled with -DMEMORY_DEBUG=1)
159*4520Snw141292# to see how many malloc()s have not been free()ed.  The number
160*4520Snw141292# of surplus malloc()s is stored in the global variable $::Leak.
161*4520Snw141292# If the value in $::Leak grows, it may mean there is a memory leak
162*4520Snw141292# in the library.
163*4520Snw141292#
164*4520Snw141292proc memleak_check {} {
165*4520Snw141292  if {[info command sqlite_malloc_stat]!=""} {
166*4520Snw141292    set r [sqlite_malloc_stat]
167*4520Snw141292    set ::Leak [expr {[lindex $r 0]-[lindex $r 1]}]
168*4520Snw141292  }
169*4520Snw141292}
170*4520Snw141292
171*4520Snw141292# Run this routine last
172*4520Snw141292#
173*4520Snw141292proc finish_test {} {
174*4520Snw141292  finalize_testing
175*4520Snw141292}
176*4520Snw141292proc finalize_testing {} {
177*4520Snw141292  global nTest nErr nProb sqlite_open_file_count
178*4520Snw141292  if {$nErr==0} memleak_check
179*4520Snw141292  catch {db close}
180*4520Snw141292  puts "$nErr errors out of $nTest tests"
181*4520Snw141292  puts "Failures on these tests: $::failList"
182*4520Snw141292  if {$nProb>0} {
183*4520Snw141292    puts "$nProb probabilistic tests also failed, but this does"
184*4520Snw141292    puts "not necessarily indicate a malfunction."
185*4520Snw141292  }
186*4520Snw141292  if {$sqlite_open_file_count} {
187*4520Snw141292    puts "$sqlite_open_file_count files were left open"
188*4520Snw141292    incr nErr
189*4520Snw141292  }
190*4520Snw141292  exit [expr {$nErr>0}]
191*4520Snw141292}
192*4520Snw141292
193*4520Snw141292# A procedure to execute SQL
194*4520Snw141292#
195*4520Snw141292proc execsql {sql {db db}} {
196*4520Snw141292  # puts "SQL = $sql"
197*4520Snw141292  return [$db eval $sql]
198*4520Snw141292}
199*4520Snw141292
200*4520Snw141292# Execute SQL and catch exceptions.
201*4520Snw141292#
202*4520Snw141292proc catchsql {sql {db db}} {
203*4520Snw141292  # puts "SQL = $sql"
204*4520Snw141292  set r [catch {$db eval $sql} msg]
205*4520Snw141292  lappend r $msg
206*4520Snw141292  return $r
207*4520Snw141292}
208*4520Snw141292
209*4520Snw141292# Do an VDBE code dump on the SQL given
210*4520Snw141292#
211*4520Snw141292proc explain {sql {db db}} {
212*4520Snw141292  puts ""
213*4520Snw141292  puts "addr  opcode        p1       p2     p3             "
214*4520Snw141292  puts "----  ------------  ------  ------  ---------------"
215*4520Snw141292  $db eval "explain $sql" {} {
216*4520Snw141292    puts [format {%-4d  %-12.12s  %-6d  %-6d  %s} $addr $opcode $p1 $p2 $p3]
217*4520Snw141292  }
218*4520Snw141292}
219*4520Snw141292
220*4520Snw141292# Another procedure to execute SQL.  This one includes the field
221*4520Snw141292# names in the returned list.
222*4520Snw141292#
223*4520Snw141292proc execsql2 {sql} {
224*4520Snw141292  set result {}
225*4520Snw141292  db eval $sql data {
226*4520Snw141292    foreach f $data(*) {
227*4520Snw141292      lappend result $f $data($f)
228*4520Snw141292    }
229*4520Snw141292  }
230*4520Snw141292  return $result
231*4520Snw141292}
232*4520Snw141292
233*4520Snw141292# Use the non-callback API to execute multiple SQL statements
234*4520Snw141292#
235*4520Snw141292proc stepsql {dbptr sql} {
236*4520Snw141292  set sql [string trim $sql]
237*4520Snw141292  set r 0
238*4520Snw141292  while {[string length $sql]>0} {
239*4520Snw141292    if {[catch {sqlite_compile $dbptr $sql sqltail} vm]} {
240*4520Snw141292      return [list 1 $vm]
241*4520Snw141292    }
242*4520Snw141292    set sql [string trim $sqltail]
243*4520Snw141292    while {[sqlite_step $vm N VAL COL]=="SQLITE_ROW"} {
244*4520Snw141292      foreach v $VAL {lappend r $v}
245*4520Snw141292    }
246*4520Snw141292    if {[catch {sqlite_finalize $vm} errmsg]} {
247*4520Snw141292      return [list 1 $errmsg]
248*4520Snw141292    }
249*4520Snw141292  }
250*4520Snw141292  return $r
251*4520Snw141292}
252*4520Snw141292
253*4520Snw141292# Delete a file or directory
254*4520Snw141292#
255*4520Snw141292proc forcedelete {filename} {
256*4520Snw141292  if {[catch {file delete -force $filename}]} {
257*4520Snw141292    exec rm -rf $filename
258*4520Snw141292  }
259*4520Snw141292}
260*4520Snw141292
261*4520Snw141292# Do an integrity check of the entire database
262*4520Snw141292#
263*4520Snw141292proc integrity_check {name} {
264*4520Snw141292  do_test $name {
265*4520Snw141292    execsql {PRAGMA integrity_check}
266*4520Snw141292  } {ok}
267*4520Snw141292}
268