def check_for_existing_boost_build_jam(t): """ This test depends on no boost-build.jam file existing in any of the folders along the current folder's path. If it does exist, not only would this test fail but it could point to a completely wrong Boost Build installation, thus causing headaches when attempting to diagnose the problem. That is why we explicitly check for this scenario. """ problem = find_up_to_root(t.workdir, "boost-build.jam") if problem: BoostBuild.annotation( "misconfiguration", """\ This test expects to be run from a folder with no 'boost-build.jam' file in any of the folders along its path. Working folder: '%s' Problematic boost-build.jam found at: '%s' Please remove this file or change the test's working folder and rerun the test. """ % (t.workdir, problem)) t.fail_test(1, dump_stdio=False, dump_stack=False)
def test_raw_empty(): whitespace_in = " \n\n\r\r\v\v\t\t \t \r\r \n\n" # We tell the testing system to read its child process output as raw # binary data but the bjam process we run will read its input file and # write out its output as text, i.e. convert all of our "\r\n" sequences to # "\n" on input and all of its "\n" characters back to "\r\n" on output. # This means that any lone "\n" input characters not preceded by "\r" will # get an extra "\r" added in front of it on output. whitespace_out = whitespace_in.replace("\r\n", "\n").replace("\n", "\r\n") t = BoostBuild.Tester(["-d2", "-d+4"], pass_toolset=0, use_test_config=False) t.write( "file.jam", """\ actions do_empty {%s} JAMSHELL = %% ; do_empty all ; """ % (whitespace_in)) t.run_build_system(["-ffile.jam"], universal_newlines=False) t.expect_output_lines("do_empty all") t.expect_output_lines("Executing raw command directly", False) if "\r\n%s\r\n" % whitespace_out not in t.stdout(): BoostBuild.annotation( "failure", "Whitespace action content not found " "on stdout.") t.fail_test(1, dump_difference=False) t.cleanup()
def test_raw_empty(): whitespace_in = " \n\n\r\r\v\v\t\t \t \r\r \n\n" # We tell the testing system to read its child process output as raw # binary data but the bjam process we run will read its input file and # write out its output as text, i.e. convert all of our "\r\n" sequences to # "\n" on input and all of its "\n" characters back to "\r\n" on output. # This means that any lone "\n" input characters not preceded by "\r" will # get an extra "\r" added in front of it on output. whitespace_out = whitespace_in.replace("\r\n", "\n").replace("\n", "\r\n") t = BoostBuild.Tester(["-d2", "-d+4"], pass_d0=False, pass_toolset=0, use_test_config=False) t.write("file.jam", """\ actions do_empty {%s} JAMSHELL = %% ; do_empty all ; """ % (whitespace_in)) t.run_build_system(["-ffile.jam"], universal_newlines=False) t.expect_output_lines("do_empty all") t.expect_output_lines("Executing raw command directly", False) if "\r\n%s\r\n" % whitespace_out not in t.stdout(): BoostBuild.annotation("failure", "Whitespace action content not found " "on stdout.") t.fail_test(1, dump_difference=False) t.cleanup()
def check_for_existing_boost_build_jam(t): """ This test depends on no boost-build.jam file existing in any of the folders along the current folder's path. If it does exist, not only would this test fail but it could point to a completely wrong Boost Build installation, thus causing headaches when attempting to diagnose the problem. That is why we explicitly check for this scenario. """ problem = find_up_to_root(t.workdir, "boost-build.jam") if problem: BoostBuild.annotation("misconfiguration", """\ This test expects to be run from a folder with no 'boost-build.jam' file in any of the folders along its path. Working folder: '%s' Problematic boost-build.jam found at: '%s' Please remove this file or change the test's working folder and rerun the test. """ % (t.workdir, problem)) t.fail_test(1, dump_stdio=False, dump_stack=False)
#ifdef ERROR #error ERROR defined #endif #ifndef OK #error ERROR not defined #endif ''') # Don't check the status immediately, so that we have a chance # to print config.log. Also, we need a minimum of d2 to make # sure that we always see the commands and output. t.run_build_system(['-sOBJECT_FILE=' + linker_input, '-d2'], status=None) if t.status != 0: log_file = t.read('bin/config.log') BoostBuild.annotation("config.log", log_file) t.fail_test(True) t.expect_output_lines([' - has --illegal-flag-cpp : no*', ' - has -DMACRO_CPP : yes*', ' - has --illegal-flag-c : no*', ' - has -DMACRO_C : yes*', ' - has --illegal-flag-link : no*', ' - has *bin*/input.* : yes*']) t.expect_addition('bin/$toolset/debug*/fail_cpp.obj') t.expect_addition('bin/$toolset/debug*/pass_cpp.obj') t.expect_addition('bin/$toolset/debug*/fail_c.obj') t.expect_addition('bin/$toolset/debug*/pass_c.obj') t.expect_addition('bin/$toolset/debug*/fail_link.obj') t.expect_addition('bin/$toolset/debug*/pass_link.obj')
def _info(*values): values = list(values) + [""] BoostBuild.annotation(tag, "\n".join(str(x) for x in values))
typedef void type; }; typedef time_waster<true, 10, void>::type type; int g() { return 0; } """) tester.write("jamroot.jam", """\ obj test2 : test2.cpp ; obj test1 : test1.cpp : <dependency>test2 ; install test2i : test2 : <dependency>test1 ; """) tester.run_build_system() tester.expect_addition("bin/$toolset/debug*/test2.obj") tester.expect_addition("bin/$toolset/debug*/test1.obj") tester.expect_addition("test2i/test2.obj") tester.expect_nothing_more() test2src = tester.read("test2i/test2.obj") test2dest = tester.read("bin/$toolset/debug*/test2.obj") if test2src != test2dest: BoostBuild.annotation("failure", "The object file was not copied " "correctly") tester.fail_test(1) tester.run_build_system(["-d1"]) tester.expect_output_lines("common.copy*", False) tester.expect_nothing_more() tester.cleanup()
def test_raw_nt(n=None, error=False): t = BoostBuild.Tester(["-d1", "-d+4"], pass_d0=False, pass_toolset=0, use_test_config=False) cmd_prefix = "%s -c \"print('XXX: " % executable cmd_suffix = "')\"" cmd_extra_length = len(cmd_prefix) + len(cmd_suffix) if n == None: n = cmd_extra_length data_length = n - cmd_extra_length if data_length < 0: BoostBuild.annotation("failure", """\ Can not construct Windows command of desired length. Requested command length too short for the current test configuration. Requested command length: %d Minimal supported command length: %d """ % (n, cmd_extra_length)) t.fail_test(1, dump_difference=False) # Each $(Xx10-1) variable contains X words of 9 characters each, which, # including spaces between words, brings the total number of characters in # its string representation to X * 10 - 1 (X * 9 characters + (X - 1) # spaces). t.write("file.jam", """\ ten = 0 1 2 3 4 5 6 7 8 9 ; 1x10-1 = 123456789 ; 10x10-1 = $(ten)12345678 ; 100x10-1 = $(ten)$(ten)1234567 ; 1000x10-1 = $(ten)$(ten)$(ten)123456 ; actions do_echo { %s%s%s } JAMSHELL = %% ; do_echo all ; """ % (cmd_prefix, string_of_length(data_length), cmd_suffix)) if error: expected_status = 1 else: expected_status = 0 t.run_build_system(["-ffile.jam"], status=expected_status) if error: t.expect_output_lines("Executing raw command directly", False) t.expect_output_lines("do_echo action is too long (%d, max 32766):" % n ) t.expect_output_lines("XXX: *", False) else: t.expect_output_lines("Executing raw command directly") t.expect_output_lines("do_echo action is too long*", False) m = re.search("^XXX: (.*)$", t.stdout(), re.MULTILINE) if not m: BoostBuild.annotation("failure", "Expected output line starting " "with 'XXX: ' not found.") t.fail_test(1, dump_difference=False) if len(m.group(1)) != data_length: BoostBuild.annotation("failure", """Unexpected output data length. Expected: %d Received: %d""" % (n, len(m.group(1)))) t.fail_test(1, dump_difference=False) t.cleanup()
def __assertionFailure(self, message): BoostBuild.annotation("failure", "Internal test assertion failure " "- %s" % message) self.__tester.fail_test(1)
def test_basic(): t = BoostBuild.Tester(pass_d0=False) __write_appender(t, "appender.jam") t.write("a.cpp", "") t.write("b.cxx", "") t.write("c.tui", "") t.write("d.wd", "") t.write("e.cpp", "") t.write("x.l", "") t.write("y.x_pro", "") t.write("z.cpp", "") t.write("lib/c.cpp", "int bar() { return 0; }\n") t.write("lib/jamfile.jam", "my-lib auxilliary : c.cpp ;") t.write( "jamroot.jam", r"""import appender ; import "class" : new ; import generators ; import type ; ################################################################################ # # We use our own custom EXE, LIB & OBJ target generators as using the regular # ones would force us to have to deal with different compiler/linker specific # 'features' that really have nothing to do with this test. For example, IBM XL # C/C++ for AIX, V12.1 (Version: 12.01.0000.0000) compiler exits with a non-zero # exit code and thus fails our build when run with a source file using an # unknown suffix like '.marked_cpp'. # ################################################################################ type.register MY_EXE : my_exe ; type.register MY_LIB : my_lib ; type.register MY_OBJ : my_obj ; appender.register compile-c : C : MY_OBJ ; appender.register compile-cpp : CPP : MY_OBJ ; appender.register link-lib composing : MY_OBJ : MY_LIB ; appender.register link-exe composing : MY_OBJ MY_LIB : MY_EXE ; ################################################################################ # # LEX --> C # ################################################################################ type.register LEX : l ; appender.register lex-to-c : LEX : C ; ################################################################################ # # /--> tUI_H --\ # tUI --< >--> CPP # \------------/ # ################################################################################ type.register tUI : tui ; type.register tUI_H : tui_h ; appender.register ui-to-cpp : tUI tUI_H : CPP ; appender.register ui-to-h : tUI : tUI_H ; ################################################################################ # # /--> X1 --\ # X_PRO --< >--> CPP # \--> X2 --/ # ################################################################################ type.register X1 : x1 ; type.register X2 : x2 ; type.register X_PRO : x_pro ; appender.register x1-x2-to-cpp : X1 X2 : CPP ; appender.register x-pro-to-x1-x2 : X_PRO : X1 X2 ; ################################################################################ # # When the main target type is NM_EXE, build OBJ from CPP-MARKED and not from # anything else, e.g. directly from CPP. # ################################################################################ type.register CPP_MARKED : marked_cpp : CPP ; type.register POSITIONS : positions ; type.register NM.TARGET.CPP : target_cpp : CPP ; type.register NM_EXE : : MY_EXE ; appender.register marked-to-target-cpp : CPP_MARKED : NM.TARGET.CPP ; appender.register cpp-to-marked-positions : CPP : CPP_MARKED POSITIONS ; class nm::target::cpp-obj-generator : generator { rule __init__ ( id ) { generator.__init__ $(id) : NM.TARGET.CPP : MY_OBJ ; generator.set-rule-name appender.appender ; } rule requirements ( ) { return <main-target-type>NM_EXE ; } rule run ( project name ? : properties * : source : multiple ? ) { if [ $(source).type ] = CPP { local converted = [ generators.construct $(project) : NM.TARGET.CPP : $(properties) : $(source) ] ; if $(converted) { return [ generators.construct $(project) : MY_OBJ : $(properties) : $(converted[2]) ] ; } } } } generators.register [ new nm::target::cpp-obj-generator target-obj ] ; generators.override target-obj : all ; ################################################################################ # # A more complex test case scenario with the following generators: # 1. WHL --> CPP, WHL_LR0, H, H(%_symbols) # 2. DLP --> CPP # 3. WD --> WHL(%_parser) DLP(%_lexer) # 4. A custom generator of higher priority than generators 1. & 2. that helps # disambiguate between them when generating CPP files from WHL and DLP # sources. # ################################################################################ type.register WHL : whl ; type.register DLP : dlp ; type.register WHL_LR0 : lr0 ; type.register WD : wd ; local whale-generator-id = [ appender.register whale : WHL : CPP WHL_LR0 H H(%_symbols) ] ; local dolphin-generator-id = [ appender.register dolphin : DLP : CPP ] ; appender.register wd : WD : WHL(%_parser) DLP(%_lexer) ; class wd-to-cpp : generator { rule __init__ ( id : sources * : targets * ) { generator.__init__ $(id) : $(sources) : $(targets) ; } rule run ( project name ? : property-set : source ) { local new-sources = $(source) ; if ! [ $(source).type ] in WHL DLP { local r1 = [ generators.construct $(project) $(name) : WHL : $(property-set) : $(source) ] ; local r2 = [ generators.construct $(project) $(name) : DLP : $(property-set) : $(source) ] ; new-sources = [ sequence.unique $(r1[2-]) $(r2[2-]) ] ; } local result ; for local i in $(new-sources) { local t = [ generators.construct $(project) $(name) : CPP : $(property-set) : $(i) ] ; result += $(t[2-]) ; } return $(result) ; } } generators.override $(__name__).wd-to-cpp : $(whale-generator-id) ; generators.override $(__name__).wd-to-cpp : $(dolphin-generator-id) ; generators.register [ new wd-to-cpp $(__name__).wd-to-cpp : : CPP ] ; ################################################################################ # # Declare build targets. # ################################################################################ # This should not cause two CPP --> MY_OBJ constructions for a.cpp or b.cpp. my-exe a : a.cpp b.cxx obj_1 obj_2 c.tui d.wd x.l y.x_pro lib//auxilliary ; my-exe f : a.cpp b.cxx obj_1 obj_2 lib//auxilliary ; # This should cause two CPP --> MY_OBJ constructions for z.cpp. my-obj obj_1 : z.cpp ; my-obj obj_2 : z.cpp ; nm-exe e : e.cpp ; """) t.run_build_system() t.expect_addition("bin/$toolset/debug/" * BoostBuild.List( "a.my_exe " "a.my_obj b.my_obj c.tui_h c.cpp c.my_obj d_parser.whl d_lexer.dlp " "d_parser.cpp d_lexer.cpp d_lexer.my_obj d_parser.lr0 d_parser.h " "d_parser.my_obj d_parser_symbols.h x.c x.my_obj y.x1 y.x2 y.cpp " "y.my_obj e.marked_cpp e.positions e.target_cpp e.my_obj e.my_exe " "f.my_exe obj_1.my_obj obj_2.my_obj")) t.expect_addition("lib/bin/$toolset/debug/" * BoostBuild.List("c.my_obj " "auxilliary.my_lib")) t.expect_nothing_more() folder = "bin/$toolset/debug" t.expect_content_lines("%s/obj_1.my_obj" % folder, " Sources: 'z.cpp'") t.expect_content_lines("%s/obj_2.my_obj" % folder, " Sources: 'z.cpp'") t.expect_content_lines("%s/a.my_obj" % folder, " Sources: 'a.cpp'") lines = t.stdout().splitlines() source_lines = [x for x in lines if re.match("^ Sources: '", x)] if not __match_count_is(source_lines, "'z.cpp'", 2): BoostBuild.annotation("failure", "z.cpp must be compiled exactly " "twice.") t.fail_test(1) if not __match_count_is(source_lines, "'a.cpp'", 1): BoostBuild.annotation("failure", "a.cpp must be compiled exactly " "once.") t.fail_test(1) t.cleanup()
def run_tests(critical_tests, other_tests): """ Runs first the critical_tests and then the other_tests. Writes the name of the first failed test to test_results.txt. Critical tests are run in the specified order, other tests are run starting with the one that failed first on the last test run. """ last_failed = last_failed_test() other_tests = reorder_tests(other_tests, last_failed) all_tests = critical_tests + other_tests invocation_dir = os.getcwd() max_test_name_len = 10 for x in all_tests: if len(x) > max_test_name_len: max_test_name_len = len(x) pass_count = 0 failures_count = 0 for test in all_tests: if not xml: print ("%%-%ds :" % max_test_name_len % test), passed = 0 try: __import__(test) passed = 1 except KeyboardInterrupt: """This allows us to abort the testing manually using Ctrl-C.""" raise except SystemExit: """This is the regular way our test scripts are supposed to report test failures.""" except: exc_type, exc_value, exc_tb = sys.exc_info() try: BoostBuild.annotation("failure - unhandled exception", "%s - " "%s" % (exc_type.__name__, exc_value)) BoostBuild.annotate_stack_trace(exc_tb) finally: # Explicitly clear a hard-to-garbage-collect traceback # related reference cycle as per documented sys.exc_info() # usage suggestion. del exc_tb if passed: pass_count += 1 else: failures_count += 1 if failures_count == 1: f = open(os.path.join(invocation_dir, "test_results.txt"), "w") try: f.write(test) finally: f.close() # Restore the current directory, which might have been changed by the # test. os.chdir(invocation_dir) if not xml: if passed: print ("PASSED") else: print ("FAILED") else: rs = "succeed" if not passed: rs = "fail" print """ <test-log library="build" test-name="%s" test-type="run" toolset="%s" test-program="%s" target-directory="%s"> <run result="%s">""" % ( test, toolset, "tools/build/v2/test/" + test + ".py", "boost/bin.v2/boost.build.tests/" + toolset + "/" + test, rs, ) if not passed: BoostBuild.flush_annotations(1) print """ </run> </test-log> """ sys.stdout.flush() # Makes testing under emacs more entertaining. BoostBuild.clear_annotations() # Erase the file on success. if failures_count == 0: open("test_results.txt", "w").close() if not xml: print """ === Test summary === PASS: %d FAIL: %d """ % ( pass_count, failures_count, )
def run_tests(critical_tests, other_tests): """ Runs first the critical_tests and then the other_tests. Writes the name of the first failed test to test_results.txt. Critical tests are run in the specified order, other tests are run starting with the one that failed first on the last test run. """ last_failed = last_failed_test() other_tests = reorder_tests(other_tests, last_failed) all_tests = critical_tests + other_tests invocation_dir = os.getcwd() max_test_name_len = 10 for x in all_tests: if len(x) > max_test_name_len: max_test_name_len = len(x) pass_count = 0 failures_count = 0 for test in all_tests: if not xml: print("%%-%ds :" % max_test_name_len % test), passed = 0 try: __import__(test) passed = 1 except KeyboardInterrupt: """This allows us to abort the testing manually using Ctrl-C.""" raise except SystemExit: """This is the regular way our test scripts are supposed to report test failures.""" except: exc_type, exc_value, exc_tb = sys.exc_info() try: BoostBuild.annotation( "failure - unhandled exception", "%s - " "%s" % (exc_type.__name__, exc_value)) BoostBuild.annotate_stack_trace(exc_tb) finally: # Explicitly clear a hard-to-garbage-collect traceback # related reference cycle as per documented sys.exc_info() # usage suggestion. del exc_tb if passed: pass_count += 1 else: failures_count += 1 if failures_count == 1: f = open(os.path.join(invocation_dir, "test_results.txt"), "w") try: f.write(test) finally: f.close() # Restore the current directory, which might have been changed by the # test. os.chdir(invocation_dir) if not xml: if passed: print("PASSED") else: print("FAILED") BoostBuild.flush_annotations() else: rs = "succeed" if not passed: rs = "fail" print """ <test-log library="build" test-name="%s" test-type="run" toolset="%s" test-program="%s" target-directory="%s"> <run result="%s">""" % (test, toolset, "tools/build/v2/test/" + test + ".py", "boost/bin.v2/boost.build.tests/" + toolset + "/" + test, rs) if not passed: BoostBuild.flush_annotations(1) print """ </run> </test-log> """ sys.stdout.flush() # Makes testing under emacs more entertaining. BoostBuild.clear_annotations() # Erase the file on success. if failures_count == 0: open("test_results.txt", "w").close() if not xml: print """ === Test summary === PASS: %d FAIL: %d """ % (pass_count, failures_count) # exit with failure with failures if failures_count > 0: sys.exit(1)
tester.write( "jamroot.jam", """ obj test2 : test2.cpp ; obj test1 : test1.cpp : <dependency>test2 ; install test2i : test2 : <dependency>test1 ; """) tester.run_build_system() tester.expect_addition("bin/$toolset/debug/test2.obj") tester.expect_addition("bin/$toolset/debug/test1.obj") tester.expect_addition("test2i/test2.obj") tester.expect_nothing_more() test2src = tester.read("test2i/test2.obj") test2dest = tester.read("bin/$toolset/debug/test2.obj") if test2src != test2dest: BoostBuild.annotation("failure", "The object file was not copied correctly") tester.fail_test(1) del test2src del test2dest tester.run_build_system("-d1") tester.expect_output_line("common.copy*", expected_to_exist=False) tester.expect_nothing_more() tester.cleanup()
def test_basic(): t = BoostBuild.Tester(pass_d0=False) __write_appender(t, "appender.jam") t.write("a.cpp", "") t.write("b.cxx", "") t.write("c.tui", "") t.write("d.wd", "") t.write("e.cpp", "") t.write("x.l", "") t.write("y.x_pro", "") t.write("z.cpp", "") t.write("lib/c.cpp", "int bar() { return 0; }\n") t.write("lib/jamfile.jam", "my-lib auxilliary : c.cpp ;") t.write("jamroot.jam", r"""import appender ; import "class" : new ; import generators ; import type ; ################################################################################ # # We use our own custom EXE, LIB & OBJ target generators as using the regular # ones would force us to have to deal with different compiler/linker specific # 'features' that really have nothing to do with this test. For example, IBM XL # C/C++ for AIX, V12.1 (Version: 12.01.0000.0000) compiler exits with a non-zero # exit code and thus fails our build when run with a source file using an # unknown suffix like '.marked_cpp'. # ################################################################################ type.register MY_EXE : my_exe ; type.register MY_LIB : my_lib ; type.register MY_OBJ : my_obj ; appender.register compile-c : C : MY_OBJ ; appender.register compile-cpp : CPP : MY_OBJ ; appender.register link-lib composing : MY_OBJ : MY_LIB ; appender.register link-exe composing : MY_OBJ MY_LIB : MY_EXE ; ################################################################################ # # LEX --> C # ################################################################################ type.register LEX : l ; appender.register lex-to-c : LEX : C ; ################################################################################ # # /--> tUI_H --\ # tUI --< >--> CPP # \------------/ # ################################################################################ type.register tUI : tui ; type.register tUI_H : tui_h ; appender.register ui-to-cpp : tUI tUI_H : CPP ; appender.register ui-to-h : tUI : tUI_H ; ################################################################################ # # /--> X1 --\ # X_PRO --< >--> CPP # \--> X2 --/ # ################################################################################ type.register X1 : x1 ; type.register X2 : x2 ; type.register X_PRO : x_pro ; appender.register x1-x2-to-cpp : X1 X2 : CPP ; appender.register x-pro-to-x1-x2 : X_PRO : X1 X2 ; ################################################################################ # # When the main target type is NM_EXE, build OBJ from CPP-MARKED and not from # anything else, e.g. directly from CPP. # ################################################################################ type.register CPP_MARKED : marked_cpp : CPP ; type.register POSITIONS : positions ; type.register NM.TARGET.CPP : target_cpp : CPP ; type.register NM_EXE : : MY_EXE ; appender.register marked-to-target-cpp : CPP_MARKED : NM.TARGET.CPP ; appender.register cpp-to-marked-positions : CPP : CPP_MARKED POSITIONS ; class nm::target::cpp-obj-generator : generator { rule __init__ ( id ) { generator.__init__ $(id) : NM.TARGET.CPP : MY_OBJ ; generator.set-rule-name appender.appender ; } rule requirements ( ) { return <main-target-type>NM_EXE ; } rule run ( project name ? : properties * : source : multiple ? ) { if [ $(source).type ] = CPP { local converted = [ generators.construct $(project) : NM.TARGET.CPP : $(properties) : $(source) ] ; if $(converted) { return [ generators.construct $(project) : MY_OBJ : $(properties) : $(converted[2]) ] ; } } } } generators.register [ new nm::target::cpp-obj-generator target-obj ] ; generators.override target-obj : all ; ################################################################################ # # A more complex test case scenario with the following generators: # 1. WHL --> CPP, WHL_LR0, H, H(%_symbols) # 2. DLP --> CPP # 3. WD --> WHL(%_parser) DLP(%_lexer) # 4. A custom generator of higher priority than generators 1. & 2. that helps # disambiguate between them when generating CPP files from WHL and DLP # sources. # ################################################################################ type.register WHL : whl ; type.register DLP : dlp ; type.register WHL_LR0 : lr0 ; type.register WD : wd ; local whale-generator-id = [ appender.register whale : WHL : CPP WHL_LR0 H H(%_symbols) ] ; local dolphin-generator-id = [ appender.register dolphin : DLP : CPP ] ; appender.register wd : WD : WHL(%_parser) DLP(%_lexer) ; class wd-to-cpp : generator { rule __init__ ( id : sources * : targets * ) { generator.__init__ $(id) : $(sources) : $(targets) ; } rule run ( project name ? : property-set : source ) { local new-sources = $(source) ; if ! [ $(source).type ] in WHL DLP { local r1 = [ generators.construct $(project) $(name) : WHL : $(property-set) : $(source) ] ; local r2 = [ generators.construct $(project) $(name) : DLP : $(property-set) : $(source) ] ; new-sources = [ sequence.unique $(r1[2-]) $(r2[2-]) ] ; } local result ; for local i in $(new-sources) { local t = [ generators.construct $(project) $(name) : CPP : $(property-set) : $(i) ] ; result += $(t[2-]) ; } return $(result) ; } } generators.override $(__name__).wd-to-cpp : $(whale-generator-id) ; generators.override $(__name__).wd-to-cpp : $(dolphin-generator-id) ; generators.register [ new wd-to-cpp $(__name__).wd-to-cpp : : CPP ] ; ################################################################################ # # Declare build targets. # ################################################################################ # This should not cause two CPP --> MY_OBJ constructions for a.cpp or b.cpp. my-exe a : a.cpp b.cxx obj_1 obj_2 c.tui d.wd x.l y.x_pro lib//auxilliary ; my-exe f : a.cpp b.cxx obj_1 obj_2 lib//auxilliary ; # This should cause two CPP --> MY_OBJ constructions for z.cpp. my-obj obj_1 : z.cpp ; my-obj obj_2 : z.cpp ; nm-exe e : e.cpp ; """) t.run_build_system() t.expect_addition("bin/$toolset/debug/" * BoostBuild.List("a.my_exe " "a.my_obj b.my_obj c.tui_h c.cpp c.my_obj d_parser.whl d_lexer.dlp " "d_parser.cpp d_lexer.cpp d_lexer.my_obj d_parser.lr0 d_parser.h " "d_parser.my_obj d_parser_symbols.h x.c x.my_obj y.x1 y.x2 y.cpp " "y.my_obj e.marked_cpp e.positions e.target_cpp e.my_obj e.my_exe " "f.my_exe obj_1.my_obj obj_2.my_obj")) t.expect_addition("lib/bin/$toolset/debug/" * BoostBuild.List("c.my_obj " "auxilliary.my_lib")) t.expect_nothing_more() folder = "bin/$toolset/debug" t.expect_content_lines("%s/obj_1.my_obj" % folder, " Sources: 'z.cpp'") t.expect_content_lines("%s/obj_2.my_obj" % folder, " Sources: 'z.cpp'") t.expect_content_lines("%s/a.my_obj" % folder, " Sources: 'a.cpp'") lines = t.stdout().splitlines() source_lines = [x for x in lines if re.match("^ Sources: '", x)] if not __match_count_is(source_lines, "'z.cpp'", 2): BoostBuild.annotation("failure", "z.cpp must be compiled exactly " "twice.") t.fail_test(1) if not __match_count_is(source_lines, "'a.cpp'", 1): BoostBuild.annotation("failure", "a.cpp must be compiled exactly " "once.") t.fail_test(1) t.cleanup()
def _info(*values): values = list(values) + [""] BoostBuild.annotation(tag, "\n".join(str(x) for x in values))
def test_raw_nt(n=None, error=False): t = BoostBuild.Tester(["-d1", "-d+4"], pass_toolset=0, use_test_config=False) cmd_prefix = "%s -c \"print('XXX: " % executable cmd_suffix = "')\"" cmd_extra_length = len(cmd_prefix) + len(cmd_suffix) if n == None: n = cmd_extra_length data_length = n - cmd_extra_length if data_length < 0: BoostBuild.annotation( "failure", """\ Can not construct Windows command of desired length. Requested command length too short for the current test configuration. Requested command length: %d Minimal supported command length: %d """ % (n, cmd_extra_length)) t.fail_test(1, dump_difference=False) # Each $(Xx10-1) variable contains X words of 9 characters each, which, # including spaces between words, brings the total number of characters in # its string representation to X * 10 - 1 (X * 9 characters + (X - 1) # spaces). t.write( "file.jam", """\ ten = 0 1 2 3 4 5 6 7 8 9 ; 1x10-1 = 123456789 ; 10x10-1 = $(ten)12345678 ; 100x10-1 = $(ten)$(ten)1234567 ; 1000x10-1 = $(ten)$(ten)$(ten)123456 ; actions do_echo { %s%s%s } JAMSHELL = %% ; do_echo all ; """ % (cmd_prefix, string_of_length(data_length), cmd_suffix)) if error: expected_status = 1 else: expected_status = 0 t.run_build_system(["-ffile.jam"], status=expected_status) if error: t.expect_output_lines("Executing raw command directly", False) t.expect_output_lines("do_echo action is too long (%d, max 32766):" % n) t.expect_output_lines("XXX: *", False) else: t.expect_output_lines("Executing raw command directly") t.expect_output_lines("do_echo action is too long*", False) m = re.search("^XXX: (.*)$", t.stdout(), re.MULTILINE) if not m: BoostBuild.annotation( "failure", "Expected output line starting " "with 'XXX: ' not found.") t.fail_test(1, dump_difference=False) if len(m.group(1)) != data_length: BoostBuild.annotation( "failure", """Unexpected output data length. Expected: %d Received: %d""" % (n, len(m.group(1)))) t.fail_test(1, dump_difference=False) t.cleanup()
def __assertionFailure(self, message): BoostBuild.annotation("failure", "Internal test assertion failure " "- %s" % message) self.__tester.fail_test(1)
#ifdef ERROR #error ERROR defined #endif #ifndef OK #error ERROR not defined #endif ''') # Don't check the status immediately, so that we have a chance # to print config.log. Also, we need a minimum of d2 to make # sure that we always see the commands and output. t.run_build_system(['-sOBJECT_FILE=' + linker_input, '-d2'], status=None) if t.status != 0: log_file = t.read('bin/config.log') BoostBuild.annotation("config.log", log_file) t.fail_test(True) t.expect_output_lines([' - has --illegal-flag-cpp : no', ' - has -DMACRO_CPP : yes', ' - has --illegal-flag-c : no', ' - has -DMACRO_C : yes', ' - has --illegal-flag-link : no', ' - has *bin*/input.* : yes']) t.expect_addition('bin/$toolset/debug*/fail_cpp.obj') t.expect_addition('bin/$toolset/debug*/pass_cpp.obj') t.expect_addition('bin/$toolset/debug*/fail_c.obj') t.expect_addition('bin/$toolset/debug*/pass_c.obj') t.expect_addition('bin/$toolset/debug*/fail_link.obj') t.expect_addition('bin/$toolset/debug*/pass_link.obj')