modernc.org/cc@v1.0.1/v2/testdata/_sqlite/test/releasetest.tcl (about)

     1  #!/usr/bin/tclsh
     2  #
     3  # Documentation for this script. This may be output to stderr
     4  # if the script is invoked incorrectly. See the [process_options]
     5  # proc below.
     6  #
     7  set ::USAGE_MESSAGE {
     8  This Tcl script is used to test the various configurations required
     9  before releasing a new version. Supported command line options (all
    10  optional) are:
    11  
    12      --buildonly                        (Just build testfixture - do not run)
    13      --config   CONFIGNAME              (Run only CONFIGNAME)
    14      --dryrun                           (Print what would have happened)
    15      -f|--force                         (Run even if uncommitted changes)
    16      --info                             (Show diagnostic info)
    17      --jobs     N                       (Use N processes - default 1)
    18      --keep                             (Delete no files after each test run)
    19      --msvc                             (Use MSVC as the compiler)
    20      --platform PLATFORM                (see below)
    21      --progress                         (Show progress messages)
    22      --quick                            (Run "veryquick.test" only)
    23      --veryquick                        (Run "make smoketest" only)
    24      --with-tcl=DIR                     (Use TCL build at DIR)
    25  
    26  The script determines the default value for --platform using the
    27  $tcl_platform(os) and $tcl_platform(machine) variables.  Supported
    28  platforms are "Linux-x86", "Linux-x86_64", "Darwin-i386",
    29  "Darwin-x86_64", "Windows NT-intel", and "Windows NT-amd64".
    30  
    31  Every test begins with a fresh run of the configure script at the top
    32  of the SQLite source tree.
    33  }
    34  
    35  # Return a timestamp of the form HH:MM:SS
    36  #
    37  proc now {} {
    38    return [clock format [clock seconds] -format %H:%M:%S]
    39  }
    40  
    41  # Omit comments (text between # and \n) in a long multi-line string.
    42  #
    43  proc strip_comments {in} {
    44    regsub -all {#[^\n]*\n} $in {} out
    45    return $out
    46  }
    47  
    48  array set ::Configs [strip_comments {
    49    "Default" {
    50      -O2
    51      --disable-amalgamation --disable-shared
    52      --enable-session
    53    }
    54    "Sanitize" {
    55      CC=clang -fsanitize=undefined
    56      -DSQLITE_ENABLE_STAT4
    57      --enable-session
    58    }
    59    "Stdcall" {
    60      -DUSE_STDCALL=1
    61      -O2
    62    }
    63    "Have-Not" {
    64      # The "Have-Not" configuration sets all possible -UHAVE_feature options
    65      # in order to verify that the code works even on platforms that lack
    66      # these support services.
    67      -DHAVE_FDATASYNC=0
    68      -DHAVE_GMTIME_R=0
    69      -DHAVE_ISNAN=0
    70      -DHAVE_LOCALTIME_R=0
    71      -DHAVE_LOCALTIME_S=0
    72      -DHAVE_MALLOC_USABLE_SIZE=0
    73      -DHAVE_STRCHRNUL=0
    74      -DHAVE_USLEEP=0
    75      -DHAVE_UTIME=0
    76    }
    77    "Unlock-Notify" {
    78      -O2
    79      -DSQLITE_ENABLE_UNLOCK_NOTIFY
    80      -DSQLITE_THREADSAFE
    81      -DSQLITE_TCL_DEFAULT_FULLMUTEX=1
    82    }
    83    "Secure-Delete" {
    84      -O2
    85      -DSQLITE_SECURE_DELETE=1
    86      -DSQLITE_SOUNDEX=1
    87    }
    88    "Update-Delete-Limit" {
    89      -O2
    90      -DSQLITE_DEFAULT_FILE_FORMAT=4
    91      -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1
    92      -DSQLITE_ENABLE_STMT_SCANSTATUS
    93      -DSQLITE_LIKE_DOESNT_MATCH_BLOBS
    94      -DSQLITE_ENABLE_CURSOR_HINTS
    95      --enable-json1
    96    }
    97    "Check-Symbols" {
    98      -DSQLITE_MEMDEBUG=1
    99      -DSQLITE_ENABLE_FTS3_PARENTHESIS=1
   100      -DSQLITE_ENABLE_FTS3=1
   101      -DSQLITE_ENABLE_RTREE=1
   102      -DSQLITE_ENABLE_MEMSYS5=1
   103      -DSQLITE_ENABLE_MEMSYS3=1
   104      -DSQLITE_ENABLE_COLUMN_METADATA=1
   105      -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1
   106      -DSQLITE_SECURE_DELETE=1
   107      -DSQLITE_SOUNDEX=1
   108      -DSQLITE_ENABLE_ATOMIC_WRITE=1
   109      -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1
   110      -DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1
   111      -DSQLITE_ENABLE_STAT4
   112      -DSQLITE_ENABLE_STMT_SCANSTATUS
   113      --enable-json1 --enable-fts5 --enable-session
   114    }
   115    "Debug-One" {
   116      --disable-shared
   117      -O2 -funsigned-char
   118      -DSQLITE_DEBUG=1
   119      -DSQLITE_MEMDEBUG=1
   120      -DSQLITE_MUTEX_NOOP=1
   121      -DSQLITE_TCL_DEFAULT_FULLMUTEX=1
   122      -DSQLITE_ENABLE_FTS3=1
   123      -DSQLITE_ENABLE_RTREE=1
   124      -DSQLITE_ENABLE_MEMSYS5=1
   125      -DSQLITE_ENABLE_COLUMN_METADATA=1
   126      -DSQLITE_ENABLE_STAT4
   127      -DSQLITE_ENABLE_HIDDEN_COLUMNS
   128      -DSQLITE_MAX_ATTACHED=125
   129      -DSQLITE_MUTATION_TEST
   130    }
   131    "Fast-One" {
   132      -O6
   133      -DSQLITE_ENABLE_FTS4=1
   134      -DSQLITE_ENABLE_RTREE=1
   135      -DSQLITE_ENABLE_STAT4
   136      -DSQLITE_ENABLE_RBU
   137      -DSQLITE_MAX_ATTACHED=125
   138      -DLONGDOUBLE_TYPE=double
   139      --enable-session
   140    }
   141    "Device-One" {
   142      -O2
   143      -DSQLITE_DEBUG=1
   144      -DSQLITE_DEFAULT_AUTOVACUUM=1
   145      -DSQLITE_DEFAULT_CACHE_SIZE=64
   146      -DSQLITE_DEFAULT_PAGE_SIZE=1024
   147      -DSQLITE_DEFAULT_TEMP_CACHE_SIZE=32
   148      -DSQLITE_DISABLE_LFS=1
   149      -DSQLITE_ENABLE_ATOMIC_WRITE=1
   150      -DSQLITE_ENABLE_IOTRACE=1
   151      -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1
   152      -DSQLITE_MAX_PAGE_SIZE=4096
   153      -DSQLITE_OMIT_LOAD_EXTENSION=1
   154      -DSQLITE_OMIT_PROGRESS_CALLBACK=1
   155      -DSQLITE_OMIT_VIRTUALTABLE=1
   156      -DSQLITE_ENABLE_HIDDEN_COLUMNS
   157      -DSQLITE_TEMP_STORE=3
   158      --enable-json1
   159    }
   160    "Device-Two" {
   161      -DSQLITE_4_BYTE_ALIGNED_MALLOC=1
   162      -DSQLITE_DEFAULT_AUTOVACUUM=1
   163      -DSQLITE_DEFAULT_CACHE_SIZE=1000
   164      -DSQLITE_DEFAULT_LOCKING_MODE=0
   165      -DSQLITE_DEFAULT_PAGE_SIZE=1024
   166      -DSQLITE_DEFAULT_TEMP_CACHE_SIZE=1000
   167      -DSQLITE_DISABLE_LFS=1
   168      -DSQLITE_ENABLE_FTS3=1
   169      -DSQLITE_ENABLE_MEMORY_MANAGEMENT=1
   170      -DSQLITE_ENABLE_RTREE=1
   171      -DSQLITE_MAX_COMPOUND_SELECT=50
   172      -DSQLITE_MAX_PAGE_SIZE=32768
   173      -DSQLITE_OMIT_TRACE=1
   174      -DSQLITE_TEMP_STORE=3
   175      -DSQLITE_THREADSAFE=2
   176      --enable-json1 --enable-fts5 --enable-session
   177    }
   178    "Locking-Style" {
   179      -O2
   180      -DSQLITE_ENABLE_LOCKING_STYLE=1
   181    }
   182    "Apple" {
   183      -Os
   184      -DHAVE_GMTIME_R=1
   185      -DHAVE_ISNAN=1
   186      -DHAVE_LOCALTIME_R=1
   187      -DHAVE_PREAD=1
   188      -DHAVE_PWRITE=1
   189      -DHAVE_USLEEP=1
   190      -DHAVE_USLEEP=1
   191      -DHAVE_UTIME=1
   192      -DSQLITE_DEFAULT_CACHE_SIZE=1000
   193      -DSQLITE_DEFAULT_CKPTFULLFSYNC=1
   194      -DSQLITE_DEFAULT_MEMSTATUS=1
   195      -DSQLITE_DEFAULT_PAGE_SIZE=1024
   196      -DSQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS=1
   197      -DSQLITE_ENABLE_API_ARMOR=1
   198      -DSQLITE_ENABLE_AUTO_PROFILE=1
   199      -DSQLITE_ENABLE_FLOCKTIMEOUT=1
   200      -DSQLITE_ENABLE_FTS3=1
   201      -DSQLITE_ENABLE_FTS3_PARENTHESIS=1
   202      -DSQLITE_ENABLE_FTS3_TOKENIZER=1
   203      if:os=="Darwin" -DSQLITE_ENABLE_LOCKING_STYLE=1
   204      -DSQLITE_ENABLE_PERSIST_WAL=1
   205      -DSQLITE_ENABLE_PURGEABLE_PCACHE=1
   206      -DSQLITE_ENABLE_RTREE=1
   207      -DSQLITE_ENABLE_SNAPSHOT=1
   208      # -DSQLITE_ENABLE_SQLLOG=1
   209      -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1
   210      -DSQLITE_MAX_LENGTH=2147483645
   211      -DSQLITE_MAX_VARIABLE_NUMBER=500000
   212      # -DSQLITE_MEMDEBUG=1
   213      -DSQLITE_NO_SYNC=1
   214      -DSQLITE_OMIT_AUTORESET=1
   215      -DSQLITE_OMIT_LOAD_EXTENSION=1
   216      -DSQLITE_PREFER_PROXY_LOCKING=1
   217      -DSQLITE_SERIES_CONSTRAINT_VERIFY=1
   218      -DSQLITE_THREADSAFE=2
   219      -DSQLITE_USE_URI=1
   220      -DSQLITE_WRITE_WALFRAME_PREBUFFERED=1
   221      -DUSE_GUARDED_FD=1
   222      -DUSE_PREAD=1
   223      --enable-json1 --enable-fts5
   224    }
   225    "Extra-Robustness" {
   226      -DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1
   227      -DSQLITE_MAX_ATTACHED=62
   228    }
   229    "Devkit" {
   230      -DSQLITE_DEFAULT_FILE_FORMAT=4
   231      -DSQLITE_MAX_ATTACHED=30
   232      -DSQLITE_ENABLE_COLUMN_METADATA
   233      -DSQLITE_ENABLE_FTS4
   234      -DSQLITE_ENABLE_FTS5
   235      -DSQLITE_ENABLE_FTS4_PARENTHESIS
   236      -DSQLITE_DISABLE_FTS4_DEFERRED
   237      -DSQLITE_ENABLE_RTREE
   238      --enable-json1 --enable-fts5
   239    }
   240    "No-lookaside" {
   241      -DSQLITE_TEST_REALLOC_STRESS=1
   242      -DSQLITE_OMIT_LOOKASIDE=1
   243      -DHAVE_USLEEP=1
   244    }
   245    "Valgrind" {
   246      -DSQLITE_ENABLE_STAT4
   247      -DSQLITE_ENABLE_FTS4
   248      -DSQLITE_ENABLE_RTREE
   249      -DSQLITE_ENABLE_HIDDEN_COLUMNS
   250      --enable-json1
   251    }
   252  
   253    # The next group of configurations are used only by the
   254    # Failure-Detection platform.  They are all the same, but we need
   255    # different names for them all so that they results appear in separate
   256    # subdirectories.
   257    #
   258    Fail0 {-O0}
   259    Fail2 {-O0}
   260    Fail3 {-O0}
   261    Fail4 {-O0}
   262    FuzzFail1 {-O0}
   263    FuzzFail2 {-O0}
   264  }]
   265  
   266  array set ::Platforms [strip_comments {
   267    Linux-x86_64 {
   268      "Check-Symbols"           checksymbols
   269      "Fast-One"                fuzztest
   270      "Debug-One"               "mptest test"
   271      "Have-Not"                test
   272      "Secure-Delete"           test
   273      "Unlock-Notify"           "QUICKTEST_INCLUDE=notify2.test test"
   274      "Update-Delete-Limit"     test
   275      "Extra-Robustness"        test
   276      "Device-Two"              test
   277      "No-lookaside"            test
   278      "Devkit"                  test
   279      "Apple"                   test
   280      "Sanitize"                {QUICKTEST_OMIT=func4.test,nan.test test}
   281      "Device-One"              fulltest
   282      "Default"                 "threadtest fulltest"
   283      "Valgrind"                valgrindtest
   284    }
   285    Linux-i686 {
   286      "Devkit"                  test
   287      "Have-Not"                test
   288      "Unlock-Notify"           "QUICKTEST_INCLUDE=notify2.test test"
   289      "Device-One"              test
   290      "Device-Two"              test
   291      "Default"                 "threadtest fulltest"
   292    }
   293    Darwin-i386 {
   294      "Locking-Style"           "mptest test"
   295      "Have-Not"                test
   296      "Apple"                   "threadtest fulltest"
   297    }
   298    Darwin-x86_64 {
   299      "Locking-Style"           "mptest test"
   300      "Have-Not"                test
   301      "Apple"                   "threadtest fulltest"
   302    }
   303    "Windows NT-intel" {
   304      "Stdcall"                 test
   305      "Have-Not"                test
   306      "Default"                 "mptest fulltestonly"
   307    }
   308    "Windows NT-amd64" {
   309      "Stdcall"                 test
   310      "Have-Not"                test
   311      "Default"                 "mptest fulltestonly"
   312    }
   313  
   314    # The Failure-Detection platform runs various tests that deliberately
   315    # fail.  This is used as a test of this script to verify that this script
   316    # correctly identifies failures.
   317    #
   318    Failure-Detection {
   319      Fail0     "TEST_FAILURE=0 test"
   320      Sanitize  "TEST_FAILURE=1 test"
   321      Fail2     "TEST_FAILURE=2 valgrindtest"
   322      Fail3     "TEST_FAILURE=3 valgrindtest"
   323      Fail4     "TEST_FAILURE=4 test"
   324      FuzzFail1 "TEST_FAILURE=5 test"
   325      FuzzFail2 "TEST_FAILURE=5 valgrindtest"
   326    }
   327  }]
   328  
   329  
   330  # End of configuration section.
   331  #########################################################################
   332  #########################################################################
   333  
   334  # Configuration verification: Check that each entry in the list of configs
   335  # specified for each platforms exists.
   336  #
   337  foreach {key value} [array get ::Platforms] {
   338    foreach {v t} $value {
   339      if {0==[info exists ::Configs($v)]} {
   340        puts stderr "No such configuration: \"$v\""
   341        exit -1
   342      }
   343    }
   344  }
   345  
   346  # Output log.   Disabled for slave interpreters.
   347  #
   348  if {[lindex $argv end]!="--slave"} {
   349    set LOG [open releasetest-out.txt w]
   350    proc PUTS {txt} {
   351      puts $txt
   352      puts $::LOG $txt
   353      flush $::LOG
   354    }
   355    proc PUTSNNL {txt} {
   356      puts -nonewline $txt
   357      puts -nonewline $::LOG $txt
   358      flush $::LOG
   359    }
   360    proc PUTSERR {txt} {
   361      puts stderr $txt
   362      puts $::LOG $txt
   363      flush $::LOG
   364    }
   365    puts $LOG "$argv0 $argv"
   366    set tm0 [clock format [clock seconds] -format {%Y-%m-%d %H:%M:%S} -gmt 1]
   367    puts $LOG "start-time: $tm0 UTC"
   368  } else {
   369    proc PUTS {txt} {
   370      puts $txt
   371    }
   372    proc PUTSNNL {txt} {
   373      puts -nonewline $txt
   374    }
   375    proc PUTSERR {txt} {
   376      puts stderr $txt
   377    }
   378  }
   379  
   380  # Open the file $logfile and look for a report on the number of errors
   381  # and the number of test cases run.  Add these values to the global
   382  # $::NERRCASE and $::NTESTCASE variables.
   383  #
   384  # If any errors occur, then write into $errmsgVar the text of an appropriate
   385  # one-line error message to show on the output.
   386  #
   387  proc count_tests_and_errors {logfile rcVar errmsgVar} {
   388    if {$::DRYRUN} return
   389    upvar 1 $rcVar rc $errmsgVar errmsg
   390    set fd [open $logfile rb]
   391    set seen 0
   392    while {![eof $fd]} {
   393      set line [gets $fd]
   394      if {[regexp {(\d+) errors out of (\d+) tests} $line all nerr ntest]} {
   395        incr ::NERRCASE $nerr
   396        incr ::NTESTCASE $ntest
   397        set seen 1
   398        if {$nerr>0} {
   399          set rc 1
   400          set errmsg $line
   401        }
   402      }
   403      if {[regexp {runtime error: +(.*)} $line all msg]} {
   404        # skip over "value is outside range" errors
   405        if {[regexp {value .* is outside the range of representable} $line]} {
   406           # noop
   407        } else {
   408          incr ::NERRCASE
   409          if {$rc==0} {
   410            set rc 1
   411            set errmsg $msg
   412          }
   413        }
   414      }
   415      if {[regexp {fatal error +(.*)} $line all msg]} {
   416        incr ::NERRCASE
   417        if {$rc==0} {
   418          set rc 1
   419          set errmsg $msg
   420        }
   421      }
   422      if {[regexp {ERROR SUMMARY: (\d+) errors.*} $line all cnt] && $cnt>0} {
   423        incr ::NERRCASE
   424        if {$rc==0} {
   425          set rc 1
   426          set errmsg $all
   427        }
   428      }
   429      if {[regexp {^VERSION: 3\.\d+.\d+} $line]} {
   430        set v [string range $line 9 end]
   431        if {$::SQLITE_VERSION eq ""} {
   432          set ::SQLITE_VERSION $v
   433        } elseif {$::SQLITE_VERSION ne $v} {
   434          set rc 1
   435          set errmsg "version conflict: {$::SQLITE_VERSION} vs. {$v}"
   436        }
   437      }
   438    }
   439    close $fd
   440    if {$::BUILDONLY} {
   441      incr ::NTESTCASE
   442      if {$rc!=0} {
   443        set errmsg "Build failed"
   444      }
   445    } elseif {!$seen} {
   446      set rc 1
   447      set errmsg "Test did not complete"
   448      if {[file readable core]} {
   449        append errmsg " - core file exists"
   450      }
   451    }
   452  }
   453  
   454  #--------------------------------------------------------------------------
   455  # This command is invoked as the [main] routine for scripts run with the
   456  # "--slave" option.
   457  #
   458  # For each test (i.e. "configure && make test" execution), the master
   459  # process spawns a process with the --slave option. It writes two lines
   460  # to the slaves stdin. The first contains a single boolean value - the
   461  # value of ::TRACE to use in the slave script. The second line contains a
   462  # list in the same format as each element of the list passed to the
   463  # [run_all_test_suites] command in the master process.
   464  #
   465  # The slave then runs the "configure && make test" commands specified. It
   466  # exits successfully if the tests passes, or with a non-zero error code
   467  # otherwise.
   468  #
   469  proc run_slave_test {} {
   470    # Read global vars configuration from stdin.
   471    set V [gets stdin]
   472    foreach {::TRACE ::MSVC ::DRYRUN ::KEEPFILES} $V {}
   473  
   474    # Read the test-suite configuration from stdin.
   475    set T [gets stdin]
   476    foreach {title dir configOpts testtarget makeOpts cflags opts} $T {}
   477  
   478    # Create and switch to the test directory.
   479    set normaldir [file normalize $dir]
   480    set ::env(SQLITE_TMPDIR) $normaldir
   481    trace_cmd file mkdir $dir
   482    trace_cmd cd $dir
   483    catch {file delete core}
   484    catch {file delete test.log}
   485  
   486    # Run the "./configure && make" commands.
   487    set rc 0
   488    set rc [catch [configureCommand $configOpts]]
   489    if {!$rc} {
   490      if {[info exists ::env(TCLSH_CMD)]} {
   491        set savedEnv(TCLSH_CMD) $::env(TCLSH_CMD)
   492      } else {
   493        unset -nocomplain savedEnv(TCLSH_CMD)
   494      }
   495      set ::env(TCLSH_CMD) [file nativename [info nameofexecutable]]
   496      set rc [catch [makeCommand $testtarget $makeOpts $cflags $opts]]
   497      if {[info exists savedEnv(TCLSH_CMD)]} {
   498        set ::env(TCLSH_CMD) $savedEnv(TCLSH_CMD)
   499      } else {
   500        unset -nocomplain ::env(TCLSH_CMD)
   501      }
   502    }
   503  
   504    # Clean up lots of extra files if --keep was not specified.
   505    if {$::KEEPFILES==0} { cleanup $normaldir }
   506  
   507    # Exis successfully if the test passed, or with a non-zero error code
   508    # otherwise.
   509    exit $rc
   510  }
   511  
   512  # This command is invoked in the master process each time a slave
   513  # file-descriptor is readable.
   514  #
   515  proc slave_fileevent {fd T tm1} {
   516    global G
   517    foreach {title dir configOpts testtarget makeOpts cflags opts} $T {}
   518  
   519    if {[eof $fd]} {
   520      fconfigure $fd -blocking 1
   521      set rc [catch { close $fd }]
   522  
   523      set errmsg {}
   524      set logfile [file join $dir test.log]
   525      if {[file exists $logfile]} {
   526        count_tests_and_errors [file join $dir test.log] rc errmsg
   527      } elseif {$rc==0 && !$::DRYRUN} {
   528        set rc 1
   529        set errmsg "no test.log file..."
   530      }
   531  
   532      if {!$::TRACE} {
   533        set tm2 [clock seconds]
   534        set hours [expr {($tm2-$tm1)/3600}]
   535        set minutes [expr {(($tm2-$tm1)/60)%60}]
   536        set seconds [expr {($tm2-$tm1)%60}]
   537        set tm [format (%02d:%02d:%02d) $hours $minutes $seconds]
   538  
   539        if {$rc} {
   540          set status FAIL
   541          incr ::NERR
   542        } else {
   543          set status Ok
   544        }
   545  
   546        set n [string length $title]
   547        if {$::PROGRESS_MSGS} {
   548          PUTS "finished: ${title}[string repeat . [expr {53-$n}]] $status $tm"
   549        } else {
   550          PUTS "${title}[string repeat . [expr {63-$n}]] $status $tm"
   551        }
   552        if {$errmsg!=""} {PUTS "     $errmsg"}
   553        flush stdout
   554      }
   555  
   556      incr G(nJob) -1
   557    } else {
   558      set line [gets $fd]
   559      if {[string trim $line] != ""} {
   560        puts "Trace   : $title - \"$line\""
   561      }
   562    }
   563  }
   564  
   565  #--------------------------------------------------------------------------
   566  # The only argument passed to this function is a list of test-suites to
   567  # run. Each "test-suite" is itself a list consisting of the following
   568  # elements:
   569  #
   570  #   * Test title (for display).
   571  #   * The name of the directory to run the test in.
   572  #   * The argument for [configureCommand]
   573  #   * The first argument for [makeCommand]
   574  #   * The second argument for [makeCommand]
   575  #   * The third argument for [makeCommand]
   576  #
   577  proc run_all_test_suites {alltests} {
   578    global G
   579    set tests $alltests
   580  
   581    set G(nJob) 0
   582  
   583    while {[llength $tests]>0 || $G(nJob)>0} {
   584      if {$G(nJob)>=$::JOBS || [llength $tests]==0} {
   585        vwait G(nJob)
   586      }
   587  
   588      if {[llength $tests]>0} {
   589        set T [lindex $tests 0]
   590        set tests [lrange $tests 1 end]
   591        foreach {title dir configOpts testtarget makeOpts cflags opts} $T {}
   592        if {$::PROGRESS_MSGS && !$::TRACE} {
   593          set n [string length $title]
   594          PUTS "starting: ${title} at [now]"
   595          flush stdout
   596        }
   597  
   598        # Run the job.
   599        #
   600        set tm1 [clock seconds]
   601        incr G(nJob)
   602        set script [file normalize [info script]]
   603        set fd [open "|[info nameofexecutable] $script --slave" r+]
   604        fconfigure $fd -blocking 0
   605        fileevent $fd readable [list slave_fileevent $fd $T $tm1]
   606        puts $fd [list $::TRACE $::MSVC $::DRYRUN $::KEEPFILES]
   607        puts $fd [list {*}$T]
   608        flush $fd
   609      }
   610    }
   611  }
   612  
   613  proc add_test_suite {listvar name testtarget config} {
   614    upvar $listvar alltests
   615  
   616    # Tcl variable $opts is used to build up the value used to set the
   617    # OPTS Makefile variable. Variable $cflags holds the value for
   618    # CFLAGS. The makefile will pass OPTS to both gcc and lemon, but
   619    # CFLAGS is only passed to gcc.
   620    #
   621    set makeOpts ""
   622    set cflags [expr {$::MSVC ? "-Zi" : "-g"}]
   623    set opts ""
   624    set title ${name}($testtarget)
   625    set configOpts $::WITHTCL
   626    set skip 0
   627  
   628    regsub -all {#[^\n]*\n} $config \n config
   629    foreach arg $config {
   630      if {$skip} {
   631        set skip 0
   632        continue
   633      }
   634      if {[regexp {^-[UD]} $arg]} {
   635        lappend opts $arg
   636      } elseif {[regexp {^[A-Z]+=} $arg]} {
   637        lappend testtarget $arg
   638      } elseif {[regexp {^if:([a-z]+)(.*)} $arg all key tail]} {
   639        # Arguments of the form 'if:os=="Linux"' will cause the subsequent
   640        # argument to be skipped if the $tcl_platform(os) is not "Linux", for
   641        # example...
   642        set skip [expr !(\$::tcl_platform($key)$tail)]
   643      } elseif {[regexp {^--(enable|disable)-} $arg]} {
   644        if {$::MSVC} {
   645          if {$arg eq "--disable-amalgamation"} {
   646            lappend makeOpts USE_AMALGAMATION=0
   647            continue
   648          }
   649          if {$arg eq "--disable-shared"} {
   650            lappend makeOpts USE_CRT_DLL=0 DYNAMIC_SHELL=0
   651            continue
   652          }
   653          if {$arg eq "--enable-fts5"} {
   654            lappend opts -DSQLITE_ENABLE_FTS5
   655            continue
   656          }
   657          if {$arg eq "--enable-json1"} {
   658            lappend opts -DSQLITE_ENABLE_JSON1
   659            continue
   660          }
   661          if {$arg eq "--enable-shared"} {
   662            lappend makeOpts USE_CRT_DLL=1 DYNAMIC_SHELL=1
   663            continue
   664          }
   665        }
   666        lappend configOpts $arg
   667      } else {
   668        if {$::MSVC} {
   669          if {$arg eq "-g"} {
   670            lappend cflags -Zi
   671            continue
   672          }
   673          if {[regexp -- {^-O(\d+)$} $arg all level]} then {
   674            lappend makeOpts OPTIMIZATIONS=$level
   675            continue
   676          }
   677        }
   678        lappend cflags $arg
   679      }
   680    }
   681  
   682    # Disable sync to make testing faster.
   683    #
   684    lappend opts -DSQLITE_NO_SYNC=1
   685  
   686    # Some configurations already set HAVE_USLEEP; in that case, skip it.
   687    #
   688    if {[lsearch -regexp $opts {^-DHAVE_USLEEP(?:=|$)}]==-1} {
   689      lappend opts -DHAVE_USLEEP=1
   690    }
   691  
   692    # Add the define for this platform.
   693    #
   694    if {$::tcl_platform(platform)=="windows"} {
   695      lappend opts -DSQLITE_OS_WIN=1
   696    } else {
   697      lappend opts -DSQLITE_OS_UNIX=1
   698    }
   699  
   700    # Set the sub-directory to use.
   701    #
   702    set dir [string tolower [string map {- _ " " _} $name]]
   703  
   704    # Join option lists into strings, using space as delimiter.
   705    #
   706    set makeOpts [join $makeOpts " "]
   707    set cflags   [join $cflags " "]
   708    set opts     [join $opts " "]
   709  
   710    lappend alltests [list \
   711        $title $dir $configOpts $testtarget $makeOpts $cflags $opts]
   712  }
   713  
   714  # The following procedure returns the "configure" command to be exectued for
   715  # the current platform, which may be Windows (via MinGW, etc).
   716  #
   717  proc configureCommand {opts} {
   718    if {$::MSVC} return [list]; # This is not needed for MSVC.
   719    set result [list trace_cmd exec]
   720    if {$::tcl_platform(platform)=="windows"} {
   721      lappend result sh
   722    }
   723    lappend result $::SRCDIR/configure --enable-load-extension
   724    foreach x $opts {lappend result $x}
   725    lappend result >& test.log
   726  }
   727  
   728  # The following procedure returns the "make" command to be executed for the
   729  # specified targets, compiler flags, and options.
   730  #
   731  proc makeCommand { targets makeOpts cflags opts } {
   732    set result [list trace_cmd exec]
   733    if {$::MSVC} {
   734      set nmakeDir [file nativename $::SRCDIR]
   735      set nmakeFile [file nativename [file join $nmakeDir Makefile.msc]]
   736      lappend result nmake /f $nmakeFile TOP=$nmakeDir
   737      if {[regexp {USE_STDCALL=1} $cflags]} {
   738        lappend result USE_STDCALL=1
   739      }
   740    } else {
   741      lappend result make
   742    }
   743    foreach makeOpt $makeOpts {
   744      lappend result $makeOpt
   745    }
   746    lappend result clean
   747    foreach target $targets {
   748      lappend result $target
   749    }
   750    lappend result CFLAGS=$cflags OPTS=$opts >>& test.log
   751  }
   752  
   753  # The following procedure prints its arguments if ::TRACE is true.
   754  # And it executes the command of its arguments in the calling context
   755  # if ::DRYRUN is false.
   756  #
   757  proc trace_cmd {args} {
   758    if {$::TRACE} {
   759      PUTS $args
   760    }
   761    set res ""
   762    if {!$::DRYRUN} {
   763      set res [uplevel 1 $args]
   764    }
   765    return $res
   766  }
   767  
   768  
   769  # This proc processes the command line options passed to this script.
   770  # Currently the only option supported is "-makefile", default
   771  # "releasetest.mk". Set the ::MAKEFILE variable to the value of this
   772  # option.
   773  #
   774  proc process_options {argv} {
   775    set ::SRCDIR    [file normalize [file dirname [file dirname $::argv0]]]
   776    set ::QUICK          0
   777    set ::MSVC           0
   778    set ::BUILDONLY      0
   779    set ::DRYRUN         0
   780    set ::TRACE          0
   781    set ::JOBS           1
   782    set ::PROGRESS_MSGS  0
   783    set ::WITHTCL        {}
   784    set ::FORCE          0
   785    set ::KEEPFILES      0          ;# Keep extra files after test run
   786    set config {}
   787    set platform $::tcl_platform(os)-$::tcl_platform(machine)
   788  
   789    for {set i 0} {$i < [llength $argv]} {incr i} {
   790      set x [lindex $argv $i]
   791      if {[regexp {^--[a-z]} $x]} {set x [string range $x 1 end]}
   792      switch -glob -- $x {
   793        -slave {
   794          run_slave_test
   795          exit
   796        }
   797  
   798        # Undocumented legacy option: --srcdir DIRECTORY
   799        #
   800        # DIRECTORY is the root of the SQLite checkout.  This sets the
   801        # SRCDIR global variable.  But that variable is already set
   802        # automatically so there really is no reason to have this option.
   803        #
   804        -srcdir {
   805          incr i
   806          set ::SRCDIR [file normalize [lindex $argv $i]]
   807        }
   808  
   809        -platform {
   810          incr i
   811          set platform [lindex $argv $i]
   812        }
   813  
   814        -jobs {
   815          incr i
   816          set ::JOBS [lindex $argv $i]
   817        }
   818  
   819        -progress {
   820          set ::PROGRESS_MSGS 1
   821        }
   822  
   823        -quick {
   824          set ::QUICK 1
   825        }
   826        -veryquick {
   827          set ::QUICK 2
   828        }
   829  
   830        -config {
   831          incr i
   832          set config [lindex $argv $i]
   833        }
   834  
   835        -msvc {
   836          set ::MSVC 1
   837        }
   838  
   839        -buildonly {
   840          set ::BUILDONLY 1
   841        }
   842  
   843        -dryrun {
   844          set ::DRYRUN 1
   845        }
   846  
   847        -force -
   848        -f {
   849          set ::FORCE 1
   850        }
   851  
   852        -trace {
   853          set ::TRACE 1
   854        }
   855  
   856        -info {
   857          PUTS "Command-line Options:"
   858          PUTS "   --srcdir $::SRCDIR"
   859          PUTS "   --platform [list $platform]"
   860          PUTS "   --config [list $config]"
   861          if {$::QUICK} {
   862            if {$::QUICK==1} {PUTS "   --quick"}
   863            if {$::QUICK==2} {PUTS "   --veryquick"}
   864          }
   865          if {$::MSVC}      {PUTS "   --msvc"}
   866          if {$::BUILDONLY} {PUTS "   --buildonly"}
   867          if {$::DRYRUN}    {PUTS "   --dryrun"}
   868          if {$::TRACE}     {PUTS "   --trace"}
   869          PUTS "\nAvailable --platform options:"
   870          foreach y [lsort [array names ::Platforms]] {
   871            PUTS "   [list $y]"
   872          }
   873          PUTS "\nAvailable --config options:"
   874          foreach y [lsort [array names ::Configs]] {
   875            PUTS "   [list $y]"
   876          }
   877          exit
   878        }
   879  
   880        -g {
   881          lappend ::EXTRACONFIG [lindex $argv $i]
   882        }
   883  
   884        -keep {
   885          set ::KEEPFILES 1
   886        }
   887  
   888        -with-tcl=* {
   889          set ::WITHTCL -$x
   890        }
   891  
   892        -D* -
   893        -O* -
   894        -enable-* -
   895        -disable-* -
   896        *=* {
   897          lappend ::EXTRACONFIG [lindex $argv $i]
   898        }
   899  
   900        default {
   901          PUTSERR ""
   902          PUTSERR [string trim $::USAGE_MESSAGE]
   903          exit -1
   904        }
   905      }
   906    }
   907  
   908    if {0==[info exists ::Platforms($platform)]} {
   909      PUTS "Unknown platform: $platform"
   910      PUTSNNL "Set the -platform option to "
   911      set print [list]
   912      foreach p [array names ::Platforms] {
   913        lappend print "\"$p\""
   914      }
   915      lset print end "or [lindex $print end]"
   916      PUTS "[join $print {, }]."
   917      exit
   918    }
   919  
   920    if {$config!=""} {
   921      if {[llength $config]==1} {lappend config fulltest}
   922      set ::CONFIGLIST $config
   923    } else {
   924      if {$::JOBS>1} {
   925        set ::CONFIGLIST {}
   926        foreach {target zConfig} [lreverse $::Platforms($platform)] {
   927          append ::CONFIGLIST [format "    %-25s %s\n" \
   928                                 [list $zConfig] [list $target]]
   929        }
   930      } else {
   931        set ::CONFIGLIST $::Platforms($platform)
   932      }
   933    }
   934    PUTS "Running the following test configurations for $platform:"
   935    PUTS "    [string trim $::CONFIGLIST]"
   936    PUTSNNL "Flags:"
   937    if {$::PROGRESS_MSGS} {PUTSNNL " --progress"}
   938    if {$::DRYRUN} {PUTSNNL " --dryrun"}
   939    if {$::BUILDONLY} {PUTSNNL " --buildonly"}
   940    if {$::MSVC} {PUTSNNL " --msvc"}
   941    switch -- $::QUICK {
   942       1 {PUTSNNL " --quick"}
   943       2 {PUTSNNL " --veryquick"}
   944    }
   945    if {$::JOBS>1} {PUTSNNL " --jobs $::JOBS"}
   946    PUTS ""
   947  }
   948  
   949  # Check to see if there are uncommitted changes in the SQLite source
   950  # checkout.  Exit if there are.  Except:  Do nothing if the --force
   951  # flag is used.  Also, ignore this test if the fossil binary is
   952  # unavailable, or if the source tree is not a valid fossil checkout.
   953  #
   954  proc check_uncommitted {} {
   955    if {$::FORCE} return
   956    set pwd [pwd]
   957    cd $::SRCDIR
   958    if {[catch {exec fossil changes} res]==0 && [string trim $res]!=""} {
   959      puts "ERROR: The check-out contains uncommitted changes:"
   960      puts $res
   961      puts "Use the -f or --force options to override"
   962      exit 1
   963    }
   964    cd $pwd
   965  }
   966  
   967  # A test run has just finished in directory $dir. This command deletes all
   968  # non-essential files from the directory. Specifically, everything except
   969  #
   970  #   * The "testfixture" and "sqlite3" binaries,
   971  #   * The "test-out.log" and "test.log" log files.
   972  #
   973  proc cleanup {dir} {
   974    set K(testfixture) 1
   975    set K(testfixture.exe) 1
   976    set K(sqlite3) 1
   977    set K(sqlite3.exe) 1
   978    set K(test-out.txt) 1
   979    set K(test.log) 1
   980  
   981    foreach f [glob -nocomplain [file join $dir *]] {
   982      set tail [file tail $f]
   983      if {[info exists K($tail)]==0} { 
   984        file delete -force $f
   985      }
   986    }
   987  }
   988  
   989  
   990  # Main routine.
   991  #
   992  proc main {argv} {
   993  
   994    # Process any command line options.
   995    set ::EXTRACONFIG {}
   996    process_options $argv
   997    if {!$::DRYRUN} check_uncommitted
   998    PUTS [string repeat * 79]
   999  
  1000    set ::NERR 0
  1001    set ::NTEST 0
  1002    set ::NTESTCASE 0
  1003    set ::NERRCASE 0
  1004    set ::SQLITE_VERSION {}
  1005    set STARTTIME [clock seconds]
  1006    foreach {zConfig target} $::CONFIGLIST {
  1007      if {$::MSVC && ($zConfig eq "Sanitize" || "checksymbols" in $target
  1008             || "valgrindtest" in $target)} {
  1009        PUTS "Skipping $zConfig / $target for MSVC..."
  1010        continue
  1011      }
  1012      if {$target ne "checksymbols"} {
  1013        switch -- $::QUICK {
  1014           1 {set target quicktest}
  1015           2 {set target smoketest}
  1016        }
  1017        if {$::BUILDONLY} {
  1018          set target testfixture
  1019          if {$::tcl_platform(platform)=="windows"} {
  1020            append target .exe
  1021          }
  1022        }
  1023      }
  1024      set config_options [concat $::Configs($zConfig) $::EXTRACONFIG]
  1025  
  1026      incr NTEST
  1027      add_test_suite all $zConfig $target $config_options
  1028  
  1029      # If the configuration included the SQLITE_DEBUG option, then remove
  1030      # it and run veryquick.test. If it did not include the SQLITE_DEBUG option
  1031      # add it and run veryquick.test.
  1032      if {$target!="checksymbols" && $target!="valgrindtest"
  1033             && $target!="fuzzoomtest" && !$::BUILDONLY && $::QUICK<2} {
  1034        set debug_idx [lsearch -glob $config_options -DSQLITE_DEBUG*]
  1035        set xtarget $target
  1036        regsub -all {fulltest[a-z]*} $xtarget test xtarget
  1037        regsub -all {fuzzoomtest} $xtarget fuzztest xtarget
  1038        if {$debug_idx < 0} {
  1039          incr NTEST
  1040          append config_options " -DSQLITE_DEBUG=1 -DSQLITE_EXTRA_IFNULLROW=1"
  1041          add_test_suite all "${zConfig}_debug" $xtarget $config_options
  1042        } else {
  1043          incr NTEST
  1044          regsub { *-DSQLITE_MEMDEBUG[^ ]* *} $config_options { } config_options
  1045          regsub { *-DSQLITE_DEBUG[^ ]* *} $config_options { } config_options
  1046          add_test_suite all "${zConfig}_ndebug" $xtarget $config_options
  1047        }
  1048      }
  1049    }
  1050  
  1051    run_all_test_suites $all
  1052  
  1053    set elapsetime [expr {[clock seconds]-$STARTTIME}]
  1054    set hr [expr {$elapsetime/3600}]
  1055    set min [expr {($elapsetime/60)%60}]
  1056    set sec [expr {$elapsetime%60}]
  1057    set etime [format (%02d:%02d:%02d) $hr $min $sec]
  1058    if {$::JOBS>1} {append etime " $::JOBS cores"}
  1059    if {[catch {exec hostname} HNAME]==0} {append etime " on $HNAME"}
  1060    PUTS [string repeat * 79]
  1061    incr ::NERRCASE $::NERR
  1062    PUTS "$::NERRCASE failures out of $::NTESTCASE tests in $etime"
  1063    if {$::SQLITE_VERSION ne ""} {
  1064      PUTS "SQLite $::SQLITE_VERSION"
  1065    }
  1066  }
  1067  
  1068  main $argv