| Index: docs/Testing.md
|
| diff --git a/docs/Testing.md b/docs/Testing.md
|
| deleted file mode 100644
|
| index 55205de29133cc5d3fbb8334b929e7e76cbbb153..0000000000000000000000000000000000000000
|
| --- a/docs/Testing.md
|
| +++ /dev/null
|
| @@ -1,459 +0,0 @@
|
| -# GYP (Generate Your Projects) Tests
|
| -
|
| ---
|
| -
|
| -Status: Draft (as of 2009-08-18)
|
| -
|
| -Steven Knight <sgk@chromium.org>
|
| -_et al._
|
| -
|
| -Modified: 2009-08-18
|
| -
|
| -[TOC]
|
| -
|
| -## Introduction
|
| -
|
| -This document describes the GYP testing infrastructure,
|
| -as provided by the `TestGyp.py` module.
|
| -
|
| -These tests emphasize testing the _behavior_ of the
|
| -various GYP-generated build configurations:
|
| -Visual Studio, Xcode, SCons, Make, etc.
|
| -The goal is _not_ to test the output of the GYP generators by,
|
| -for example, comparing a GYP-generated Makefile
|
| -against a set of known "golden" Makefiles
|
| -(although the testing infrastructure could
|
| -be used to write those kinds of tests).
|
| -The idea is that the generated build configuration files
|
| -could be completely written to add a feature or fix a bug
|
| -so long as they continue to support the functional behaviors
|
| -defined by the tests: building programs, shared libraries, etc.
|
| -
|
| -## "Hello, world!" GYP test configuration
|
| -
|
| -Here is an actual test configuration,
|
| -a simple build of a C program to print `"Hello, world!"`.
|
| -
|
| -```
|
| - $ ls -l test/hello
|
| - total 20
|
| - -rw-r--r-- 1 knight knight 312 Jul 30 20:22 gyptest-all.py
|
| - -rw-r--r-- 1 knight knight 307 Jul 30 20:22 gyptest-default.py
|
| - -rwxr-xr-x 1 knight knight 326 Jul 30 20:22 gyptest-target.py
|
| - -rw-r--r-- 1 knight knight 98 Jul 30 20:22 hello.c
|
| - -rw-r--r-- 1 knight knight 142 Jul 30 20:22 hello.gyp
|
| - $
|
| -```
|
| -
|
| -The `gyptest-*.py` files are three separate tests (test scripts)
|
| -that use this configuration. The first one, `gyptest-all.py`,
|
| -looks like this:
|
| -
|
| -```
|
| - #!/usr/bin/env python
|
| -
|
| - """
|
| - Verifies simplest-possible build of a "Hello, world!" program
|
| - using an explicit build target of 'all'.
|
| - """
|
| -
|
| - import TestGyp
|
| -
|
| - test = TestGyp.TestGyp()
|
| -
|
| - test.run_gyp('hello.gyp')
|
| -
|
| - test.build_all('hello.gyp')
|
| -
|
| - test.run_built_executable('hello', stdout="Hello, world!\n")
|
| -
|
| - test.pass_test()
|
| -```
|
| -
|
| -The test script above runs GYP against the specified input file
|
| -(`hello.gyp`) to generate a build configuration.
|
| -It then tries to build the `'all'` target
|
| -(or its equivalent) using the generated build configuration.
|
| -Last, it verifies that the build worked as expected
|
| -by running the executable program (`hello`)
|
| -that was just presumably built by the generated configuration,
|
| -and verifies that the output from the program
|
| -matches the expected `stdout` string (`"Hello, world!\n"`).
|
| -
|
| -Which configuration is generated
|
| -(i.e., which build tool to test)
|
| -is specified when the test is run;
|
| -see the next section.
|
| -
|
| -Surrounding the functional parts of the test
|
| -described above are the header,
|
| -which should be basically the same for each test
|
| -(modulo a different description in the docstring):
|
| -
|
| -```
|
| - #!/usr/bin/env python
|
| -
|
| - """
|
| - Verifies simplest-possible build of a "Hello, world!" program
|
| - using an explicit build target of 'all'.
|
| - """
|
| -
|
| - import TestGyp
|
| -
|
| - test = TestGyp.TestGyp()
|
| -```
|
| -
|
| -Similarly, the footer should be the same in every test:
|
| -
|
| -```
|
| - test.pass_test()
|
| -```
|
| -
|
| -## Running tests
|
| -
|
| -Test scripts are run by the `gyptest.py` script.
|
| -You can specify (an) explicit test script(s) to run:
|
| -
|
| -```
|
| - $ python gyptest.py test/hello/gyptest-all.py
|
| - PYTHONPATH=/home/knight/src/gyp/trunk/test/lib
|
| - TESTGYP_FORMAT=scons
|
| - /usr/bin/python test/hello/gyptest-all.py
|
| - PASSED
|
| - $
|
| -```
|
| -
|
| -If you specify a directory, all test scripts
|
| -(scripts prefixed with `gyptest-`) underneath
|
| -the directory will be run:
|
| -
|
| -```
|
| - $ python gyptest.py test/hello
|
| - PYTHONPATH=/home/knight/src/gyp/trunk/test/lib
|
| - TESTGYP_FORMAT=scons
|
| - /usr/bin/python test/hello/gyptest-all.py
|
| - PASSED
|
| - /usr/bin/python test/hello/gyptest-default.py
|
| - PASSED
|
| - /usr/bin/python test/hello/gyptest-target.py
|
| - PASSED
|
| - $
|
| -```
|
| -
|
| -Or you can specify the `-a` option to run all scripts
|
| -in the tree:
|
| -
|
| -```
|
| - $ python gyptest.py -a
|
| - PYTHONPATH=/home/knight/src/gyp/trunk/test/lib
|
| - TESTGYP_FORMAT=scons
|
| - /usr/bin/python test/configurations/gyptest-configurations.py
|
| - PASSED
|
| - /usr/bin/python test/defines/gyptest-defines.py
|
| - PASSED
|
| - .
|
| - .
|
| - .
|
| - .
|
| - /usr/bin/python test/variables/gyptest-commands.py
|
| - PASSED
|
| - $
|
| -```
|
| -
|
| -If any tests fail during the run,
|
| -the `gyptest.py` script will report them in a
|
| -summary at the end.
|
| -
|
| -## Debugging tests
|
| -
|
| -Tests that create intermediate output do so under the gyp/out/testworkarea
|
| -directory. On test completion, intermediate output is cleaned up. To preserve
|
| -this output, set the environment variable PRESERVE=1. This can be handy to
|
| -inspect intermediate data when debugging a test.
|
| -
|
| -You can also set PRESERVE\_PASS=1, PRESERVE\_FAIL=1 or PRESERVE\_NO\_RESULT=1
|
| -to preserve output for tests that fall into one of those categories.
|
| -
|
| -# Specifying the format (build tool) to use
|
| -
|
| -By default, the `gyptest.py` script will generate configurations for
|
| -the "primary" supported build tool for the platform you're on:
|
| -Visual Studio on Windows,
|
| -Xcode on Mac,
|
| -and (currently) SCons on Linux.
|
| -An alternate format (build tool) may be specified
|
| -using the `-f` option:
|
| -
|
| -```
|
| - $ python gyptest.py -f make test/hello/gyptest-all.py
|
| - PYTHONPATH=/home/knight/src/gyp/trunk/test/lib
|
| - TESTGYP_FORMAT=make
|
| - /usr/bin/python test/hello/gyptest-all.py
|
| - PASSED
|
| - $
|
| -```
|
| -
|
| -Multiple tools may be specified in a single pass as
|
| -a comma-separated list:
|
| -
|
| -```
|
| - $ python gyptest.py -f make,scons test/hello/gyptest-all.py
|
| - PYTHONPATH=/home/knight/src/gyp/trunk/test/lib
|
| - TESTGYP_FORMAT=make
|
| - /usr/bin/python test/hello/gyptest-all.py
|
| - PASSED
|
| - TESTGYP_FORMAT=scons
|
| - /usr/bin/python test/hello/gyptest-all.py
|
| - PASSED
|
| - $
|
| -```
|
| -
|
| -## Test script functions and methods
|
| -
|
| -The `TestGyp` class contains a lot of functionality
|
| -intended to make it easy to write tests.
|
| -This section describes the most useful pieces for GYP testing.
|
| -
|
| -(The `TestGyp` class is actually a subclass of more generic
|
| -`TestCommon` and `TestCmd` base classes
|
| -that contain even more functionality than is
|
| -described here.)
|
| -
|
| -### Initialization
|
| -
|
| -The standard initialization formula is:
|
| -
|
| -```
|
| - import TestGyp
|
| - test = TestGyp.TestGyp()
|
| -```
|
| -
|
| -This copies the contents of the directory tree in which
|
| -the test script lives to a temporary directory for execution,
|
| -and arranges for the temporary directory's removal on exit.
|
| -
|
| -By default, any comparisons of output or file contents
|
| -must be exact matches for the test to pass.
|
| -If you need to use regular expressions for matches,
|
| -a useful alternative initialization is:
|
| -
|
| -```
|
| - import TestGyp
|
| - test = TestGyp.TestGyp(match = TestGyp.match_re,
|
| - diff = TestGyp.diff_re)`
|
| -```
|
| -
|
| -### Running GYP
|
| -
|
| -The canonical invocation is to simply specify the `.gyp` file to be executed:
|
| -
|
| -```
|
| - test.run_gyp('file.gyp')
|
| -```
|
| -
|
| -Additional GYP arguments may be specified:
|
| -
|
| -```
|
| - test.run_gyp('file.gyp', arguments=['arg1', 'arg2', ...])
|
| -```
|
| -
|
| -To execute GYP from a subdirectory (where, presumably, the specified file
|
| -lives):
|
| -
|
| -```
|
| - test.run_gyp('file.gyp', chdir='subdir')
|
| -```
|
| -
|
| -### Running the build tool
|
| -
|
| -Running the build tool requires passing in a `.gyp` file, which may be used to
|
| -calculate the name of a specific build configuration file (such as a MSVS
|
| -solution file corresponding to the `.gyp` file).
|
| -
|
| -There are several different `.build_*()` methods for invoking different types
|
| -of builds.
|
| -
|
| -To invoke a build tool with an explicit `all` target (or equivalent):
|
| -
|
| -```
|
| - test.build_all('file.gyp')
|
| -```
|
| -
|
| -To invoke a build tool with its default behavior (for example, executing `make`
|
| -with no targets specified):
|
| -
|
| -```
|
| - test.build_default('file.gyp')
|
| -```
|
| -
|
| -To invoke a build tool with an explicit specified target:
|
| -
|
| -```
|
| - test.build_target('file.gyp', 'target')
|
| -```
|
| -
|
| -### Running executables
|
| -
|
| -The most useful method executes a program built by the GYP-generated
|
| -configuration:
|
| -
|
| -```
|
| - test.run_built_executable('program')
|
| -```
|
| -
|
| -The `.run_built_executable()` method will account for the actual built target
|
| -output location for the build tool being tested, as well as tack on any
|
| -necessary executable file suffix for the platform (for example `.exe` on
|
| -Windows).
|
| -
|
| -`stdout=` and `stderr=` keyword arguments specify expected standard output and
|
| -error output, respectively. Failure to match these (if specified) will cause
|
| -the test to fail. An explicit `None` value will suppress that verification:
|
| -
|
| -```
|
| - test.run_built_executable('program',
|
| - stdout="expect this output\n",
|
| - stderr=None)
|
| -```
|
| -
|
| -Note that the default values are `stdout=None` and `stderr=''` (that is, no
|
| -check for standard output, and error output must be empty).
|
| -
|
| -Arbitrary executables (not necessarily those built by GYP) can be executed with
|
| -the lower-level `.run()` method:
|
| -
|
| -```
|
| - test.run('program')
|
| -```
|
| -
|
| -The program must be in the local directory (that is, the temporary directory
|
| -for test execution) or be an absolute path name.
|
| -
|
| -### Fetching command output
|
| -
|
| -```
|
| - test.stdout()
|
| -```
|
| -
|
| -Returns the standard output from the most recent executed command (including
|
| -`.run_gyp()`, `.build_*()`, or `.run*()` methods).
|
| -
|
| -```
|
| - test.stderr()
|
| -```
|
| -
|
| -Returns the error output from the most recent executed command (including
|
| -`.run_gyp()`, `.build_*()`, or `.run*()` methods).
|
| -
|
| -### Verifying existence or non-existence of files or directories
|
| -
|
| -```
|
| - test.must_exist('file_or_dir')
|
| -```
|
| -
|
| -Verifies that the specified file or directory exists, and fails the test if it
|
| -doesn't.
|
| -
|
| -```
|
| - test.must_not_exist('file_or_dir')
|
| -```
|
| -
|
| -Verifies that the specified file or directory does not exist, and fails the
|
| -test if it does.
|
| -
|
| -### Verifying file contents
|
| -
|
| -```
|
| - test.must_match('file', 'expected content\n')
|
| -```
|
| -
|
| -Verifies that the content of the specified file match the expected string, and
|
| -fails the test if it does not. By default, the match must be exact, but
|
| -line-by-line regular expressions may be used if the `TestGyp` object was
|
| -initialized with `TestGyp.match_re`.
|
| -
|
| -```
|
| - test.must_not_match('file', 'expected content\n')
|
| -```
|
| -
|
| -Verifies that the content of the specified file does _not_ match the expected
|
| -string, and fails the test if it does. By default, the match must be exact,
|
| -but line-by-line regular expressions may be used if the `TestGyp` object was
|
| -initialized with `TestGyp.match_re`.
|
| -
|
| -```
|
| - test.must_contain('file', 'substring')
|
| -```
|
| -
|
| -Verifies that the specified file contains the specified substring, and fails
|
| -the test if it does not.
|
| -
|
| -```
|
| - test.must_not_contain('file', 'substring')
|
| -```
|
| -
|
| -Verifies that the specified file does not contain the specified substring, and
|
| -fails the test if it does.
|
| -
|
| -```
|
| - test.must_contain_all_lines(output, lines)
|
| -```
|
| -
|
| -Verifies that the output string contains all of the "lines" in the specified
|
| -list of lines. In practice, the lines can be any substring and need not be
|
| -`\n`-terminaed lines per se. If any line is missing, the test fails.
|
| -
|
| -```
|
| - test.must_not_contain_any_lines(output, lines)
|
| -```
|
| -
|
| -Verifies that the output string does _not_ contain any of the "lines" in the
|
| -specified list of lines. In practice, the lines can be any substring and need
|
| -not be `\n`-terminaed lines per se. If any line exists in the output string,
|
| -the test fails.
|
| -
|
| -```
|
| - test.must_contain_any_line(output, lines)
|
| -```
|
| -
|
| -Verifies that the output string contains at least one of the "lines" in the
|
| -specified list of lines. In practice, the lines can be any substring and need
|
| -not be `\n`-terminaed lines per se. If none of the specified lines is present,
|
| -the test fails.
|
| -
|
| -### Reading file contents
|
| -
|
| -```
|
| - test.read('file')
|
| -```
|
| -
|
| -Returns the contents of the specified file. Directory elements contained in a
|
| -list will be joined:
|
| -
|
| -```
|
| - test.read(['subdir', 'file'])
|
| -```
|
| -
|
| -### Test success or failure
|
| -
|
| -```
|
| - test.fail_test()
|
| -```
|
| -
|
| -Fails the test, reporting `FAILED` on standard output and exiting with an exit
|
| -status of `1`.
|
| -
|
| -```
|
| - test.pass_test()
|
| -```
|
| -
|
| -Passes the test, reporting `PASSED` on standard output and exiting with an exit
|
| -status of `0`.
|
| -
|
| -```
|
| - test.no_result()
|
| -```
|
| -
|
| -Indicates the test had no valid result (i.e., the conditions could not be
|
| -tested because of an external factor like a full file system). Reports `NO
|
| -RESULT` on standard output and exits with a status of `2`.
|
|
|