Index: third_party/sqlite/src/test/tester.tcl |
diff --git a/third_party/sqlite/src/test/tester.tcl b/third_party/sqlite/src/test/tester.tcl |
index 4008a34491090cb90dd6a4b136ba7f0f23821c5c..1da89fec2692423e2651c7f8f5bb48ac12350fb9 100644 |
--- a/third_party/sqlite/src/test/tester.tcl |
+++ b/third_party/sqlite/src/test/tester.tcl |
@@ -25,6 +25,7 @@ |
# copy_file FROM TO |
# delete_file FILENAME |
# drop_all_tables ?DB? |
+# drop_all_indexes ?DB? |
# forcecopy FROM TO |
# forcedelete FILENAME |
# |
@@ -373,6 +374,28 @@ proc do_not_use_codec {} { |
set ::do_not_use_codec 1 |
reset_db |
} |
+unset -nocomplain do_not_use_codec |
+ |
+# Return true if the "reserved_bytes" integer on database files is non-zero. |
+# |
+proc nonzero_reserved_bytes {} { |
+ return [sqlite3 -has-codec] |
+} |
+ |
+# Print a HELP message and exit |
+# |
+proc print_help_and_quit {} { |
+ puts {Options: |
+ --pause Wait for user input before continuing |
+ --soft-heap-limit=N Set the soft-heap-limit to N |
+ --maxerror=N Quit after N errors |
+ --verbose=(0|1) Control the amount of output. Default '1' |
+ --output=FILE set --verbose=2 and output to FILE. Implies -q |
+ -q Shorthand for --verbose=0 |
+ --help This message |
+} |
+ exit 1 |
+} |
# The following block only runs the first time this file is sourced. It |
# does not run in slave interpreters (since the ::cmdlinearg array is |
@@ -396,6 +419,8 @@ if {[info exists cmdlinearg]==0} { |
# --match=$pattern |
# --verbose=$val |
# --output=$filename |
+ # -q Reduce output |
+ # --testdir=$dir Run tests in subdirectory $dir |
# --help |
# |
set cmdlinearg(soft-heap-limit) 0 |
@@ -410,6 +435,7 @@ if {[info exists cmdlinearg]==0} { |
set cmdlinearg(match) "" |
set cmdlinearg(verbose) "" |
set cmdlinearg(output) "" |
+ set cmdlinearg(testdir) "testdir" |
set leftover [list] |
foreach a $argv { |
@@ -435,10 +461,11 @@ if {[info exists cmdlinearg]==0} { |
} |
{^-+backtrace=.+$} { |
foreach {dummy cmdlinearg(backtrace)} [split $a =] break |
- sqlite3_memdebug_backtrace $value |
+ sqlite3_memdebug_backtrace $cmdlinearg(backtrace) |
} |
{^-+binarylog=.+$} { |
foreach {dummy cmdlinearg(binarylog)} [split $a =] break |
+ set cmdlinearg(binarylog) [file normalize $cmdlinearg(binarylog)] |
} |
{^-+soak=.+$} { |
foreach {dummy cmdlinearg(soak)} [split $a =] break |
@@ -471,6 +498,7 @@ if {[info exists cmdlinearg]==0} { |
{^-+output=.+$} { |
foreach {dummy cmdlinearg(output)} [split $a =] break |
+ set cmdlinearg(output) [file normalize $cmdlinearg(output)] |
if {$cmdlinearg(verbose)==""} { |
set cmdlinearg(verbose) 2 |
} |
@@ -483,12 +511,34 @@ if {[info exists cmdlinearg]==0} { |
error "option --verbose= must be set to a boolean or to \"file\"" |
} |
} |
+ {^-+testdir=.*$} { |
+ foreach {dummy cmdlinearg(testdir)} [split $a =] break |
+ } |
+ {.*help.*} { |
+ print_help_and_quit |
+ } |
+ {^-q$} { |
+ set cmdlinearg(output) test-out.txt |
+ set cmdlinearg(verbose) 2 |
+ } |
default { |
- lappend leftover $a |
+ if {[file tail $a]==$a} { |
+ lappend leftover $a |
+ } else { |
+ lappend leftover [file normalize $a] |
+ } |
} |
} |
} |
+ set testdir [file normalize $testdir] |
+ set cmdlinearg(TESTFIXTURE_HOME) [pwd] |
+ set cmdlinearg(INFO_SCRIPT) [file normalize [info script]] |
+ set argv0 [file normalize $argv0] |
+ if {$cmdlinearg(testdir)!=""} { |
+ file mkdir $cmdlinearg(testdir) |
+ cd $cmdlinearg(testdir) |
+ } |
set argv $leftover |
# Install the malloc layer used to inject OOM errors. And the 'automatic' |
@@ -672,6 +722,17 @@ proc puts {args} { uplevel puts_override $args } |
# Invoke the do_test procedure to run a single test |
# |
+# The $expected parameter is the expected result. The result is the return |
+# value from the last TCL command in $cmd. |
+# |
+# Normally, $expected must match exactly. But if $expected is of the form |
+# "/regexp/" then regular expression matching is used. If $expected is |
+# "~/regexp/" then the regular expression must NOT match. If $expected is |
+# of the form "#/value-list/" then each term in value-list must be numeric |
+# and must approximately match the corresponding numeric term in $result. |
+# Values must match within 10%. Or if the $expected term is A..B then the |
+# $result term must be in between A and B. |
+# |
proc do_test {name cmd expected} { |
global argv cmdlinearg |
@@ -705,7 +766,7 @@ proc do_test {name cmd expected} { |
output2 "\nError: $result" |
fail_test $name |
} else { |
- if {[regexp {^~?/.*/$} $expected]} { |
+ if {[regexp {^[~#]?/.*/$} $expected]} { |
# "expected" is of the form "/PATTERN/" then the result if correct if |
# regular expression PATTERN matches the result. "~/PATTERN/" means |
# the regular expression must not match. |
@@ -719,6 +780,21 @@ proc do_test {name cmd expected} { |
set ok [regexp $re $result] |
} |
set ok [expr {!$ok}] |
+ } elseif {[string index $expected 0]=="#"} { |
+ # Numeric range value comparison. Each term of the $result is matched |
+ # against one term of $expect. Both $result and $expected terms must be |
+ # numeric. The values must match within 10%. Or if $expected is of the |
+ # form A..B then the $result term must be between A and B. |
+ set e2 [string range $expected 2 end-1] |
+ foreach i $result j $e2 { |
+ if {[regexp {^(-?\d+)\.\.(-?\d)$} $j all A B]} { |
+ set ok [expr {$i+0>=$A && $i+0<=$B}] |
+ } else { |
+ set ok [expr {$i+0>=0.9*$j && $i+0<=1.1*$j}] |
+ } |
+ if {!$ok} break |
+ } |
+ if {$ok && [llength $result]!=[llength $e2]} {set ok 0} |
} else { |
set re [string range $expected 1 end-1] |
if {[string index $re 0]=="*"} { |
@@ -837,10 +913,43 @@ proc fix_testname {varname} { |
} |
} |
-proc do_execsql_test {testname sql {result {}}} { |
+proc normalize_list {L} { |
+ set L2 [list] |
+ foreach l $L {lappend L2 $l} |
+ set L2 |
+} |
+ |
+# Either: |
+# |
+# do_execsql_test TESTNAME SQL ?RES? |
+# do_execsql_test -db DB TESTNAME SQL ?RES? |
+# |
+proc do_execsql_test {args} { |
+ set db db |
+ if {[lindex $args 0]=="-db"} { |
+ set db [lindex $args 1] |
+ set args [lrange $args 2 end] |
+ } |
+ |
+ if {[llength $args]==2} { |
+ foreach {testname sql} $args {} |
+ set result "" |
+ } elseif {[llength $args]==3} { |
+ foreach {testname sql result} $args {} |
+ } else { |
+ error [string trim { |
+ wrong # args: should be "do_execsql_test ?-db DB? testname sql ?result?" |
+ }] |
+ } |
+ |
fix_testname testname |
- uplevel do_test [list $testname] [list "execsql {$sql}"] [list [list {*}$result]] |
+ |
+ uplevel do_test \ |
+ [list $testname] \ |
+ [list "execsql {$sql} $db"] \ |
+ [list [list {*}$result]] |
} |
+ |
proc do_catchsql_test {testname sql result} { |
fix_testname testname |
uplevel do_test [list $testname] [list "catchsql {$sql}"] [list $result] |
@@ -1028,7 +1137,13 @@ proc finalize_testing {} { |
output2 "[expr {$nErr-$nKnown}] new errors and $nKnown known errors\ |
out of $nTest tests" |
} else { |
- output2 "$nErr errors out of $nTest tests" |
+ set cpuinfo {} |
+ if {[catch {exec hostname} hname]==0} {set cpuinfo [string trim $hname]} |
+ append cpuinfo " $::tcl_platform(os)" |
+ append cpuinfo " [expr {$::tcl_platform(pointerSize)*8}]-bit" |
+ append cpuinfo " [string map {E -e} $::tcl_platform(byteOrder)]" |
+ output2 "SQLite [sqlite3 -sourceid]" |
+ output2 "$nErr errors out of $nTest tests on $cpuinfo" |
} |
if {$nErr>$nKnown} { |
output2 -nonewline "!Failures on these tests:" |
@@ -1202,9 +1317,9 @@ proc explain_i {sql {db db}} { |
set D "" |
} |
foreach opcode { |
- Seek SeekGe SeekGt SeekLe SeekLt NotFound Last Rewind |
+ Seek SeekGE SeekGT SeekLE SeekLT NotFound Last Rewind |
NoConflict Next Prev VNext VPrev VFilter |
- SorterSort SorterNext |
+ SorterSort SorterNext NextIfOpen |
} { |
set color($opcode) $B |
} |
@@ -1225,9 +1340,15 @@ proc explain_i {sql {db db}} { |
set bSeenGoto 1 |
} |
+ if {$opcode=="Once"} { |
+ for {set i $addr} {$i<$p2} {incr i} { |
+ set star($i) $addr |
+ } |
+ } |
+ |
if {$opcode=="Next" || $opcode=="Prev" |
|| $opcode=="VNext" || $opcode=="VPrev" |
- || $opcode=="SorterNext" |
+ || $opcode=="SorterNext" || $opcode=="NextIfOpen" |
} { |
for {set i $p2} {$i<$addr} {incr i} { |
incr x($i) 2 |
@@ -1251,6 +1372,12 @@ proc explain_i {sql {db db}} { |
} |
set I [string repeat " " $x($addr)] |
+ if {[info exists star($addr)]} { |
+ set ii [expr $x($star($addr))] |
+ append I " " |
+ set I [string replace $I $ii $ii *] |
+ } |
+ |
set col "" |
catch { set col $color($opcode) } |
@@ -1852,6 +1979,16 @@ proc drop_all_tables {{db db}} { |
} |
} |
+# Drop all auxiliary indexes from the main database opened by handle [db]. |
+# |
+proc drop_all_indexes {{db db}} { |
+ set L [$db eval { |
+ SELECT name FROM sqlite_master WHERE type='index' AND sql LIKE 'create%' |
+ }] |
+ foreach idx $L { $db eval "DROP INDEX $idx" } |
+} |
+ |
+ |
#------------------------------------------------------------------------- |
# If a test script is executed with global variable $::G(perm:name) set to |
# "wal", then the tests are run in WAL mode. Otherwise, they should be run |
@@ -1888,6 +2025,12 @@ proc wal_check_journal_mode {testname {db db}} { |
} |
} |
+proc wal_is_capable {} { |
+ ifcapable !wal { return 0 } |
+ if {[permutation]=="journaltest"} { return 0 } |
+ return 1 |
+} |
+ |
proc permutation {} { |
set perm "" |
catch {set perm $::G(perm:name)} |
@@ -1899,6 +2042,12 @@ proc presql {} { |
set presql |
} |
+proc isquick {} { |
+ set ret 0 |
+ catch {set ret $::G(isquick)} |
+ set ret |
+} |
+ |
#------------------------------------------------------------------------- |
# |
proc slave_test_script {script} { |
@@ -2080,6 +2229,41 @@ proc test_restore_config_pagecache {} { |
sqlite3 db test.db |
} |
+proc test_find_binary {nm} { |
+ if {$::tcl_platform(platform)=="windows"} { |
+ set ret "$nm.exe" |
+ } else { |
+ set ret $nm |
+ } |
+ set ret [file normalize [file join $::cmdlinearg(TESTFIXTURE_HOME) $ret]] |
+ if {![file executable $ret]} { |
+ finish_test |
+ return "" |
+ } |
+ return $ret |
+} |
+ |
+# Find the name of the 'shell' executable (e.g. "sqlite3.exe") to use for |
+# the tests in shell[1-5].test. If no such executable can be found, invoke |
+# [finish_test ; return] in the callers context. |
+# |
+proc test_find_cli {} { |
+ set prog [test_find_binary sqlite3] |
+ if {$prog==""} { return -code return } |
+ return $prog |
+} |
+ |
+# Find the name of the 'sqldiff' executable (e.g. "sqlite3.exe") to use for |
+# the tests in sqldiff tests. If no such executable can be found, invoke |
+# [finish_test ; return] in the callers context. |
+# |
+proc test_find_sqldiff {} { |
+ set prog [test_find_binary sqldiff] |
+ if {$prog==""} { return -code return } |
+ return $prog |
+} |
+ |
+ |
# If the library is compiled with the SQLITE_DEFAULT_AUTOVACUUM macro set |
# to non-zero, then set the global variable $AUTOVACUUM to 1. |
set AUTOVACUUM $sqlite_options(default_autovacuum) |