xref: /sqlite-3.40.0/test/wapptest.tcl (revision 5f7e173a)
1#!/bin/sh
2# \
3exec wapptclsh "$0" ${1+"$@"}
4
5# package required wapp
6source [file join [file dirname [info script]] wapp.tcl]
7
8# Variables set by the "control" form:
9#
10#   G(platform) - User selected platform.
11#   G(cfgglob)  - Glob pattern that all configurations must match
12#   G(test)     - Set to "Normal", "Veryquick", "Smoketest" or "Build-Only".
13#   G(keep)     - Boolean. True to delete no files after each test.
14#   G(msvc)     - Boolean. True to use MSVC as the compiler.
15#   G(tcl)      - Use Tcl from this directory for builds.
16#   G(jobs)     - How many sub-processes to run simultaneously.
17#
18set G(platform) $::tcl_platform(os)-$::tcl_platform(machine)
19set G(cfgglob)  *
20set G(test)     Normal
21set G(keep)     1
22set G(msvc)     0
23set G(tcl)      [::tcl::pkgconfig get libdir,install]
24set G(jobs)     3
25set G(debug)    0
26
27set G(noui)     0
28set G(stdout)   0
29
30
31proc wapptest_init {} {
32  global G
33
34  set lSave [list platform test keep msvc tcl jobs debug noui stdout cfgglob]
35  foreach k $lSave { set A($k) $G($k) }
36  array unset G
37  foreach k $lSave { set G($k) $A($k) }
38
39  # The root of the SQLite source tree.
40  set G(srcdir)   [file dirname [file dirname [info script]]]
41
42  set G(sqlite_version) "unknown"
43
44  # Either "config", "running" or "stopped":
45  set G(state) "config"
46
47  set G(hostname) "(unknown host)"
48  catch { set G(hostname) [exec hostname] }
49  set G(host) $G(hostname)
50  append G(host) " $::tcl_platform(os) $::tcl_platform(osVersion)"
51  append G(host) " $::tcl_platform(machine) $::tcl_platform(byteOrder)"
52}
53
54proc wapptest_run {} {
55  global G
56  set_test_array
57  set G(state) "running"
58
59  wapptest_openlog
60
61  wapptest_output "Running the following for $G(platform). $G(jobs) jobs."
62  foreach t $G(test_array) {
63    set config [dict get $t config]
64    set target [dict get $t target]
65    wapptest_output [format "    %-25s%s" $config $target]
66  }
67  wapptest_output [string repeat * 70]
68}
69
70proc releasetest_data {args} {
71  global G
72  set rtd [file join $G(srcdir) test releasetest_data.tcl]
73  set fd [open "|[info nameofexecutable] $rtd $args" r+]
74  set ret [read $fd]
75  close $fd
76  return $ret
77}
78
79# Generate the text for the box at the top of the UI. The current SQLite
80# version, according to fossil, along with a warning if there are
81# uncommitted changes in the checkout.
82#
83proc generate_fossil_info {} {
84  global G
85  set pwd [pwd]
86  cd $G(srcdir)
87  set rc [catch {
88    set r1 [exec fossil info]
89    set r2 [exec fossil changes]
90  }]
91  cd $pwd
92  if {$rc} return
93
94  foreach line [split $r1 "\n"] {
95    if {[regexp {^checkout: *(.*)$} $line -> co]} {
96      wapp-trim { <br> %html($co) }
97    }
98  }
99
100  if {[string trim $r2]!=""} {
101    wapp-trim {
102      <br><span class=warning>
103      WARNING: Uncommitted changes in checkout
104      </span>
105    }
106  }
107}
108
109# If the application is in "config" state, set the contents of the
110# ::G(test_array) global to reflect the tests that will be run. If the
111# app is in some other state ("running" or "stopped"), this command
112# is a no-op.
113#
114proc set_test_array {} {
115  global G
116  if { $G(state)=="config" } {
117    set G(test_array) [list]
118    set debug "-debug"
119    if {$G(debug)==0} { set debug "-nodebug"}
120    foreach {config target} [releasetest_data tests $debug $G(platform)] {
121
122      # All configuration names must match $g(cfgglob), which defaults to *
123      #
124      if {![string match -nocase $G(cfgglob) $config]} continue
125
126      # If using MSVC, do not run sanitize or valgrind tests. Or the
127      # checksymbols test.
128      if {$G(msvc) && (
129          "Sanitize" == $config
130       || "checksymbols" in $target
131       || "valgrindtest" in $target
132      )} {
133        continue
134      }
135
136      # If the test mode is not "Normal", override the target.
137      #
138      if {$target!="checksymbols" && $G(platform)!="Failure-Detection"} {
139        switch -- $G(test) {
140          Veryquick { set target quicktest }
141          Smoketest { set target smoketest }
142          Build-Only {
143            set target testfixture
144            if {$::tcl_platform(platform)=="windows"} {
145              set target testfixture.exe
146            }
147          }
148        }
149      }
150
151      lappend G(test_array) [dict create config $config target $target]
152    }
153  }
154}
155
156proc count_tests_and_errors {name logfile} {
157  global G
158
159  set fd [open $logfile rb]
160  set seen 0
161  while {![eof $fd]} {
162    set line [gets $fd]
163    if {[regexp {(\d+) errors out of (\d+) tests} $line all nerr ntest]} {
164      incr G(test.$name.nError) $nerr
165      incr G(test.$name.nTest) $ntest
166      set seen 1
167      if {$nerr>0} {
168        set G(test.$name.errmsg) $line
169      }
170    }
171    if {[regexp {runtime error: +(.*)} $line all msg]} {
172      # skip over "value is outside range" errors
173      if {[regexp {.* is outside the range of representable} $line]} {
174         # noop
175      } else {
176        incr G(test.$name.nError)
177        if {$G(test.$name.errmsg)==""} {
178          set G(test.$name.errmsg) $msg
179        }
180      }
181    }
182    if {[regexp {fatal error +(.*)} $line all msg]} {
183      incr G(test.$name.nError)
184      if {$G(test.$name.errmsg)==""} {
185        set G(test.$name.errmsg) $msg
186      }
187    }
188    if {[regexp {ERROR SUMMARY: (\d+) errors.*} $line all cnt] && $cnt>0} {
189      incr G(test.$name.nError)
190      if {$G(test.$name.errmsg)==""} {
191        set G(test.$name.errmsg) $all
192      }
193    }
194    if {[regexp {^VERSION: 3\.\d+.\d+} $line]} {
195      set v [string range $line 9 end]
196      if {$G(sqlite_version) eq "unknown"} {
197        set G(sqlite_version) $v
198      } elseif {$G(sqlite_version) ne $v} {
199        set G(test.$name.errmsg) "version conflict: {$G(sqlite_version)} vs. {$v}"
200      }
201    }
202  }
203  close $fd
204  if {$G(test) == "Build-Only"} {
205    incr G(test.$name.nTest)
206    if {$G(test.$name.nError)>0} {
207      set errmsg "Build failed"
208    }
209  } elseif {!$seen} {
210    set G(test.$name.errmsg) "Test did not complete"
211    if {[file readable core]} {
212      append G(test.$name.errmsg) " - core file exists"
213    }
214  }
215}
216
217proc wapptest_output {str} {
218  global G
219  if {$G(stdout)} { puts $str }
220  if {[info exists G(log)]} {
221    puts $G(log) $str
222    flush $G(log)
223  }
224}
225proc wapptest_openlog {} {
226  global G
227  set G(log) [open wapptest-out.txt w+]
228}
229proc wapptest_closelog {} {
230  global G
231  close $G(log)
232  unset G(log)
233}
234
235proc format_seconds {seconds} {
236  set min [format %.2d [expr ($seconds / 60) % 60]]
237  set  hr [format %.2d [expr $seconds / 3600]]
238  set sec [format %.2d [expr $seconds % 60]]
239  return "$hr:$min:$sec"
240}
241
242# This command is invoked once a slave process has finished running its
243# tests, successfully or otherwise. Parameter $name is the name of the
244# test, $rc the exit code returned by the slave process.
245#
246proc slave_test_done {name rc} {
247  global G
248  set G(test.$name.done) [clock seconds]
249  set G(test.$name.nError) 0
250  set G(test.$name.nTest) 0
251  set G(test.$name.errmsg) ""
252  if {$rc} {
253    incr G(test.$name.nError)
254  }
255  if {[file exists $G(test.$name.log)]} {
256    count_tests_and_errors $name $G(test.$name.log)
257  }
258
259  # If the "keep files" checkbox is clear, delete all files except for
260  # the executables and test logs. And any core file that is present.
261  if {$G(keep)==0} {
262    set keeplist {
263      testfixture testfixture.exe
264      sqlite3 sqlite3.exe
265      test.log test-out.txt
266      core
267      wapptest_make.sh
268      wapptest_configure.sh
269      wapptest_run.tcl
270    }
271    foreach f [glob -nocomplain [file join $G(test.$name.dir) *]] {
272      set t [file tail $f]
273      if {[lsearch $keeplist $t]<0} {
274        catch { file delete -force $f }
275      }
276    }
277  }
278
279  # Format a message regarding the success or failure of hte test.
280  set t [format_seconds [expr $G(test.$name.done) - $G(test.$name.start)]]
281  set res "OK"
282  if {$G(test.$name.nError)} { set res "FAILED" }
283  set dots [string repeat . [expr 60 - [string length $name]]]
284  set msg "$name $dots $res ($t)"
285
286  wapptest_output $msg
287  if {[info exists G(test.$name.errmsg)] && $G(test.$name.errmsg)!=""} {
288    wapptest_output "    $G(test.$name.errmsg)"
289  }
290}
291
292# This is a fileevent callback invoked each time a file-descriptor that
293# connects this process to a slave process is readable.
294#
295proc slave_fileevent {name} {
296  global G
297  set fd $G(test.$name.channel)
298
299  if {[eof $fd]} {
300    fconfigure $fd -blocking 1
301    set rc [catch { close $fd }]
302    unset G(test.$name.channel)
303    slave_test_done $name $rc
304  } else {
305    set line [gets $fd]
306    if {[string trim $line] != ""} { puts "Trace   : $name - \"$line\"" }
307  }
308
309  do_some_stuff
310}
311
312# Return the contents of the "slave script" - the script run by slave
313# processes to actually perform the test. All it does is execute the
314# test script already written to disk (wapptest_cmd.sh or wapptest_cmd.bat).
315#
316proc wapptest_slave_script {} {
317  global G
318  if {$G(msvc)==0} {
319    set dir [file join .. $G(srcdir)]
320    set res [subst -nocommands {
321      set rc [catch "exec sh wapptest_cmd.sh {$dir} >>& test.log" ]
322      exit [set rc]
323    }]
324  } else {
325    set dir [file nativename [file normalize $G(srcdir)]]
326    set dir [string map [list "\\" "\\\\"] $dir]
327    set res [subst -nocommands {
328      set rc [catch "exec wapptest_cmd.bat {$dir} >>& test.log" ]
329      exit [set rc]
330    }]
331  }
332
333  set res
334}
335
336
337# Launch a slave process to run a test.
338#
339proc slave_launch {name target dir} {
340  global G
341
342  catch { file mkdir $dir } msg
343  foreach f [glob -nocomplain [file join $dir *]] {
344    catch { file delete -force $f }
345  }
346  set G(test.$name.dir) $dir
347
348  # Write the test command to wapptest_cmd.sh|bat.
349  #
350  set ext sh
351  if {$G(msvc)} { set ext bat }
352  set fd1 [open [file join $dir wapptest_cmd.$ext] w]
353  if {$G(msvc)} {
354    puts $fd1 [releasetest_data script -msvc $name $target]
355  } else {
356    puts $fd1 [releasetest_data script $name $target]
357  }
358  close $fd1
359
360  # Write the wapptest_run.tcl script to the test directory. To run the
361  # commands in the other two files.
362  #
363  set fd3 [open [file join $dir wapptest_run.tcl] w]
364  puts $fd3 [wapptest_slave_script]
365  close $fd3
366
367  set pwd [pwd]
368  cd $dir
369  set fd [open "|[info nameofexecutable] wapptest_run.tcl" r+]
370  cd $pwd
371
372  set G(test.$name.channel) $fd
373  fconfigure $fd -blocking 0
374  fileevent $fd readable [list slave_fileevent $name]
375}
376
377proc do_some_stuff {} {
378  global G
379
380  # Count the number of running jobs. A running job has an entry named
381  # "channel" in its dictionary.
382  set nRunning 0
383  set bFinished 1
384  foreach j $G(test_array) {
385    set name [dict get $j config]
386    if { [info exists G(test.$name.channel)]} { incr nRunning   }
387    if {![info exists G(test.$name.done)]}    { set bFinished 0 }
388  }
389
390  if {$bFinished} {
391    set nError 0
392    set nTest 0
393    set nConfig 0
394    foreach j $G(test_array) {
395      set name [dict get $j config]
396      incr nError $G(test.$name.nError)
397      incr nTest $G(test.$name.nTest)
398      incr nConfig
399    }
400    set G(result) "$nError errors from $nTest tests in $nConfig configurations."
401    wapptest_output [string repeat * 70]
402    wapptest_output $G(result)
403    catch {
404      append G(result) " SQLite version $G(sqlite_version)"
405      wapptest_output " SQLite version $G(sqlite_version)"
406    }
407    set G(state) "stopped"
408    wapptest_closelog
409    if {$G(noui)} { exit 0 }
410  } else {
411    set nLaunch [expr $G(jobs) - $nRunning]
412    foreach j $G(test_array) {
413      if {$nLaunch<=0} break
414      set name [dict get $j config]
415      if { ![info exists G(test.$name.channel)]
416        && ![info exists G(test.$name.done)]
417      } {
418
419        set target [dict get $j target]
420        set dir [string tolower [string map {" " _ "-" _} $name]]
421        set G(test.$name.start) [clock seconds]
422        set G(test.$name.log) [file join $dir test.log]
423
424        slave_launch $name $target $dir
425
426        incr nLaunch -1
427      }
428    }
429  }
430}
431
432proc generate_select_widget {label id lOpt opt} {
433  wapp-trim {
434    <label> %string($label) </label>
435    <select id=%string($id) name=%string($id)>
436  }
437  foreach o $lOpt {
438    set selected ""
439    if {$o==$opt} { set selected " selected=1" }
440    wapp-subst "<option $selected>$o</option>"
441  }
442  wapp-trim { </select> }
443}
444
445proc generate_main_page {{extra {}}} {
446  global G
447  set_test_array
448
449  set hostname $G(hostname)
450  wapp-trim {
451    <html>
452    <head>
453      <title> %html($hostname): wapptest.tcl </title>
454      <link rel="stylesheet" type="text/css" href="style.css"/>
455    </head>
456    <body>
457  }
458
459  set host $G(host)
460  wapp-trim {
461    <div class="border">%string($host)
462  }
463  generate_fossil_info
464  wapp-trim {
465    </div>
466    <div class="border" id=controls>
467    <form action="control" method="post" name="control">
468  }
469
470  # Build the "platform" select widget.
471  set lOpt [releasetest_data platforms]
472  generate_select_widget Platform control_platform $lOpt $G(platform)
473
474  # Build the "test" select widget.
475  set lOpt [list Normal Veryquick Smoketest Build-Only]
476  generate_select_widget Test control_test $lOpt $G(test)
477
478  # Build the "jobs" select widget. Options are 1 to 8.
479  generate_select_widget Jobs control_jobs {1 2 3 4 5 6 7 8 12 16} $G(jobs)
480
481  switch $G(state) {
482    config {
483      set txt "Run Tests!"
484      set id control_run
485    }
486    running {
487      set txt "STOP Tests!"
488      set id control_stop
489    }
490    stopped {
491      set txt "Reset!"
492      set id control_reset
493    }
494  }
495  wapp-trim {
496    <div class=right>
497    <input id=%string($id) name=%string($id) type=submit value="%string($txt)">
498    </input>
499    </div>
500  }
501
502  wapp-trim {
503  <br><br>
504        <label> Tcl: </label>
505        <input id="control_tcl" name="control_tcl"></input>
506        <label> Keep files: </label>
507        <input id="control_keep" name="control_keep" type=checkbox value=1>
508        </input>
509        <label> Use MSVC: </label>
510        <input id="control_msvc" name="control_msvc" type=checkbox value=1>
511        <label> Debug tests: </label>
512        <input id="control_debug" name="control_debug" type=checkbox value=1>
513        </input>
514  }
515  wapp-trim {
516     </form>
517  }
518  wapp-trim {
519     </div>
520     <div id=tests>
521  }
522  wapp-page-tests
523
524  set script "script/$G(state).js"
525  wapp-trim {
526    </div>
527      <script src=%string($script)></script>
528    </body>
529    </html>
530  }
531}
532
533proc wapp-default {} {
534  generate_main_page
535}
536
537proc wapp-page-tests {} {
538  global G
539  wapp-trim { <table class="border" width=100%> }
540  foreach t $G(test_array) {
541    set config [dict get $t config]
542    set target [dict get $t target]
543
544    set class "testwait"
545    set seconds ""
546
547    if {[info exists G(test.$config.log)]} {
548      if {[info exists G(test.$config.channel)]} {
549        set class "testrunning"
550        set seconds [expr [clock seconds] - $G(test.$config.start)]
551      } elseif {[info exists G(test.$config.done)]} {
552        if {$G(test.$config.nError)>0} {
553          set class "testfail"
554        } else {
555          set class "testdone"
556        }
557        set seconds [expr $G(test.$config.done) - $G(test.$config.start)]
558      }
559      set seconds [format_seconds $seconds]
560    }
561
562    wapp-trim {
563      <tr class=%string($class)>
564      <td class="nowrap"> %html($config)
565      <td class="padleft nowrap"> %html($target)
566      <td class="padleft nowrap"> %html($seconds)
567      <td class="padleft nowrap">
568    }
569    if {[info exists G(test.$config.log)]} {
570      set log $G(test.$config.log)
571      set uri "log/$log"
572      wapp-trim {
573        <a href=%url($uri)> %html($log) </a>
574      }
575    }
576    if {[info exists G(test.$config.errmsg)] && $G(test.$config.errmsg)!=""} {
577      set errmsg $G(test.$config.errmsg)
578      wapp-trim {
579        <tr class=testfail>
580        <td> <td class="padleft" colspan=3> %html($errmsg)
581      }
582    }
583  }
584
585  wapp-trim { </table> }
586
587  if {[info exists G(result)]} {
588    set res $G(result)
589    wapp-trim {
590      <div class=border id=result> %string($res) </div>
591    }
592  }
593}
594
595# URI: /control
596#
597# Whenever the form at the top of the application page is submitted, it
598# is submitted here.
599#
600proc wapp-page-control {} {
601  global G
602  if {$::G(state)=="config"} {
603    set lControls [list platform test tcl jobs keep msvc debug]
604    set G(msvc) 0
605    set G(keep) 0
606    set G(debug) 0
607  } else {
608    set lControls [list jobs]
609  }
610  foreach v $lControls {
611    if {[wapp-param-exists control_$v]} {
612      set G($v) [wapp-param control_$v]
613    }
614  }
615
616  if {[wapp-param-exists control_run]} {
617    # This is a "run test" command.
618    wapptest_run
619  }
620
621  if {[wapp-param-exists control_stop]} {
622    # A "STOP tests" command.
623    set G(state) "stopped"
624    set G(result) "Test halted by user"
625    foreach j $G(test_array) {
626      set name [dict get $j config]
627      if { [info exists G(test.$name.channel)] } {
628        close $G(test.$name.channel)
629        unset G(test.$name.channel)
630        slave_test_done $name 1
631      }
632    }
633    wapptest_closelog
634  }
635
636  if {[wapp-param-exists control_reset]} {
637    # A "reset app" command.
638    set G(state) "config"
639    wapptest_init
640  }
641
642  if {$::G(state) == "running"} {
643    do_some_stuff
644  }
645  wapp-redirect /
646}
647
648# URI: /style.css
649#
650# Return the stylesheet for the application main page.
651#
652proc wapp-page-style.css {} {
653  wapp-subst {
654
655    /* The boxes with black borders use this class */
656    .border {
657      border: 3px groove #444444;
658      padding: 1em;
659      margin-top: 1em;
660      margin-bottom: 1em;
661    }
662
663    /* Float to the right (used for the Run/Stop/Reset button) */
664    .right { float: right; }
665
666    /* Style for the large red warning at the top of the page */
667    .warning {
668      color: red;
669      font-weight: bold;
670    }
671
672    /* Styles used by cells in the test table */
673    .padleft { padding-left: 5ex; }
674    .nowrap  { white-space: nowrap; }
675
676    /* Styles for individual tests, depending on the outcome */
677    .testwait    {              }
678    .testrunning { color: blue  }
679    .testdone    { color: green }
680    .testfail    { color: red   }
681  }
682}
683
684# URI: /script/${state}.js
685#
686# The last part of this URI is always "config.js", "running.js" or
687# "stopped.js", depending on the state of the application. It returns
688# the javascript part of the front-end for the requested state to the
689# browser.
690#
691proc wapp-page-script {} {
692  regexp {[^/]*$} [wapp-param REQUEST_URI] script
693
694  set tcl $::G(tcl)
695  set keep $::G(keep)
696  set msvc $::G(msvc)
697  set debug $::G(debug)
698
699  wapp-subst {
700    var lElem = \["control_platform", "control_test", "control_msvc",
701        "control_jobs", "control_debug"
702    \];
703    lElem.forEach(function(e) {
704      var elem = document.getElementById(e);
705      elem.addEventListener("change", function() { control.submit() } );
706    })
707
708    elem = document.getElementById("control_tcl");
709    elem.value = "%string($tcl)"
710
711    elem = document.getElementById("control_keep");
712    elem.checked = %string($keep);
713
714    elem = document.getElementById("control_msvc");
715    elem.checked = %string($msvc);
716
717    elem = document.getElementById("control_debug");
718    elem.checked = %string($debug);
719  }
720
721  if {$script != "config.js"} {
722    wapp-subst {
723      var lElem = \["control_platform", "control_test",
724          "control_tcl", "control_keep", "control_msvc",
725          "control_debug"
726      \];
727      lElem.forEach(function(e) {
728        var elem = document.getElementById(e);
729        elem.disabled = true;
730      })
731    }
732  }
733
734  if {$script == "running.js"} {
735    wapp-subst {
736      function reload_tests() {
737        fetch('tests')
738          .then( data => data.text() )
739          .then( data => {
740            document.getElementById("tests").innerHTML = data;
741          })
742          .then( data => {
743            if( document.getElementById("result") ){
744              document.location = document.location;
745            } else {
746              setTimeout(reload_tests, 1000)
747            }
748          });
749      }
750
751      setTimeout(reload_tests, 1000)
752    }
753  }
754}
755
756# URI: /env
757#
758# This is for debugging only. Serves no other purpose.
759#
760proc wapp-page-env {} {
761  wapp-allow-xorigin-params
762  wapp-trim {
763    <h1>Wapp Environment</h1>\n<pre>
764    <pre>%html([wapp-debug-env])</pre>
765  }
766}
767
768# URI: /log/dirname/test.log
769#
770# This URI reads file "dirname/test.log" from disk, wraps it in a <pre>
771# block, and returns it to the browser. Use for viewing log files.
772#
773proc wapp-page-log {} {
774  set log [string range [wapp-param REQUEST_URI] 5 end]
775  set fd [open $log]
776  set data [read $fd]
777  close $fd
778  wapp-trim {
779    <pre>
780    %html($data)
781    </pre>
782  }
783}
784
785# Print out a usage message. Then do [exit 1].
786#
787proc wapptest_usage {} {
788  puts stderr {
789This Tcl script is used to test various configurations of SQLite. By
790default it uses "wapp" to provide an interactive interface. Supported
791command line options (all optional) are:
792
793    --platform    PLATFORM         (which tests to run)
794    --config      GLOB             (only run configurations matching GLOB)
795    --smoketest                    (run "make smoketest" only)
796    --veryquick                    (run veryquick.test only)
797    --buildonly                    (build executables, do not run tests)
798    --jobs        N                (number of concurrent jobs)
799    --tcl         DIR              (where to find tclConfig.sh)
800    --deletefiles                  (delete extra files after each test)
801    --msvc                         (Use MS Visual C)
802    --debug                        (Also run [n]debugging versions of tests)
803    --noui                         (do not use wapp)
804  }
805  exit 1
806}
807
808# Sort command line arguments into two groups: those that belong to wapp,
809# and those that belong to the application.
810set WAPPARG(-server)      1
811set WAPPARG(-local)       1
812set WAPPARG(-scgi)        1
813set WAPPARG(-remote-scgi) 1
814set WAPPARG(-fromip)      1
815set WAPPARG(-nowait)      0
816set WAPPARG(-cgi)         0
817set lWappArg [list]
818set lTestArg [list]
819for {set i 0} {$i < [llength $argv]} {incr i} {
820  set arg [lindex $argv $i]
821  if {[string range $arg 0 1]=="--"} {
822    set arg [string range $arg 1 end]
823  }
824  if {[info exists WAPPARG($arg)]} {
825    lappend lWappArg $arg
826    if {$WAPPARG($arg)} {
827      incr i
828      lappend lWappArg [lindex $argv $i]
829    }
830  } else {
831    lappend lTestArg $arg
832  }
833}
834
835wapptest_init
836for {set i 0} {$i < [llength $lTestArg]} {incr i} {
837  set opt [lindex $lTestArg $i]
838  if {[string range $opt 0 1]=="--"} {
839    set opt [string range $opt 1 end]
840  }
841  switch -- $opt {
842    -platform {
843      if {$i==[llength $lTestArg]-1} { wapptest_usage }
844      incr i
845      set arg [lindex $lTestArg $i]
846      set lPlatform [releasetest_data platforms]
847      if {[lsearch $lPlatform $arg]<0} {
848        puts stderr "No such platform: $arg. Platforms are: $lPlatform"
849        exit -1
850      }
851      set G(platform) $arg
852    }
853
854    -smoketest { set G(test) Smoketest }
855    -veryquick { set G(test) Veryquick }
856    -buildonly { set G(test) Build-Only }
857    -jobs {
858      if {$i==[llength $lTestArg]-1} { wapptest_usage }
859      incr i
860      set G(jobs) [lindex $lTestArg $i]
861    }
862
863    -tcl {
864      if {$i==[llength $lTestArg]-1} { wapptest_usage }
865      incr i
866      set G(tcl) [lindex $lTestArg $i]
867    }
868
869    -deletefiles {
870      set G(keep) 0
871    }
872
873    -msvc {
874      set G(msvc) 1
875    }
876
877    -debug {
878      set G(debug) 1
879    }
880
881    -noui {
882      set G(noui) 1
883      set G(stdout) 1
884    }
885
886    -config {
887      if {$i==[llength $lTestArg]-1} { wapptest_usage }
888      incr i
889      set G(cfgglob) [lindex $lTestArg $i]
890    }
891
892    -stdout {
893      set G(stdout) 1
894    }
895
896    default {
897      puts stderr "Unrecognized option: [lindex $lTestArg $i]"
898      wapptest_usage
899    }
900  }
901}
902
903if {$G(noui)==0} {
904  wapp-start $lWappArg
905} else {
906  wapptest_run
907  do_some_stuff
908  vwait forever
909}
910