# 2001 September 15
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements some common TCL routines used for regression
# testing the SQLite library
#
# $Id: tester.tcl,v 1.143 2009/04/09 01:23:49 drh Exp $
#-------------------------------------------------------------------------
# The commands provided by the code in this file to help with creating
# test cases are as follows:
#
# Commands to manipulate the db and the file-system at a high level:
#
# is_relative_file
# test_pwd
# get_pwd
# copy_file FROM TO
# delete_file FILENAME
# drop_all_tables ?DB?
# drop_all_indexes ?DB?
# forcecopy FROM TO
# forcedelete FILENAME
#
# Test the capability of the SQLite version built into the interpreter to
# determine if a specific test can be run:
#
# capable EXPR
# ifcapable EXPR
#
# Calulate checksums based on database contents:
#
# dbcksum DB DBNAME
# allcksum ?DB?
# cksum ?DB?
#
# Commands to execute/explain SQL statements:
#
# memdbsql SQL
# stepsql DB SQL
# execsql2 SQL
# explain_no_trace SQL
# explain SQL ?DB?
# catchsql SQL ?DB?
# execsql SQL ?DB?
#
# Commands to run test cases:
#
# do_ioerr_test TESTNAME ARGS...
# crashsql ARGS...
# integrity_check TESTNAME ?DB?
# verify_ex_errcode TESTNAME EXPECTED ?DB?
# do_test TESTNAME SCRIPT EXPECTED
# do_execsql_test TESTNAME SQL EXPECTED
# do_catchsql_test TESTNAME SQL EXPECTED
# do_timed_execsql_test TESTNAME SQL EXPECTED
#
# Commands providing a lower level interface to the global test counters:
#
# set_test_counter COUNTER ?VALUE?
# omit_test TESTNAME REASON ?APPEND?
# fail_test TESTNAME
# incr_ntest
#
# Command run at the end of each test file:
#
# finish_test
#
# Commands to help create test files that run with the "WAL" and other
# permutations (see file permutations.test):
#
# wal_is_wal_mode
# wal_set_journal_mode ?DB?
# wal_check_journal_mode TESTNAME?DB?
# permutation
# presql
#
# Command to test whether or not --verbose=1 was specified on the command
# line (returns 0 for not-verbose, 1 for verbose and 2 for "verbose in the
# output file only").
#
# verbose
#
# Only run this script once. If sourced a second time, make it a no-op
if return
# Set the precision of FP arithmatic used by the interpreter. And
# configure SQLite to take database file locks on the page that begins
# 64KB into the database file instead of the one 1GB in. This means
# the code that handles that special case can be tested without creating
# very large database files.
#
set tcl_precision 15
sqlite3_test_control_pending_byte 0x0010000
# If the pager codec is available, create a wrapper for the [sqlite3]
# command that appends "-key {xyzzy}" to the command line. i.e. this:
#
# sqlite3 db test.db
#
# becomes
#
# sqlite3 db test.db -key {xyzzy}
#
if
# Return the string representing the name of the current directory. On
# Windows, the result is "normalized" to whatever our parent command shell
# is using to prevent case-mismatch issues.
#
# Copy file $from into $to. This is used because some versions of
# TCL for windows (notably the 8.4.1 binary package shipped with the
# current mingw release) have a broken "file copy" command.
#
# Check if a file name is relative
#
# If the VFS supports using the current directory, returns [pwd];
# otherwise, it returns only the provided suffix string (which is
# empty by default).
#
# Delete a file or directory
#
if
# This command should be called after loading tester.tcl from within
# all test scripts that are incompatible with encryption codecs.
#
unset -nocomplain do_not_use_codec
# Return true if the "reserved_bytes" integer on database files is non-zero.
#
# Print a HELP message and exit
#
# The following block only runs the first time this file is sourced. It
# does not run in slave interpreters (since the ::cmdlinearg array is
# populated before the test script is run in slave interpreters).
#
if
# Update the soft-heap-limit each time this script is run. In that
# way if an individual test file changes the soft-heap-limit, it
# will be reset at the start of the next test file.
#
sqlite3_soft_heap_limit64 $cmdlinearg(soft-heap-limit)
sqlite3_hard_heap_limit64 $cmdlinearg(hard-heap-limit)
# Create a test database
#
reset_db
# Abort early if this script has been run before.
#
if return
# Make sure memory statistics are enabled.
#
sqlite3_config_memstatus 1
# Initialize the test counters and set up commands to access them.
# Or, if this is a slave interpreter, set up aliases to write the
# counters in the parent interpreter.
#
if
# Record the fact that a sequence of tests were omitted.
#
# Record the fact that a test failed.
#
# Remember a warning message to be displayed at the conclusion of all testing
#
# Increment the number of tests run
#
# Return true if --verbose=1 was specified on the command line. Otherwise,
# return false.
#
# Use the following commands instead of [puts] for test output within
# this file. Test scripts can still use regular [puts], which is directed
# to stdout and, if one is open, the --output file.
#
# output1: output that should be printed if --verbose=1 was specified.
# output2: output that should be printed unconditionally.
# output2_if_no_verbose: output that should be printed only if --verbose=0.
#
# Override the [puts] command so that if no channel is explicitly
# specified the string is written to both stdout and to the file
# specified by "--output=", if any.
#
rename puts puts_original
# 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.
#
# Run SQL and verify that the number of "vmsteps" required is greater
# than or less than some constant.
#
# Either:
#
# do_execsql_test TESTNAME SQL ?RES?
# do_execsql_test -db DB TESTNAME SQL ?RES?
#
# Run an EXPLAIN QUERY PLAN $sql in database "db". Then rewrite the output
# as an ASCII-art graph and return a string that is that graph.
#
# Hexadecimal literals in the output text are converted into "xxxxxx" since those
# literals are pointer values that might very from one run of the test to the
# next, yet we want the output to be consistent.
#
# Helper routine for [query_plan_graph SQL]:
#
# Output rows of the graph that are children of $level.
#
# prefix: Prepend to every output line
#
# dxname: Name of an array variable that stores text describe
# The description for $id is $dx($id)
#
# cxname: Name of an array variable holding children of item.
# Children of $id are $cx($id)
#
# level: Render all lines that are children of $level
#
# Do an EXPLAIN QUERY PLAN test on input $sql with expected results $res
#
# If $res begins with a "\s+QUERY PLAN\n" then it is assumed to be the
# complete graph which must match the output of [query_plan_graph $sql]
# exactly.
#
# If $res does not begin with "\s+QUERY PLAN\n" then take it is a string
# that must be found somewhere in the query plan output.
#
#-------------------------------------------------------------------------
# Usage: do_select_tests PREFIX ?SWITCHES? TESTLIST
#
# Where switches are:
#
# -errorformat FMTSTRING
# -count
# -query SQL
# -tclquery TCL
# -repair TCL
#
# Run an SQL script.
# Return the number of microseconds per statement.
#
# Clear out left-over configuration setup from the end of a test
#
# Run this routine last
#
# Display memory statistics for analysis and debugging purposes.
#
# A procedure to execute SQL
#
# Execute SQL and catch exceptions.
#
# Do an VDBE code dump on the SQL given
#
# Show the VDBE program for an SQL statement but omit the Trace
# opcode at the beginning. This procedure can be used to prove
# that different SQL statements generate exactly the same VDBE code.
#
# Another procedure to execute SQL. This one includes the field
# names in the returned list.
#
# Use a temporary in-memory database to execute SQL statements
#
# Use the non-callback API to execute multiple SQL statements
#
# Do an integrity check of the entire database
#
# Check the extended error code
#
# Return true if the SQL statement passed as the second argument uses a
# statement transaction.
#
# Returns non-zero if the capabilities are present; zero otherwise.
#
# Evaluate a boolean expression of capabilities. If true, execute the
# code. Omit the code if false.
#
# This proc execs a seperate process that crashes midway through executing
# the SQL script $sql on database test.db.
#
# The crash occurs during a sync() of file $crashfile. When the crash
# occurs a random subset of all unsynced writes made by the process are
# written into the files on disk. Argument $crashdelay indicates the
# number of file syncs to wait before crashing.
#
# The return value is a list of two elements. The first element is a
# boolean, indicating whether or not the process actually crashed or
# reported some other error. The second element in the returned list is the
# error message. This is "child process exited abnormally" if the crash
# occurred.
#
# crashsql -delay CRASHDELAY -file CRASHFILE ?-blocksize BLOCKSIZE? $sql
#
# crash_on_write ?-devchar DEVCHAR? CRASHDELAY SQL
#
# Usage: do_ioerr_test <test number> <options...>
#
# This proc is used to implement test cases that check that IO errors
# are correctly handled. The first argument, <test number>, is an integer
# used to name the tests executed by this proc. Options are as follows:
#
# -tclprep TCL script to run to prepare test.
# -sqlprep SQL script to run to prepare test.
# -tclbody TCL script to run with IO error simulation.
# -sqlbody TCL script to run with IO error simulation.
# -exclude List of 'N' values not to test.
# -erc Use extended result codes
# -persist Make simulated I/O errors persistent
# -start Value of 'N' to begin with (default 1)
#
# -cksum Boolean. If true, test that the database does
# not change during the execution of the test case.
#
# Return a checksum based on the contents of the main database associated
# with connection $db
#
# Generate a checksum based on the contents of the main and temp tables
# database $db. If the checksum of two databases is the same, and the
# integrity-check passes for both, the two databases are identical.
#
# Generate a checksum based on the contents of a single database with
# a database connection. The name of the database is $dbname.
# Examples of $dbname are "temp" or "main".
#
# Drop all tables in database [db]
# Drop all auxiliary indexes from the main database opened by handle [db].
#
#-------------------------------------------------------------------------
# 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
# in rollback mode. The following Tcl procs are used to make this less
# intrusive:
#
# wal_set_journal_mode ?DB?
#
# If running a WAL test, execute "PRAGMA journal_mode = wal" using
# connection handle DB. Otherwise, this command is a no-op.
#
# wal_check_journal_mode TESTNAME ?DB?
#
# If running a WAL test, execute a tests case that fails if the main
# database for connection handle DB is not currently a WAL database.
# Otherwise (if not running a WAL permutation) this is a no-op.
#
# wal_is_wal_mode
#
# Returns true if this test should be run in WAL mode. False otherwise.
#
#-------------------------------------------------------------------------
#
# Open a new connection on database test.db and execute the SQL script
# supplied as an argument. Before returning, close the new conection and
# restore the 4 byte fields starting at header offsets 28, 92 and 96
# to the values they held before the SQL was executed. This simulates
# a write by a pre-3.7.0 client.
#
# Close any connections named [db], [db2] or [db3]. Then use sqlite3_config
# to configure the size of the PAGECACHE allocation using the parameters
# provided to this command. Save the old PAGECACHE parameters in a global
# variable so that [test_restore_config_pagecache] can restore the previous
# configuration.
#
# Before returning, reopen connection [db] on file test.db.
#
# Close any connections named [db], [db2] or [db3]. Then use sqlite3_config
# to configure the size of the PAGECACHE allocation to the size saved in
# the global variable by an earlier call to [test_set_config_pagecache].
#
# Before returning, reopen connection [db] on file test.db.
#
# Find the name of the 'shell' executable (e.g. "sqlite3.exe") to use for
# the tests in shell*.test. If no such executable can be found, invoke
# [finish_test ; return] in the callers context.
#
# Find invocation of the 'shell' executable (e.g. "sqlite3.exe") to use
# for the tests in shell*.test with optional valgrind prefix when the
# environment variable SQLITE_CLI_VALGRIND_OPT is set. The set value
# operates as follows:
# empty or 0 => no valgrind prefix;
# 1 => valgrind options for memory leak check;
# other => use value as valgrind options.
# If shell not found, invoke [finish_test ; return] in callers context.
#
# 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.
#
# Call sqlite3_expanded_sql() on all statements associated with database
# connection $db. This sometimes finds use-after-free bugs if run with
# valgrind or address-sanitizer.
# 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)
# Make sure the FTS enhanced query syntax is disabled.
set sqlite_fts3_enable_parentheses 0
# During testing, assume that all database files are well-formed. The
# few test cases that deliberately corrupt database files should rescind
# this setting by invoking "database_can_be_corrupt"
#
database_never_corrupt
extra_schema_checks 1
source $testdir/thread_common.tcl
source $testdir/malloc_common.tcl
set tester_tcl_has_run 1