• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
2"http://www.w3.org/TR/html4/strict.dtd">
3
4<html>
5  <head>
6    <meta name="generator" content=
7    "HTML Tidy for Linux/x86 (vers 1st March 2002), see www.w3.org">
8    <!--tidy options: -i -wrap 78 -->
9    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
10
11    <title>A testing system for B2</title>
12<style type="text/css">
13        hr { color: black }
14        p.revision { text-align: right; font-style: italic }
15        pre.code { margin-left: 2em }
16        pre.example { margin-left: 2em; border: solid black thin }
17        pre.output { margin-left: 2em }
18        img.banner { border: 0; float: left }
19        h1 { text-align: right }
20        br.clear { clear: left }
21        div.attention { color: red }
22
23</style>
24  </head>
25
26  <body>
27    <p><a href="../../../../index.htm"><img class="banner" height="86" width=
28    "277" alt="C++ Boost" src="../../../../boost.png"></a></p>
29
30    <h1>A testing system for B2<br class="clear">
31    </h1>
32    <hr>
33
34    <dl class="page-index">
35      <dt><a href="#sec-intro">Introduction for users</a></dt>
36
37      <dd>
38        <dl class="page-index">
39          <dt><a href="#sec-command-line-options">Command line options</a></dt>
40        </dl>
41      </dd>
42
43      <dt><a href="#sec-developers">Introduction for developers</a></dt>
44
45      <dd>
46        <dl class="page-index">
47          <dt><a href="#sec-intro-changing">Changing the working
48          directory</a></dt>
49
50          <dt><a href="#sec-intro-examining">Examining the working directory and
51          changing it</a></dt>
52
53          <dt><a href="#sec-intro-results">Test result</a></dt>
54        </dl>
55      </dd>
56
57      <dt><a href="#sec-reference">Reference documentation</a></dt>
58
59      <dd>
60        <dl class="page-index">
61          <dt><a href="#method-__init__">Method __init__</a></dt>
62
63          <dt><a href="#method-set_tree">Method <tt>set_tree</tt></a></dt>
64
65          <dt><a href="#method-write">Method <tt>write</tt></a></dt>
66
67          <dt><a href="#method-copy">Method <tt>copy</tt></a></dt>
68
69          <dt><a href="#method-touch">Method <tt>touch</tt></a></dt>
70
71          <dt><a href="#method-run_build_system">Method
72          <tt>run_build_system</tt></a></dt>
73
74          <dt><a href="#method-read">Method <tt>read</tt></a></dt>
75
76          <dt><a href="#method-read_and_strip">Method
77          <tt>read_and_strip</tt></a></dt>
78
79          <dt><a href="#methods-expectations">Methods for declaring
80          expectations</a></dt>
81
82          <dt><a href="#methods-ignoring">Methods for ignoring
83          changes</a></dt>
84
85          <dt><a href="#methods-result">Methods for explicitly specifying
86          results</a></dt>
87
88          <dt><a href="#class-list">Helper class <tt>List</tt></a></dt>
89        </dl>
90      </dd>
91    </dl>
92    <hr>
93
94    <h2><a name="sec-intro">Introduction for users</a></h2>
95
96    <p>The testing system for B2 is a small set of Python modules and
97    scripts for automatically testing user-obversable behaviour. It uses
98    components from testing systems of <a href="http://www.scons.org">Scons</a>
99    and <a href="http://subversion.tigris.org">Subversion</a>, together with
100    some additional functionality.</p>
101
102    <p>To run the tests you need to:</p>
103
104    <ol>
105      <li>Get the source tree of B2 (located at <tt>tools/build</tt>
106      in Boost)</li>
107
108      <li>Have <a href="http://www.python.org">Python</a> installed. Version
109      2.1 is known to work.</li>
110
111      <li>Build Boost.Jam. See <a href=
112      "../engine/index.html">$boost_build_root/engine/index.html</a> for
113      instructions.</li>
114
115      <li>Configure at least one toolset. You can edit <tt>site-config.jam</tt>
116      or <tt>user-config.jam</tt> to add new toolsets. Or you can create file
117      <tt>test-config.jam</tt> in <tt>$boost_build_root/test</tt> directory. In
118      this case, <tt>site-config.jam</tt> and <tt>user-config.jam</tt> will be
119      ignored for testing.</li>
120
121      <li>Make sure that in the configuration jam file(s) that you use you generate
122      no console output, ie. with the Boost Build 'ECHO' rule. Such console output
123      in the configuration jam file(s) will cause a number of tests to automatically
124      fail which would otherwise succeed.</li>
125    </ol>
126
127    <p>When all is set, you can run all the tests using the <tt>test_all.py</tt>
128     script or you can run a specific test by starting its Python script
129     directly.</p>
130
131    <p>Examples:</p>
132
133<pre class="code">
134python test_all.py
135python generators_test.py
136</pre>
137
138    <p>If everything is OK, you will see a list of passed tests. Otherwise, a
139    failure will be reported.</p>
140
141    <h3><a name="sec-command-line-options">Command line options</a></h3>
142
143    <p>Test scripts will use the toolset you configured to be the default or
144    you can specify a specific one on the command line:</p>
145
146<pre class="code">
147python test_all.py borland
148python generators_test.py msvc-7.1
149</pre>
150
151    <p>Other test script flags you can specify on the command line are:</p>
152
153    <ul>
154        <li><tt>--default-bjam</tt> -- By default the test system will use the
155        Boost Jam executable found built in its default development build
156        location. This option makes it use the default one available on your
157        system, i.e. the one found in the system path.</li>
158
159        <li><tt>--preserve</tt> -- In case of a failed test its working
160        directory will be copied to the "failed_test" directory under the
161        current directory.</li>
162
163        <li><tt>--verbose</tt> -- Makes the test system and the run build system
164        display additional output. Note though that this may cause tests that
165        check the build system output to fail.</li>
166    </ul>
167
168    <h2><a name="sec-developers">Introduction for developers</a></h2>
169
170    <p>It is suggested that every new functionality come together with tests,
171    and that bugfixes are accompanied by tests. There's no need to say that
172    tests are good, but two points are extremely important:</p>
173
174    <ul>
175      <li>For an interpreted language like Jam, without any static checks,
176      testing is simply the only sefeguard we can have.</li>
177
178      <li>Good tests allow us to change internal design much more safely, and we
179      have not gotten everything nailed down yet.</li>
180    </ul>
181
182    <p>Adding a new test is simple:</p>
183
184    <ol>
185      <li>Go to <tt>$boost_build_root/test/test_all.py</tt> and add new test
186      name to the list at the end of the file. Suppose the test name is "hello".
187      </li>
188
189      <li>Add a new python module, in this example "hello.py", to do the actual
190      testing.</li>
191    </ol>
192
193    <p>The module, in general will perform these basic actions:</p>
194
195    <ol>
196      <li>Set up the initial working directory state</li>
197
198      <li>
199        Run the build system and check the results:
200
201        <ol>
202          <li>generated output,</li>
203
204          <li>changes made to the working directory,</li>
205
206          <li>new content of the working directory.</li>
207        </ol>
208      </li>
209
210      <li>Add, remove or touch files or change their content and then repeat
211      the previous step until satisfied.</li>
212
213      <li>Clean up</li>
214    </ol>
215
216    <p>The "hello.py" module might contain:</p>
217<pre class="example">
218from BoostBuild import List
219
220# Create a temporary working directory
221t = BoostBuild.Tester()
222
223# Create the needed files
224t.write("jamroot.jam", "")
225t.write("jamfile.jam", """
226exe hello : hello.cpp ;
227""")
228t.write("hello.cpp", """
229int main()
230{
231    return 0;
232}
233
234""")
235
236t.run_build_system()
237
238# First, create a list of three pathnames.
239file_list = List("bin/$toolset/debug/") * List("hello.exe hello.obj")
240# Second, assert that those files were added as result of the last build system invocation.
241t.expect_addition(file_list)
242
243# Invoke the build system once again.
244t.run_build_system("clean")
245# Check if the files added previously were removed.
246t.expect_removal(file_list)
247
248# Remove temporary directories
249t.cleanup()
250</pre>
251
252    <p>The <tt>test</tt> directory contains a file "template.py" which can be
253    used as a start for your own tests.</p>
254
255    <p>Overview of the most important methods of class <tt>Tester</tt> follows.
256    </p>
257
258    <h3><a name="sec-intro-changing">Changing the working directory</a></h3>
259
260    <p>The class <tt>Tester</tt> creates a temporary directory in its
261    constructor and changes to that directory. It can be modified by calling
262    these methods:</p>
263
264    <ul>
265      <li><tt>set_tree</tt> -- sets the content of the working directory to be
266      equal to the content of the specified directory. This method is
267      preferable when directory tree for testing is large.</li>
268
269      <li><tt>write</tt> -- sets the content of file in a working directory.
270      This is optimal if you want to create a directory tree with 3-4 small
271      files.</li>
272
273      <li><tt>touch</tt> -- changes the modification times of a file</li>
274    </ul>
275
276    <h3><a name="sec-intro-examining">Examining the working directory and
277    changing it</a></h3>
278
279    <p>The method <tt>read</tt>, inherited from the <tt>TestCmd</tt> class, can
280    be used to read any file in the working directory and check its content.
281    <tt>Tester</tt> adds another method for tracking changes. Whenever the build
282    system is run (using <a href="#method-run_build_system"><tt>run_build_system
283    </tt></a>), the working dir state before and after running is recorded. In
284    addition, difference between the two states -- i.e. lists of files that were
285    added, removed, modified or touched -- are stored in two member variables -
286    <tt>tree_difference</tt> and <tt>unexpected_difference</tt>.</p>
287
288    <p>After than, the test author may specify that some change is expected, for
289    example, by calling <tt>expect_addition("foo")</tt>. This call will check if
290    the file was indeed added, and if so, will remove its name from the list of
291    added files in <tt>unexpected_difference</tt>. Likewise, it is possible to
292    specify that some changes are not interesting, for example a call to
293    <tt>ignore("*.obj")</tt> will just remove every file with the ".obj"
294    extension from <tt>unexpected_difference</tt>.</p>
295
296    <p>When test has finished with expectations and ignoring, the member
297    <tt>unexpected_difference</tt> will contain the list of all changes not yet
298    accounted for. It is possible to assure that this list is empty by calling
299    the <tt>expect_nothing_more</tt> member function.</p>
300
301    <h3><a name="sec-intro-results">Test result</a></h3>
302
303    <p>Any of the <tt>expect*</tt> methods below will fail the test if the
304    expectation is not met. It is also possible to perform manually arbitrary
305    test and explicitly cause the test to either pass or fail. Ordinary
306    filesystem functions can be used to work with the directory tree. Methods
307    <tt>pass_test</tt> and <tt>fail_test</tt> are used to explicitly give the
308    test outcome.</p>
309
310    <p>Typically, after test termination, the working directory is erased. See
311    the <a href="#sec-command-line-options">"--preserve" command line option</a>
312    for information on how to preserve the working directory content for failed
313    tests for debugging purposes.</p>
314
315    <h2 id="sec-reference">Reference documentation</h2>
316
317    <p>The test system is composed of class <tt>Tester</tt>, derived form
318    <tt>TestCmd.TestCmd</tt>, and helper class <tt>List</tt>. <tt>Tester</tt>
319    and <tt>List</tt> methods are described below.</p>
320
321    <p>The documentation frequently refers to <tt>filename</tt>. In all cases,
322    files are specified in unix style: a sequence of components, separated by
323    "/". This is true on all platforms. In some contexts a list of files is
324    allowed. In those cases any object with a sequence interface is allowed.</p>
325
326    <h3><a name="method-__init__">Method <tt>__init__(self, arguments="",
327    executable="bjam", match=TestCmd.match_exact, boost_build_path=None,
328    translate_suffixes=True, pass_toolset=True, use_test_config=True,
329    ignore_toolset_requirements=True, workdir="", **keywords)</tt></a></h3>
330
331    <p><b>Optional arguments:</b></p>
332
333    <ul>
334        <li><tt>arguments</tt>
335            -- Arguments passed to the run executable.</li>
336        <li><tt>executable</tt>
337            -- Name of the executable to invoke.</li>
338        <li><tt>match</tt>
339            -- Function to use for compating actual and expected file contents.
340            </li>
341        <li><tt>boost_build_path</tt>
342            -- Boost build path to be passed to the run executable.</li>
343        <li><tt>translate_suffixes</tt>
344            -- Whether to update suffixes on the the file names passed from the
345            test script so they match those actually created by the current
346            toolset. For example, static library files are specified by using
347            the .lib suffix but when the 'gcc' toolset is used it actually
348            creates them using the .a suffix.</li>
349        <li><tt>pass_toolset</tt>
350            -- Whether the test system should pass the specified toolset to the
351            run executable.</li>
352        <li><tt>use_test_config</tt>
353            -- Whether the test system should tell the run executable to read in
354            the test_config.jam configuration file.</li>
355        <li><tt>ignore_toolset_requirements</tt>
356            -- Whether the test system should tell the run executable to ignore
357            toolset requirements.</li>
358        <li><tt>workdir</tt>
359            -- Indicates an absolute directory where the test will be run from.
360            </li>
361    </ul>
362
363    <p><b>Optional arguments inherited from the base class:</b></p>
364
365    <ul>
366        <li><tt>description</tt>
367            -- Test description string displayed in case of a failed test.</li>
368        <li><tt>subdir</tt>
369            -- List of subdirectories to automatically create under the working
370              directory. Each subdirectory needs to be specified separately
371              parent coming before its child.</li>
372        <li><tt>verbose</tt>
373            -- Flag that may be used to enable more verbose test system output.
374            Note that it does not also enable more verbose build system output
375            like the <a href="#sec-command-line-options">"--verbose" command
376            line option</a> does.</li>
377    </ul>
378
379    <p><b>Effects:</b></p>
380
381    <ol>
382      <li>Remembers the current working directory in member
383      <tt>original_workdir</tt>.</li>
384
385      <li>Determines the location of the executable (<code>bjam</code> by
386      default) and build system files, assuming that the current directory is
387      <tt>tools/build/test</tt>. Formulates jam invocation command, which
388      will include explicit setting for the <tt>BOOST_BUILD_PATH</tt> variable
389      and arguments passed to this methods, if any. This command will be used
390      by subsequent invocation of <a href="#method-run_build_system"><tt>
391      run_build_system</tt></a>. Finally, initializes the base class.</li>
392
393      <li>Changes the current working directory to the temporary working
394      directory created by the base constructor.</li>
395
396      <li>If you want to run a test in an existing directory, pass it as
397      <tt>workdir</tt>.</li>
398
399      <li> Most parameters passed to this constructor function may be overruled
400      for each specific test system run using <a href=
401      "#method-run_build_system"><tt>run_build_system</tt></a> parameters.
402    </ol>
403
404    <h3><a name="method-set_tree">Method <tt>set_tree(self,
405    tree_location)</tt></a></h3>
406
407    <p><b>Effects:</b></p>
408
409    <p>Replaces the content of the current working directory with the content
410    of directory at <tt>tree_location</tt>. If <tt>tree_location</tt> is not
411    absolute pathname, it will be treated as relative to
412    <tt>self.original_workdir</tt>. This methods also explicitly makes the
413    copied files writeable.</p>
414
415    <h3><a name="method-write">Method <tt>write(self, name,
416    content)</tt></a></h3>
417
418    <p><b>Effects:</b></p>
419
420    <p>Writes the specified content to the file given by <tt>name</tt> under
421    the temporary working directory. If the file already exists, it is
422    overwritten. Any required directories are automatically created.</p>
423
424    <h3><a name="method-copy">Method <tt>copy(self, src, dst)</tt></a></h3>
425
426    <p><b>Effects:</b></p>
427
428    <p>Equvivalent to <tt>self.write(self.read(src), dst)</tt>.</p>
429
430    <h3><a name="method-touch">Method <tt>touch(self, names)</tt></a></h3>
431
432    <p><b>Effects:</b></p>
433
434    <p>Sets the access and modification times for all files in <tt>names</tt> to
435    the current time. All the elements in <tt>names</tt> should be relative
436    paths.</p>
437
438    <h3><a name="method-run_build_system">Method <tt>run_build_system(self,
439    extra_args="", subdir="", stdout=None, stderr="", status=0, match=None,
440    pass_toolset=None, use_test_config=None, ignore_toolset_requirements=None,
441    expected_duration=None, **kw)</tt></a></h3>
442
443    <p><b>Effects:</b></p>
444
445    <ol>
446      <li>Stores the state of the working directory in
447      <tt>self.previous_tree</tt>.</li>
448
449      <li>Changes to <tt>subdir</tt>, if it is specified. It is relative to
450      the <tt>original_workdir</tt> or the workdir specified in
451      <tt>__init</tt>.</li>
452
453      <li>Invokes the <tt>bjam</tt> executable, passing <tt>extra_args</tt>
454      to it. The binary should be located under
455      <tt>&lt;test_invocation_dir&gt;/../jam/src/bin.&lt;platform&gt;</tt>.
456      This is to make sure tests use the version of jam build from CVS.</li>
457
458      <li>Compares the stdout, stderr and exit status of build system
459      invocation with values to appropriate parameters, if they are not
460      <tt>None</tt>. If any difference is found, the test fails.</li>
461
462      <li>If the <tt>expected_duration</tt> parameter is specified then it
463      represents the maximal allowed time in seconds for the test to run. The
464      test will be marked as failed if its duration is greater than the given
465      <tt>expected_duration</tt> parameter value.</li>
466
467      <li>Stores the new state of the working directory in <tt>self.tree</tt>.
468      Computes the difference between previous and current trees and stores them
469      in variables <tt>self.tree_difference</tt> and
470      <tt>self.unexpected_difference</tt>. Both variables are instances of class
471      <tt>tree.Trees_different</tt>, which have four attributes:
472      <tt>added_files</tt>, <tt>removed_files</tt>, <tt>modified_files</tt> and
473      <tt>touched_files</tt>. Each is a list of strings.</p></li>
474    </ol>
475
476    <h3><a name="method-read">Method <tt>read(self, name)</tt></a></h3>
477
478    <p><b>Effects:</b></p>
479
480    <p>Read the specified file and returns it content. Raises an exception is
481    the file is absent.</p>
482
483    <h3><a name="method-read_and_strip">Method <tt>read_and_strip(self, name)
484    </tt></a></h3>
485
486    <p><b>Effects:</b></p>
487
488    <p>Read the specified file and returns it content, after removing trailing
489    whitespace from every line. Raises an exception is the file is absent.</p>
490
491    <p><b>Rationale:</b></p>
492
493    <p>Although this method is questionable, there are a lot of cases when jam
494    or shells it uses insert spaces. It seems that introducing this method is
495    much simpler than dealing with all those cases.</p>
496
497    <h3><a name="methods-expectations">Methods for declaring expectations</a>
498    </h3>
499
500    <p>Accordingly to the number of changes kinds that are detected, there are
501    four methods that specify that test author expects a specific change to
502    occur. They check <tt>self.unexpected_difference</tt>, and if the change is
503    present there, it is removed. Otherwise, test fails.</p>
504
505    <p>Each method accepts a list of names. Those names use <tt>/</tt> path
506    separator on all systems. Additionally, the test system translates suffixes
507    appropriately. For the test to be portable, suffixes should use Windows
508    convention: <tt>exe</tt> for executables, <tt>dll</tt> for dynamic libraries
509    and <tt>lib</tt> for static libraries. Lastly, the string "$toolset" in file
510    names is replaced by the name of tested toolset.</p>
511
512    <p><b>Note:</b> The <tt>List</tt> helper class might be useful to create
513    lists of names.</p>
514
515    <p><b>Note:</b> The file content can be examined using the
516    <tt>TestCmd.read</tt> function.</p>
517
518    <p>The members are:</p>
519
520    <ul>
521      <li>expect_addition</li>
522      <li>expect_removal</li>
523      <li>expect_modification</li>
524      <li>expect_nothing</li>
525    </ul>
526
527    <p>Note that <tt>expect_modification</tt> is used to check that a either
528    file content or timestamp has changed. The rationale is that some compilers
529    change content even if sources does not change, and it's easier to have a
530    method which checks for both content and time changes.</p>
531
532    <p>There's also a member <tt>expect_nothing_more</tt>, which checks that all
533    the changes are either expected or ignored, in other words that
534    <tt>unexpected_difference</tt> is empty by now.</p>
535
536    <p>Lastly, there's a method to compare file content with expected content:
537    </p>
538    <tt>expect_content(self, name, content, exact=0)</tt>
539
540    <p>The method fails the test if the content of file identified by 'name' is
541    different from 'content'. If 'exact' is true, the file content is used
542    as-is, otherwise, two transformations are applied:</p>
543
544    <ul>
545      <li>The <tt>read_and_strip</tt> method is used to read the file, which
546      removes trailing whitespace</li>
547
548      <li>Each backslash in the file content is converted to forward slash.</li>
549    </ul>
550
551    <h3><a name="methods-ignoring">Methods for ignoring changes</a></h3>
552
553    <p>There are five methods which ignore changes made to the working tree.
554    They silently remove elements from <tt>self.unexpected_difference</tt>, and
555    don't generate error if element is not found. They accept shell style
556    wildcard.</p>
557
558    <p>The following methods correspond to four kinds of changes:</p>
559
560    <ul>
561      <li>ignore_addition(self, wildcard)</li>
562      <li>ignore_removal(self, wildcard)</li>
563      <li>ignore_modification(self, wildcard)</li>
564      <li>ignore_touch(self, wildcard)</li>
565    </ul>
566
567    <p>The method <tt>ignore(self, wildcard)</tt> ignores all the changes made
568    to files that match a wildcard.</p>
569
570    <h3><a name="methods-result">Methods for explicitly specifying results</a>
571    </h3>
572
573    <h4>Method <tt>pass_test(self, condition=1)</tt></h4>
574
575    <div class="attention">
576      At this moment, the method should not be used.
577    </div>
578
579    <h4>Method <tt>fail_test(self, condition=1)</tt></h4>
580
581    <p><b>Effects:</b> Cause the test to fail if <tt>condition</tt> is true.</p>
582
583    <h3><a name="class-list">Helper class <tt>List</tt></a></h3>
584    The class has sequence interface and two additional methods.
585
586    <h4>Method <tt>__init__(self, string)</tt></h4>
587
588    <p><b>Effects:</b> Splits the string on unescaped spaces and tabs. The split
589    components can further be retrieved using standard sequence access.</p>
590
591    <h4>Method <tt>__mul__(self, other)</tt></h4>
592
593    <p><b>Effects:</b> Returns an <tt>List</tt> instance, which elements are all
594    possible concatenations of two string, first of which is from <tt>self</tt>,
595    and second of which is from <tt>other</tt>.</p>
596
597    <p>The class also defines <tt>__str__</tt> and <tt>__repr__</tt> methods.
598    Finally, there's <tt>__coerce__</tt> method which allows to convert strings
599    to instances of <tt>List</tt>.</p>
600
601    <p><b>Example:</b></p>
602<pre>
603    l = "a b" * List("c d")
604    for e in l:
605        print e
606</pre>
607
608    <p>will output:</p>
609<pre>
610    ac
611    ad
612    bc
613    bd
614
615</pre>
616    <hr>
617    <p class="revision">Last modified: May 02, 2008</p>
618    <p>&copy; Copyright Vladimir Prus 2002, 2003, 2004, 2005.<br>
619    &copy; Copyright Jurko Gospodnetic 2008.<br>
620    Distributed under the Boost Software License, Version 1.0.
621    (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)</p>
622  </body>
623</html>
624