blob: b70488647b44ebcc0555fccf81273c711a49e7c7 [file] [log] [blame]
The Insight Testsuite
---------------------
Keith Seitz (keiths@cygnus.com)
May 1, 2001
RUNNING THE TESTSUITE
The Insight testsuite is run in much the same way that gdb's testsuites
are run. The one big difference is the environment variable GDB_DISPLAY,
which governs what display should be used for the tests.
When GDB_DISPLAY is not set in the user's environment, the Insight testsuite
will attempt to run Xvfb, an X server with a virtual frame buffer. Using
Xvfb, the testsuite can run without interuppting the user.
When Xvfb is not available, the testsuite will mark the Insight tests
"untested" and print out some appropriate warning to the testsuite log
file.
If GDB_DISPLAY is set in the user's environment, the testsuite will attempt
to use this display for the tests. If this display is a desktop display,
it is very likely that any interaction between the user and his desktop
will interfere with the tests. Some tests warp the cursor, i.e., they
force the mouse to move on the screen. If you don't want this to happen to
you, put Xvfb in your path.
On Cygwin systems, Xvfb is not supported. Only two choices are available in
this environment: run the testsuites using the desktop or do not run the
testsuite. To run the testsuite on Cygwin, just define the environment
variable GDB_DISPLAY to anything.
The examples below summarize the usage of the environment variable GDB_DISPLAY
on unix/X-Windows hosts and Cygwin hosts. In all examples, assume that DISPLAY
set to the local workstation's main display (:0).
To run the testsuite using Xvfb -- unix only (Xvfb must be in PATH):
$ make check
To run the testsuite using a given display (either the desktop or a peviously
started Xvfb):
$ GDB_DISPLAY=$DISPLAY make check
To run the testsuite on Cygwin:
$ GDB_DISPLAY=foo make check
TESTSUITE INFRASTRUCTURE
The rest of this document deals with writing tests for Insight. This reading
is only noteworthy for developers and contributors.
The Insight testsuite consists of two large portions of code: code which is
run in dejagnu and code which runs in Insight's built-in Tcl interpreter. Files
containing dejagnu code (those files ending in ".exp" in the testsuite directory)
are "glue code" between gdb's dejagnu testsuite and Insight's Tcl testsuite.
Dejagnu testsuite files are considered "drivers" for any particular set of
tests, since they allow dejagnu to control Insight's Tcl testsuite.
Dejagnu Testsuite Infrastructure
The dejagnu code is responsible for doing several things. Some of the more
important responsibilities include:
o Initializing the display
o Determining if tests should be run
o Results accounting
o Compiling testcases in various languages
o Repoting results to gdb's testsuite
There are various functions defined to facilitate the writing of tests. These
functions currently reside in gdb's gdb.exp (src/gdb/testsuite/lib/gdb.exp) and
include:
Pulic functions:
proc gdbtk_initialize_display {}
gdbtk_initialize_display should be the first function called from the
(dejagnu) test file. It initializes the DISPLAY variable on unix systems
and determines (for all host systems) whether or not the testsuite should
run. It returns 1 if the test should run. If tests should not run, it
marks the test as "untested" and leaves a suitable message about why
the test should not run. If gdbtk_initialize_display returns zero, a test
should simply exit.
proc gdbtk_start {test}
This function marks the start of a test and will execute Insight for
testing. The TEST parameter should be the file name of the Tcl test
file to load into Insight's Tcl interpreter. It returns a list of
test results suitable for passing to gdbtk_done or gdbtk_analyze_results.
See gdbtk_analyze_results for more information on the format of results.
gdbtk_start is responsible for communicating target startup information
to Insight, so that Insight's testsuite may be run on any target supported
by gdb. It does this by setting several environment variables just before
it starts Insight. These environment variables are:
OBJDIR
The object directory of the dejagnu testsuite (i.e.,
objdir/gdb/testsuite).
SRCDIR
The dejagnu source directory in which the tests are located (i.e,
src/gdb/testsuite)
SUBDIR
The dejagnu testsuite subdirectory for the test (i.e., gdb.gdbtk)
DEFS
The location of the testsuite definitions file (i.e.,
src/gdb/testsuite/gdb.gdbtk/defs)
Note that DEFS is converted to abs$lute tcl-style paths. On unix,
this means that DEFS would point to, for example,
/home/keiths/insight/src/gdb/testsuite/gdb.gdbtk/defs. On Cygwin it
would point to C:/cygwin/home/keiths/insight/src/gdb/testsuite/gdb.gdbtk/defs.
This is because of a descrepency between Cygwin's posix paths and Tcl's
not-quite-posix paths.
proc gdbtk_analyze_results {results}
This function translates the list of results in RESULTS into dejagnu
results, reporting the number of failures, errors, passes, and expected
failures and passes. It currently does not deal with "untested" and other
test statuses from dejagnu since Insight's tcl testsuite does not
issue such results.
The format of the results expected by gdbtk_analyze_results is simple:
it is a list of {status name description msg}. "status" is the execution
status of one of the tcl tests run. This can be "PASS", "FAIL", "ERROR",
"XFAIL", or "XPASS".
"name" is the name of the test, and it is reported in all testsuite
results in dejagnu. This speeds location of the failing test. This
"name" may also be given to Insight's testsuite, telling it to
only run this test. See "do_tests" in Tcl Testsuite Infrastructure
for more information.
"description" is a textual description of the test given by "name".
"msg" is currently not used.
proc gdbtk_done {{results {}}}
gdbtk_done takes any RESULTS and passes it gdbtk_analyze_results for
outputting to the dejagnu part of the testsuite. It may be called
without an argument, in which case it will only terminate Xvfb if it
was started. Tests must call gdbtk_done _once_ at the end of their
test drivers.
Private functions:
proc _gdbtk_export_target_info
This functin exports information about the target into the environment
so that Insight's testsuite may run programs on any supported gdb
target. This target information is passed into the Tcl testsuite
via an environment variable, TARGET_INFO, which is really a Tcl array,
i.e., the array is constructed in tcl and exported into the environment
with Tcl's "array get" command).
There are four elements to the array:
TARGET_INFO(init) - (optional) A list of commands to execute in gdb
to initialize the session. This usually includes
setting baud rates and remote protocol options.
TARGET_INFO(target) - (required) The complete "target" command to connect
to the given target.
TARGET_INFO(load) - (optional) The complete "load" command to load an
executable into a target.
TARGET_INFO(run) - (required) The complete "run" command, sans arguments,
to start a process on the target. For remote targets,
this is usually just "continue".
proc _gdbtk_xvfb_init
This procedure actually determines whether the an Insight test should
run and what DISPLAY it should use for that test. It is called by
gdbtk_initialize_display to do most of the dirty work.
It has a simple heuristic: If GDB_DISPLAY is not set and Xvfb is available
(on unix), it starts Xvfb, using the current process id as the screen number.
If Xvfb is not available and GDB_DISPLAY was not set, it skips the tests.
proc _gdbtk_xvfb_exit
_gdbtk_xvfb_exit will kill any previously started Xvfb.
Private globals:
global _xvfb_spawn_id
This variable holds the spawn_id of any Xvfb process started
by the testsuite (or it is left undefined).
global _using_windows
A global variable which indicates whether the testsuite is running
on cygwin. Unfortunately, as of writing, the global variable
tcl_platform(platform) is "unix" on Cygwin, so it is not possible
to rely on this for platform-dependent operations.
Instead, this variable is set by gdbtk_initialize_display. The test
it uses to determine if Cygwin is being used: it looks for the program
cygpath in the PATH. Therefore, cygpath is REQUIRED to run the testsuite
on Cygwin. (gdbtk_start also uses cygpath to determine Windows
pathnames for Cygwin.)
Testsuite Driver Basics
Given the above interfaces for connecting Insight's Tcl testsuite and
gdb's dejagnu testsuite, the basic testsuite driver file should look
(minimally) like this:
File: mytest.exp
1 load_lib "insight-support.exp"
2 if {[gdbtk_initialize_display]} {
3 # We found a display to use
4 gdb_exit; # Make sure any previous gdb is gone
5 set results [gdbtk_start mytest.test]
6
7 # Done!
8 gdbtk_done [split $results \n]
9 }
Line 1 loads the insight testsuite support library which contains definitions
for all the procedures used in dejagnu to initialize and run the Insight testsuite.
Line 2 calls gdbtk_initialize_display to ascertain whether there is a display
to use for the test. This could use an existing display (if GDB_DISPLAY is
set in the environment) or gdbk_initialize_display could startup an Xvfb
for use by the testsuite.
Line 4 forces any previously executing gdb to terminate.
Line 5 signals the start of the test run. "mytest.test" is the name of the
Tcl test file to execute in Insight's built-in Tcl interpreter. The output
of gdbtk_start_test is all of the results of the Tcl test from Insight, which
is subsequently passed to gdbk_analyze_results via gdbtk_done on Line 8.
Note how nothing happens if gdbtk_initialize_display returns false.
Tcl Testsuite Infrastructure
The heart of Insight's testsuite is its Tcl testsuite. It is these tests
which run directly in Insight's Tcl interpreter and allow test writers
access to Insight's internals. Tcl testsuite files have the filename suffix
".test" to distinguish them from their driver files, which end in ".exp".
The design of the Insight Tcl testsuite parallels Tcl's testsuite. It has
many powerful features, including the ability to run ANY test in a given
Tcl test file. See the description of utility routines below for more
information about running any set of tests from a file.
The bulk of the code implementing the Tcl testsuite infrastructure in
Insight is contained in the testsuite definitions file, "defs", located
in src/gdb/testsuite/gdb.gdbtk. This file contains routines necessary
to write tests for Insight.
Public functions:
proc gdbtk_read_defs {}
This function, located in Insight's core Tcl library, attempts to load
the testsuite definitions file. If it fails, it will either pop up
a dialog box with the error (if running interactively) or it will
print the error to stderr and exit (if running non-interactively).
If successful, it will return true.
proc gdbtk_test_file {filename}
This function is used to load the file given by FILENAME into
Insight. It will automatically append ".exe" to any FILENAME
on Cygwin-hosted systems.
If successful, it will load the given file into Insight and
return the output of gdb's file command. It will call "error"
if it was succesful, therefore all calls to "gdbtk_test_file"
should be called using "catch".
Test authors should not use "gdb_cmd {file FILENAME}" to load
files into gdb unless they are testing interface code between
gdb and Insight.
proc gdbtk_test_run {{prog_args {}}}
gdbtk_test_run runs the previoiusly loaded executable, passing
the given arguments to the inferior. Like Insight's Run button,
it will do whatever is necessary to get the executable running,
including any target initialization (setting baud rate and remote
protocol options), downloading the executable to the target, and
finally starting execution.
Test authors should NEVER use "gdb_cmd {run ARGUMENTS}" to run an
executable. Doing so will insure that your tests will only run on
a native debugger.
It returns true if successful or false otherwise. It will report
the error in a dialog box (if running interactively) or it will
print the error to stderr.
proc gdbtk_test {name description script answer}
This is Tcl testsuite equivalent of "expect". "name" is a canonical
name of the test, usually of the form "shortname-major.minor". This is
the name that is used when running selected tests from a given file.
If "name" starts with an asterisk (*), it designates that the test
is expected to fail.
"description" is a short textual description of the test to help
humans understand what it does.
"script" is the actual test script to run. The result of this script
will be compared against "answer" to determine if the test passed
or failed.
It calls gdbtk_print_verbose to print out the results to the terminal
(if running interactively) or to the log file.
proc gdbtk_test_done {}
gdbtk_test_done is called at the very end of all tcl tests. It is used
to exit Insight and return control back to the dejagnu driver which
started the tests.
proc gdbtk_dotests {file args}
Obsolete.
proc do_test {{file {}} {verbose {}} {tests {}}}
This procedure is used to invoke the Insight test(s) given in FILE
which match the regular expression(s) in TESTS. This is invoked
from Insight's console window to run tests interactively.
VERBOSE sets the verbosity of the test run. When set to one,
the testsuite will report all results in human readable form.
When set greater than one, it will print out results as a list,
i.e., for passing to gdbtk_analyze_results. If zero, it will only
print errors and failures in human readable form.
Public global variables:
objdir - The objdir from dejagnu. See gdbtk_start for more information.
srcdir - The srcdir from dejagnu. See gdbtk_start for more information.
test_ran - Indicates whether the last test ran or not. See example below.
Private functions:
proc gdbtk_test_error {desc}
An internal function used to report a framework error in the testsuite.
"desc" is a description of the error. It calls gdbtk_test_done.
proc gdbtk_print_verbose {status name description script code answer}
A helper procedure to gdbtk_test which prints out results to the terminal
or the logfile (or both or none).
Private global variables:
_test - An array used by the testsuite internals.
Tcl Test Basics
Armed with the basic interface described above, it is possible to test Insight's
GUI. Please do not write tests which attempt to imitate a user (moving the
mouse and clicking buttons), unless there is no other way to test the functionality.
The basic test file (with one test) looks like this (nonsensical one):
File: mytest.test
1 if {![gdbtk_read_defs]} {
2 break
3 }
4
5 global objdir test_ran
6 set program [file join $objdir mytest]
7 if {[catch {gdbtk_test_file $program} t]} {
8 gdbtk_test_error "loading \"$program\": $t"
9 }
10 if {![gdbtk_test_run]} { exit 1 }
11
12 global foo
13 set foo 1
14
15 # Test: mytest-1.1
16 # Desc: check if a source window was created
17 gdbtk_test mytest-1.1 {source window created} {
18 set window [ManagedWin::find SrcWin]
19 llength $window
20 set foo 13
21 } {1}
22
23 if {$test_ran} {
24 set foo 1
25 }
26
27 # Done
28 gdbtk_test_done
Line 1 calls the Inisght function gdbtk_read_defs to read in the testsuite
definitions file.
Line 6 then specifies the name of a file (mytest) in the object directory
which is loaded into gdb on Line 7. If loading the file into Insight
failed, gdbtk_test_error is called to publish the error (and terminate the
test run for this file).
Line 10 runs the executable on the target, and exits if it was unable
to do so.
Line 13 simply sets a global variable foo to illustrate the purpose
of the global "test_ran". Before the test "mytest-1.1" runs, foo is set to
one. In order to support running specific tests, the state of the debugger
cannot be altered INSIDE gdbtk_test scripts, since the contents of the
script may not be run if the user requested only a specific test to run.
Line 20 in the middle of the test modifies the global foo. If subsequent
test relied on foo being one, we would have a state violation, since
mytest-1.1 may have (or may have not) run.
Therefore, we can check if a test ran and reset foo by checking the
global "test_ran". If set, we know that the previous test (mytest-1.1)
was run, and that foo is now thirteen. We reset the result back to one.
(Aside: Some tests do not follow this rule explicitly: they can assume
that all tests run sequentially. In these cases, running a specific
test in the file will probably fail, since the debugger is not brought
to a known state along the way.)
Lines 17-21 contain the actual test. The test's name is "mytest-1.1". It
is this name that may be referred to when asking the testsuite to run
a specific test. The description of this test is "source window created",
indicating that mytest-1.1's purpose is to check whether a source window
was created.
If gdbtk_test determines that this test is to run, it will execute the
next part, lines 18-20, and compare the output of that script (llength
$window) with "1". If the result is not "1", a failure is recorded. If
it is "1", a pass is recorded.
Finally, the test file is done and exits on line 28.