1#!/usr/local/bin/python3.8
2
3# Copyright 2008 Jurko Gospodnetic
4# Copyright 2017 Steven Watanabe
5# Distributed under the Boost Software License, Version 1.0.
6# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
7
8# Tests different aspects of Boost Builds automated testing support.
9
10import BoostBuild
11import TestCmd
12
13def test_run():
14    t = BoostBuild.Tester(use_test_config=False)
15
16    t.write("pass.cpp", "int main() {}\n")
17    t.write("fail-compile.cpp", "#error expected to fail\n")
18    t.write("fail-link.cpp", "int f();\nint main() { return f(); }\n")
19    t.write("fail-run.cpp", "int main() { return 1; }\n")
20
21    t.write("Jamroot.jam", """import testing ;
22run pass.cpp ;
23run fail-compile.cpp ;
24run fail-link.cpp ;
25run fail-run.cpp ;
26""")
27
28    t.run_build_system(status=1)
29    t.expect_addition("bin/pass.test/$toolset/debug*/pass.obj")
30    t.expect_addition("bin/pass.test/$toolset/debug*/pass.exe")
31    t.expect_addition("bin/pass.test/$toolset/debug*/pass.output")
32    t.expect_addition("bin/pass.test/$toolset/debug*/pass.run")
33    t.expect_addition("bin/pass.test/$toolset/debug*/pass.test")
34
35    t.expect_addition("bin/fail-link.test/$toolset/debug*/fail-link.obj")
36
37    t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.obj")
38    t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.exe")
39    t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.output")
40
41    t.ignore_addition("bin/pass.test/*/pass.rsp")
42    t.ignore_addition("bin/fail-link.test/*/fail-link.rsp")
43    t.ignore_addition("bin/fail-run.test/*/fail-run.rsp")
44
45    t.expect_nothing_more()
46
47    t.cleanup()
48
49def test_run_fail():
50    t = BoostBuild.Tester(use_test_config=False)
51
52    t.write("pass.cpp", "int main() {}\n")
53    t.write("fail-compile.cpp", "#error expected to fail\n")
54    t.write("fail-link.cpp", "int f();\nint main() { return f(); }\n")
55    t.write("fail-run.cpp", "int main() { return 1; }\n")
56
57    t.write("Jamroot.jam", """import testing ;
58run-fail pass.cpp ;
59run-fail fail-compile.cpp ;
60run-fail fail-link.cpp ;
61run-fail fail-run.cpp ;
62""")
63
64    t.run_build_system(status=1)
65    t.expect_addition("bin/pass.test/$toolset/debug*/pass.obj")
66    t.expect_addition("bin/pass.test/$toolset/debug*/pass.exe")
67    t.expect_addition("bin/pass.test/$toolset/debug*/pass.output")
68
69    t.expect_addition("bin/fail-link.test/$toolset/debug*/fail-link.obj")
70
71    t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.obj")
72    t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.exe")
73    t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.output")
74    t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.run")
75    t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.test")
76
77    t.ignore_addition("bin/pass.test/*/pass.rsp")
78    t.ignore_addition("bin/fail-link.test/*/fail-link.rsp")
79    t.ignore_addition("bin/fail-run.test/*/fail-run.rsp")
80
81    t.expect_nothing_more()
82
83    t.cleanup()
84
85def test_run_change():
86    """Tests that the test file is removed when a test fails after it
87    previously passed."""
88
89    t = BoostBuild.Tester(use_test_config=False)
90
91    t.write("pass.cpp", "int main() { return 1; }\n")
92    t.write("fail-compile.cpp", "int main() {}\n")
93    t.write("fail-link.cpp", "int main() {}\n")
94    t.write("fail-run.cpp", "int main() {}\n")
95
96    t.write("Jamroot.jam", """import testing ;
97run-fail pass.cpp ;
98run fail-compile.cpp ;
99run fail-link.cpp ;
100run fail-run.cpp ;
101""")
102    t.run_build_system()
103    # Sanity check
104    t.expect_addition("bin/pass.test/$toolset/debug*/pass.test")
105    t.expect_addition("bin/fail-compile.test/$toolset/debug*/fail-compile.test")
106    t.expect_addition("bin/fail-link.test/$toolset/debug*/fail-link.test")
107    t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.test")
108    t.expect_output_lines("...failed*", False)
109
110    # Now make them fail
111    t.write("pass.cpp", "int main() {}\n")
112    t.write("fail-compile.cpp", "#error expected to fail\n")
113    t.write("fail-link.cpp", "int f();\nint main() { return f(); }\n")
114    t.write("fail-run.cpp", "int main() { return 1; }\n")
115    t.run_build_system(status=1)
116
117    t.expect_removal("bin/pass.test/$toolset/debug*/pass.test")
118    t.expect_removal("bin/fail-compile.test/$toolset/debug*/fail-compile.test")
119    t.expect_removal("bin/fail-link.test/$toolset/debug*/fail-link.test")
120    t.expect_removal("bin/fail-run.test/$toolset/debug*/fail-run.test")
121
122    t.cleanup()
123
124def test_run_path():
125    """Tests that run can find shared libraries even without
126    hardcode-dll-paths.  Important: The library is in neither the
127    current working directory, nor any system path, nor the same
128    directory as the executable, so it should never be found without
129    help from B2."""
130    t = BoostBuild.Tester(["hardcode-dll-paths=false"], use_test_config=False)
131
132    t.write("l.cpp", """
133void
134#if defined(_WIN32)
135__declspec(dllexport)
136#endif
137f() {}
138""")
139    t.write("pass.cpp", "void f(); int main() { f(); }\n")
140
141    t.write("Jamroot.jam", """import testing ;
142lib l : l.cpp : <link>shared ;
143run pass.cpp l ;
144""")
145
146    t.run_build_system()
147    t.expect_addition("bin/$toolset/debug*/l.obj")
148    t.expect_addition("bin/$toolset/debug*/l.dll")
149    t.expect_addition("bin/pass.test/$toolset/debug*/pass.obj")
150    t.expect_addition("bin/pass.test/$toolset/debug*/pass.exe")
151    t.expect_addition("bin/pass.test/$toolset/debug*/pass.output")
152    t.expect_addition("bin/pass.test/$toolset/debug*/pass.run")
153    t.expect_addition("bin/pass.test/$toolset/debug*/pass.test")
154
155    t.cleanup()
156
157def test_run_args():
158    """Tests the handling of args and input-files"""
159    t = BoostBuild.Tester(use_test_config=False)
160    t.write("test.cpp", """
161#include <iostream>
162#include <fstream>
163int main(int argc, const char ** argv)
164{
165    for(int i = 1; i < argc; ++i)
166    {
167        if(argv[i][0] == '-')
168        {
169            std::cout << argv[i] << std::endl;
170        }
171        else
172        {
173            std::ifstream ifs(argv[i]);
174            std::cout << ifs.rdbuf();
175        }
176    }
177}
178""")
179    t.write("input1.in", "first input\n")
180    t.write("input2.in", "second input\n")
181    t.write("Jamroot.jam", """import testing ;
182import common ;
183# FIXME: The order actually depends on the lexigraphical
184# ordering of the virtual target objects, which is just
185# crazy.  Switch the order of input1.txt and input2.txt
186# to make this fail.  Joining the arguments with && might
187# work, but might get a bit complicated to implement as
188# dependency properties do not currently support &&.
189make input1.txt : input1.in : @common.copy ;
190make input2.txt : input2.in : @common.copy ;
191run test.cpp : -y -a : input1.txt input2.txt ;
192""")
193    t.run_build_system()
194    t.expect_content("bin/test.test/$toolset/debug*/test.output", """\
195-y
196-a
197first input
198second input
199
200EXIT STATUS: 0
201""")
202    t.cleanup()
203
204def test_link():
205    t = BoostBuild.Tester(use_test_config=False)
206
207    t.write("pass.cpp", "int main() {}\n")
208    t.write("fail-compile.cpp", "#error expected to fail\n")
209    t.write("fail-link.cpp", "int f();\nint main() { return f(); }\n")
210    t.write("fail-run.cpp", "int main() { return 1; }\n")
211
212    t.write("Jamroot.jam", """import testing ;
213link pass.cpp ;
214link fail-compile.cpp ;
215link fail-link.cpp ;
216link fail-run.cpp ;
217""")
218
219    t.run_build_system(status=1)
220    t.expect_addition("bin/pass.test/$toolset/debug*/pass.obj")
221    t.expect_addition("bin/pass.test/$toolset/debug*/pass.exe")
222    t.expect_addition("bin/pass.test/$toolset/debug*/pass.test")
223
224    t.expect_addition("bin/fail-link.test/$toolset/debug*/fail-link.obj")
225
226    t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.obj")
227    t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.exe")
228    t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.test")
229
230    t.ignore_addition("bin/pass.test/*/pass.rsp")
231    t.ignore_addition("bin/fail-link.test/*/fail-link.rsp")
232    t.ignore_addition("bin/fail-run.test/*/fail-run.rsp")
233
234    t.expect_nothing_more()
235
236    t.cleanup()
237
238def test_link_fail():
239    t = BoostBuild.Tester(use_test_config=False)
240
241    t.write("pass.cpp", "int main() {}\n")
242    t.write("fail-compile.cpp", "#error expected to fail\n")
243    t.write("fail-link.cpp", "int f();\nint main() { return f(); }\n")
244    t.write("fail-run.cpp", "int main() { return 1; }\n")
245
246    t.write("Jamroot.jam", """import testing ;
247link-fail pass.cpp ;
248link-fail fail-compile.cpp ;
249link-fail fail-link.cpp ;
250link-fail fail-run.cpp ;
251""")
252
253    t.run_build_system(status=1)
254    t.expect_addition("bin/pass.test/$toolset/debug*/pass.obj")
255
256    t.expect_addition("bin/fail-link.test/$toolset/debug*/fail-link.obj")
257    t.expect_addition("bin/fail-link.test/$toolset/debug*/fail-link.exe")
258    t.expect_addition("bin/fail-link.test/$toolset/debug*/fail-link.test")
259
260    t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.obj")
261
262    t.ignore_addition("bin/pass.test/*/pass.rsp")
263    t.ignore_addition("bin/fail-link.test/*/fail-link.rsp")
264    t.ignore_addition("bin/fail-run.test/*/fail-run.rsp")
265
266    t.expect_nothing_more()
267
268    t.cleanup()
269
270def test_link_change():
271    """Tests that the test file is removed when a test fails after it
272    previously passed."""
273
274    t = BoostBuild.Tester(use_test_config=False)
275
276    t.write("pass.cpp", "int f();\nint main() { return f(); }\n")
277    t.write("fail-compile.cpp", "int main() {}\n")
278    t.write("fail-link.cpp", "int main() {}\n")
279
280    t.write("Jamroot.jam", """import testing ;
281link-fail pass.cpp ;
282link fail-compile.cpp ;
283link fail-link.cpp ;
284""")
285    t.run_build_system()
286    # Sanity check
287    t.expect_addition("bin/pass.test/$toolset/debug*/pass.test")
288    t.expect_addition("bin/fail-compile.test/$toolset/debug*/fail-compile.test")
289    t.expect_addition("bin/fail-link.test/$toolset/debug*/fail-link.test")
290    t.expect_output_lines("...failed*", False)
291
292    # Now make them fail
293    t.write("pass.cpp", "int main() {}\n")
294    t.write("fail-compile.cpp", "#error expected to fail\n")
295    t.write("fail-link.cpp", "int f();\nint main() { return f(); }\n")
296    t.run_build_system(status=1)
297
298    t.expect_removal("bin/pass.test/$toolset/debug*/pass.test")
299    t.expect_removal("bin/fail-compile.test/$toolset/debug*/fail-compile.test")
300    t.expect_removal("bin/fail-link.test/$toolset/debug*/fail-link.test")
301
302    t.cleanup()
303
304def test_compile():
305    t = BoostBuild.Tester(use_test_config=False)
306
307    t.write("pass.cpp", "int main() {}\n")
308    t.write("fail-compile.cpp", "#error expected to fail\n")
309    t.write("fail-link.cpp", "int f();\nint main() { return f(); }\n")
310    t.write("fail-run.cpp", "int main() { return 1; }\n")
311
312    t.write("Jamroot.jam", """import testing ;
313compile pass.cpp ;
314compile fail-compile.cpp ;
315compile fail-link.cpp ;
316compile fail-run.cpp ;
317""")
318
319    t.run_build_system(status=1)
320    t.expect_addition("bin/pass.test/$toolset/debug*/pass.obj")
321    t.expect_addition("bin/pass.test/$toolset/debug*/pass.test")
322
323    t.expect_addition("bin/fail-link.test/$toolset/debug*/fail-link.obj")
324    t.expect_addition("bin/fail-link.test/$toolset/debug*/fail-link.test")
325
326    t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.obj")
327    t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.test")
328
329    t.expect_nothing_more()
330
331    t.cleanup()
332
333def test_compile_fail():
334    t = BoostBuild.Tester(use_test_config=False)
335
336    t.write("pass.cpp", "int main() {}\n")
337    t.write("fail-compile.cpp", "#error expected to fail\n")
338    t.write("fail-link.cpp", "int f();\nint main() { return f(); }\n")
339    t.write("fail-run.cpp", "int main() { return 1; }\n")
340
341    t.write("Jamroot.jam", """import testing ;
342compile-fail pass.cpp ;
343compile-fail fail-compile.cpp ;
344compile-fail fail-link.cpp ;
345compile-fail fail-run.cpp ;
346""")
347
348    t.run_build_system(status=1)
349    t.expect_addition("bin/fail-compile.test/$toolset/debug*/fail-compile.obj")
350    t.expect_addition("bin/fail-compile.test/$toolset/debug*/fail-compile.test")
351
352    t.expect_nothing_more()
353
354    t.cleanup()
355
356def test_compile_change():
357    """Tests that the test file is removed when a test fails after it
358    previously passed."""
359
360    t = BoostBuild.Tester(use_test_config=False)
361
362    t.write("pass.cpp", "#error expected to fail\n")
363    t.write("fail-compile.cpp", "int main() {}\n")
364
365    t.write("Jamroot.jam", """import testing ;
366compile-fail pass.cpp ;
367compile fail-compile.cpp ;
368""")
369    t.run_build_system()
370    # Sanity check
371    t.expect_addition("bin/pass.test/$toolset/debug*/pass.test")
372    t.expect_addition("bin/fail-compile.test/$toolset/debug*/fail-compile.test")
373    t.expect_output_lines("...failed*", False)
374
375    # Now make them fail
376    t.write("pass.cpp", "int main() {}\n")
377    t.write("fail-compile.cpp", "#error expected to fail\n")
378    t.run_build_system(status=1)
379
380    t.expect_removal("bin/pass.test/$toolset/debug*/pass.test")
381    t.expect_removal("bin/fail-compile.test/$toolset/debug*/fail-compile.test")
382
383    t.cleanup()
384
385def test_remove_test_targets(option):
386    t = BoostBuild.Tester(use_test_config=False)
387
388    t.write("pass-compile.cpp", "int main() {}\n")
389    t.write("pass-link.cpp", "int main() {}\n")
390    t.write("pass-run.cpp", "int main() {}\n")
391    t.write("fail-compile.cpp", "#error expected to fail\n")
392    t.write("fail-link.cpp", "int f();\nint main() { return f(); }\n")
393    t.write("fail-run.cpp", "int main() { return 1; }\n")
394    t.write("source.cpp", "int f();\n")
395
396    t.write("Jamroot.jam", """import testing ;
397obj source.o : source.cpp ;
398compile pass-compile.cpp ;
399link pass-link.cpp source.o ;
400run pass-run.cpp source.o ;
401compile-fail fail-compile.cpp ;
402link-fail fail-link.cpp ;
403run-fail fail-run.cpp ;
404""")
405
406    t.run_build_system([option])
407
408    t.expect_addition("bin/$toolset/debug*/source.obj")
409
410    t.expect_addition("bin/pass-compile.test/$toolset/debug*/pass-compile.test")
411
412    t.expect_addition("bin/pass-link.test/$toolset/debug*/pass-link.test")
413
414    t.expect_addition("bin/pass-run.test/$toolset/debug*/pass-run.output")
415    t.expect_addition("bin/pass-run.test/$toolset/debug*/pass-run.run")
416    t.expect_addition("bin/pass-run.test/$toolset/debug*/pass-run.test")
417
418    t.expect_addition("bin/fail-compile.test/$toolset/debug*/fail-compile.test")
419
420    t.expect_addition("bin/fail-link.test/$toolset/debug*/fail-link.test")
421
422    t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.output")
423    t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.run")
424    t.expect_addition("bin/fail-run.test/$toolset/debug*/fail-run.test")
425
426    t.ignore_addition("bin/pass-link.test/*/pass-link.rsp")
427    t.ignore_addition("bin/pass-run.test/*/pass-run.rsp")
428    t.ignore_addition("bin/fail-link.test/*/fail-link.rsp")
429    t.ignore_addition("bin/fail-run.test/*/fail-run.rsp")
430
431    t.expect_nothing_more()
432
433    t.cleanup()
434
435def test_dump_tests():
436    """Tests the output of the --dump-tests option"""
437    t = BoostBuild.Tester(use_test_config=False)
438
439    t.write("pass-compile.cpp", "int main() {}\n")
440    t.write("pass-link.cpp", "int main() {}\n")
441    t.write("pass-run.cpp", "int main() {}\n")
442    t.write("fail-compile.cpp", "#error expected to fail\n")
443    t.write("fail-link.cpp", "int f();\nint main() { return f(); }\n")
444    t.write("fail-run.cpp", "int main() { return 1; }\n")
445
446    t.write("Jamroot.jam", """import testing ;
447run pass-run.cpp ;
448run-fail fail-run.cpp ;
449link pass-link.cpp ;
450link-fail fail-link.cpp ;
451compile pass-compile.cpp ;
452compile-fail fail-compile.cpp ;
453build-project libs/any/test ;
454build-project libs/any/example ;
455build-project libs/any ;
456build-project tools/bcp/test ;
457build-project tools/bcp/example ;
458build-project subdir/test ;
459build-project status ;
460build-project outside/project ;
461""")
462    def write_subdir(dir):
463        t.write(dir + "/test.cpp", "int main() {}\n")
464        t.write(dir + "/Jamfile", "run test.cpp ;")
465    write_subdir("libs/any/test")
466    write_subdir("libs/any/example")
467    write_subdir("libs/any")
468    write_subdir("tools/bcp/test")
469    write_subdir("tools/bcp/example")
470    write_subdir("status")
471    write_subdir("subdir/test")
472    t.write("outside/other/test.cpp", "int main() {}\n")
473    t.write("outside/project/Jamroot", "run ../other/test.cpp ;")
474    t.run_build_system(["--dump-tests", "-n", "-d0"],
475                       match=TestCmd.match_re, stdout=
476"""boost-test\(RUN\) ".*/pass-run" : "pass-run\.cpp"
477boost-test\(RUN_FAIL\) ".*/fail-run" : "fail-run\.cpp"
478boost-test\(LINK\) ".*/pass-link" : "pass-link\.cpp"
479boost-test\(LINK_FAIL\) ".*/fail-link" : "fail-link\.cpp"
480boost-test\(COMPILE\) ".*/pass-compile" : "pass-compile\.cpp"
481boost-test\(COMPILE_FAIL\) ".*/fail-compile" : "fail-compile\.cpp"
482boost-test\(RUN\) "any/test" : "libs/any/test\.cpp"
483boost-test\(RUN\) "any/test" : "libs/any/test/test\.cpp"
484boost-test\(RUN\) "any/test" : "libs/any/example/test\.cpp"
485boost-test\(RUN\) "bcp/test" : "tools/bcp/test/test\.cpp"
486boost-test\(RUN\) "bcp/test" : "tools/bcp/example/test\.cpp"
487boost-test\(RUN\) ".*/subdir/test/test" : "subdir/test/test\.cpp"
488boost-test\(RUN\) "test" : "status/test\.cpp"
489boost-test\(RUN\) ".*/outside/project/test" : "../other/test.cpp"
490""")
491    t.cleanup()
492
493################################################################################
494#
495# test_files_with_spaces_in_their_name()
496# --------------------------------------
497#
498################################################################################
499
500def test_files_with_spaces_in_their_name():
501    """Regression test making sure test result files get created correctly when
502    testing files with spaces in their name.
503    """
504
505    t = BoostBuild.Tester(use_test_config=False)
506
507    t.write("valid source.cpp", "int main() {}\n");
508
509    t.write("invalid source.cpp", "this is not valid source code");
510
511    t.write("jamroot.jam", """
512import testing ;
513testing.compile "valid source.cpp" ;
514testing.compile-fail "invalid source.cpp" ;
515""")
516
517    t.run_build_system(status=0)
518    t.expect_addition("bin/invalid source.test/$toolset/debug*/invalid source.obj")
519    t.expect_addition("bin/invalid source.test/$toolset/debug*/invalid source.test")
520    t.expect_addition("bin/valid source.test/$toolset/debug*/valid source.obj")
521    t.expect_addition("bin/valid source.test/$toolset/debug*/valid source.test")
522
523    t.expect_content("bin/valid source.test/$toolset/debug*/valid source.test", \
524        "passed" )
525    t.expect_content( \
526        "bin/invalid source.test/$toolset/debug*/invalid source.test", \
527        "passed" )
528    t.expect_content( \
529        "bin/invalid source.test/$toolset/debug*/invalid source.obj", \
530        "failed as expected" )
531
532    t.cleanup()
533
534
535################################################################################
536#
537# main()
538# ------
539#
540################################################################################
541
542test_run()
543test_run_fail()
544test_run_change()
545test_run_path()
546test_run_args()
547test_link()
548test_link_fail()
549test_link_change()
550test_compile()
551test_compile_fail()
552test_compile_change()
553test_remove_test_targets("--remove-test-targets")
554test_remove_test_targets("preserve-test-targets=off")
555test_dump_tests()
556test_files_with_spaces_in_their_name()
557