A testing system for Boost.Build


Introduction and examples
Changing the working directory
Examining the working directory and changing it
Reference documentation
Method __init__
Method set_tree
Method touch
Method run_build_system
Methods for declaring expectations
Methods for ignoring changes
Method mul

Introduction and examples

The testing system for Boost.Build is derived from the TestCmd Python module used for testing the Scons build tools. The changes are very few, and I hope that some of them may be adopted by TestCmd in future.

Unfortunately, there are not documentation for TestCmd, apart from the comments in code, so the most essential base methods will be described here.

The basic steps of testing a build system behaviour are:

  1. Setting the initial working directory state
  2. Running the build system and check:
    1. generated output,
    2. changes made to the working directory,
    3. new content of the working directory.
  3. Adding, removing or touching files, or changing their content and then repeating the previous step, until satisfied.

For example, suppose that the current working directory contains the a file test1.py and a subdirectory test1 with files foo.cpp, Jamfile and Jamrules. A definition of function main is the only content of foo.cpp, Jamfile builds an executable foo from foo.cpp and Jamrules is empty. Finally, test1.py contains:

import BoostBuild

# Create a temporary working directory
t = BoostBuild.Tester()

# Make content of the working directory equal to the content of the 'test1' directory.
t.copy_tree('test1')

# Invoke the build system and record which changes were made
t.run_build_system("-sTOOLS=borland")
# First, create a list of three filenames with t.mul
# Second, check if those files were added as result of the last build system invocation.
t.expect_addition(t.mul("bin/foo/borland/debug/runtime-link-dynamic/foo", [".exe", ".obj", ".tds"]))

# Invoke the build system once again
t.run_build_system("clean")
# Check if the files added previously were removed.
t.expect_removal(t.mul("bin/foo/borland/debug/runtime-link-dynamic/foo", [".exe", ".obj", ".tds"]))

This is all needed for a minimal test (and to find a bug in the borland toolset!). Running the test1.py gives the following output:

File bin/foo/borland/debug/runtime-link-dynamic/foo.tds not removed as expected
FAILED test of D:\MyDocu~1\Work\build\boost-build\boost-build -d0
        at line 144 of TestBoostBuild.py (expect_removal)
        from line 12 of test1.py

Overview of the most important methods of class TestBoostBuild follows.

Changing the working directory

The class TestBoostBuild creates a temporary directory in its constructor and changes to that directory. It can be modified by calling these methods:

Examining the working directory and changing it

The method read, inherited from the TestCmd class, can be used to read any file in the working directory and check its content. TestBoostBuild adds another method for tracking changes. Whenever build system is run (via run_build_system), the state of working dir before and after running is recorded. In addition, difference between the two states -- i.e. lists of files that were added, removed, modified or touched -- is stored in two member variables, tree_difference and unexpected_difference.

After than, the test author may specify that some change is expected, for example, by calling expect_addition("foo"). This call will check if the file was indeed added, and if so, will remove its name from the list of added files in unexpected_difference.Likewise, it's possible to specify that some changes are not interesting, for example a call ignore("*.obj") will just remove every files with ".obj" extension from unexpected_difference.

When test has finished with expectations and ingoring, the member unexpected_difference will contain the list of all changes not yet accounted for. It is possible to assure that this list is empty by calling expect_nothing_more member function.

Reference documentation

The entire test system is composed of single class BoostBuild.Tester, derived form TestCmd.TestCmd. The methods defined in BoostBuild.Tester are described below.

Method __init__(self)

Effects:

  1. Remembers the current working directory in member original_workdir.
  2. Invokes the base method __init__ with appropriate parameters.
  3. Changes current working dir to the temporary working directory created by the base constructor.

Method set_tree(self, tree_location)

Effects:

Replaces the current working dir with content of directory at tree_location. If tree_location is not absolute pathname, it will be treated as relative to self.original_workdir.

Method touch(self, names)

Effects:

Sets the access and modification times for all files in names to the current time. All the elements names should be relative paths.

Method run_build_system(self, extra_args='', stdout=None, stderr='', status=0, **kw)

Effects:

  1. Stores the state of the working directory in self.previous_tree.
  2. Invokes the build system, passing extra_args to it.
  3. Compares the stdout, stderr and exit status of build system invocation with values to appropriate parameters, if they are not None. If any difference is found, the test fails.
  4. Stores the new state of the working directory in self.tree. Computes the difference between previous and current trees and store them in variables self.tree_difference and self.unexpected_difference.

    Both variables are instances of class tree.Trees_different, which have four attributes: added_files, removed_files, modified_files and touched_files. Each is a list of strings.

Methods for declaring expectations

Accordingly to the number of changes kinds that are detected, there are four methods that specify that test author expects a specific change to occur. They check self.unexpected_difference, and if the change is present there, it is removed. Otherwise, test fails.

Each method accepts a list of names. Those names are always unix-style, even on other systems.

Note:The mul member might be usefull to create lists of names.

Note:The file content can be examined using TestCmd.read function.

The members are:

There's also a member expect_nothing_more, which checks that all the changes are either expected or ignored, in other words that unexpected_difference is empty by now.

Methods for ignoring changes

There are five methods which ignore changes made to the working tree. They silently remove elements from self.unexpected_difference, and don't generate error if element is not found. They accept shell style wildcard.

The following methods correspond to four kinds of changes:

The method ignore(self, wildcard) ingores all the changes made to files that match a wildcard.

Method mul(self, *arguments)

Precondition:Each passed arguments must be either string or a list of strings.

Effects:Returns a list of strings which are formed by taking one string from each passed argument and joining them. The order of strings corresponds to lexicagraphical ordering of sequences of indices.

Example:

    mul("/home/ghost", [".bashrc", ".bash_profile"])

will return

   ["/home/ghost/.bashrc", "/home/ghost/.bash_profile"]

Last modified: April 4, 2002

© Copyright Vladimir Prus 2002. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided ``as is'' without express or implied warranty, and with no claim as to its suitability for any purpose.