diff --git a/tests/always_rebuild_if_no_inputs.hancho b/tests/always_rebuild_if_no_inputs.hancho index d4f55b9..ec48364 100644 --- a/tests/always_rebuild_if_no_inputs.hancho +++ b/tests/always_rebuild_if_no_inputs.hancho @@ -1,7 +1,6 @@ # test/always_rebuild_if_no_inputs.hancho always_rebuilt = Rule( - desc = "Always rebuild {files_out} if the rule has no inputs", command = "touch {files_out}", ) diff --git a/tests/build_dir_works.hancho b/tests/build_dir_works.hancho index 34299c5..c4e2886 100644 --- a/tests/build_dir_works.hancho +++ b/tests/build_dir_works.hancho @@ -3,7 +3,6 @@ config.build_dir = "build/build_dir_works" build_dir_works = Rule( - desc = "Should put a file in build/build_dir_works", command = "touch {files_out}", ) diff --git a/tests/check_output.hancho b/tests/check_output.hancho index 0395949..13c0ead 100644 --- a/tests/check_output.hancho +++ b/tests/check_output.hancho @@ -1,7 +1,6 @@ # tests/check_output.hancho check_output = Rule( - desc = "A build rule that doesn't update one of its outputs should fail", command = "touch {files_out[0]}", ) diff --git a/tests/command_missing.hancho b/tests/command_missing.hancho index b8bf43d..f4336ca 100644 --- a/tests/command_missing.hancho +++ b/tests/command_missing.hancho @@ -1,7 +1,6 @@ # tests/command_missing.hancho command_missing = Rule( - desc = "Command is missing", ) command_missing(__file__) diff --git a/tests/dep_changed.hancho b/tests/dep_changed.hancho index 3937f2c..c338445 100644 --- a/tests/dep_changed.hancho +++ b/tests/dep_changed.hancho @@ -1,6 +1,5 @@ dep_changed = Rule( - desc = "Changing a file in deps[] should trigger a rebuild", command = "touch {files_out}", ) diff --git a/tests/does_create_output.hancho b/tests/does_create_output.hancho index d1a18c5..af86dc5 100644 --- a/tests/does_create_output.hancho +++ b/tests/does_create_output.hancho @@ -1,7 +1,6 @@ # tests/does_create_output does_create_output = Rule( - desc = "Does create its output file", command = "touch {files_out}", ) diff --git a/tests/doesnt_create_output.hancho b/tests/doesnt_create_output.hancho index c0c88ef..90c0669 100644 --- a/tests/doesnt_create_output.hancho +++ b/tests/doesnt_create_output.hancho @@ -1,7 +1,6 @@ # tests/doesnt_create_output.hancho doesnt_create_output = Rule( - desc = "Doesn't create {files_out}", command = ":", ) diff --git a/tests/expand_failed_to_terminate.hancho b/tests/expand_failed_to_terminate.hancho index 0a6b209..8cfefc0 100644 --- a/tests/expand_failed_to_terminate.hancho +++ b/tests/expand_failed_to_terminate.hancho @@ -1,7 +1,6 @@ # tests/expand_failed_to_terminate.hancho expand_failed_to_terminate = Rule( - desc = "A recursive text template should cause an 'expand failed to terminate' error.", command = "{flarp}", flarp = "asdf {flarp}" ) diff --git a/tests/garbage_command.hancho b/tests/garbage_command.hancho index b80a559..aa44dfe 100644 --- a/tests/garbage_command.hancho +++ b/tests/garbage_command.hancho @@ -1,7 +1,6 @@ # tests/garbage_command.hancho garbage_command = Rule( - desc = "This command should fail to run", command = "aklsjdflksjdlfkjldfk", ) diff --git a/tests/header_changed.hancho b/tests/header_changed.hancho index 61456df..6a83f91 100644 --- a/tests/header_changed.hancho +++ b/tests/header_changed.hancho @@ -1,6 +1,5 @@ header_changed = Rule( - desc = "Changing a header file tracked in the GCC depfile should trigger a rebuild", command = "gcc -MMD -c {files_in} -o {files_out}", files_out = "{swap_ext(files_in, '.o')}", depfile = "{swap_ext(files_out, '.d')}", diff --git a/tests/input_changed.hancho b/tests/input_changed.hancho index b1783d6..45d9bac 100644 --- a/tests/input_changed.hancho +++ b/tests/input_changed.hancho @@ -1,6 +1,5 @@ input_changed = Rule( - desc = "Changing a source file should trigger a rebuild", command = "gcc -MMD -c {files_in} -o {files_out}", files_out = "{swap_ext(files_in, '.o')}", depfile = "{swap_ext(files_out, '.d')}", diff --git a/tests/missing_src.hancho b/tests/missing_src.hancho index 6b485e6..5d5a14c 100644 --- a/tests/missing_src.hancho +++ b/tests/missing_src.hancho @@ -1,7 +1,6 @@ # tests/missing_src.hancho missing_src = Rule( - desc = "We should fail if a source file is missing", command = "touch {files_out}", ) diff --git a/tests/test.py b/tests/test.py index e09e489..72101a0 100755 --- a/tests/test.py +++ b/tests/test.py @@ -1,4 +1,5 @@ #!/usr/bin/python3 +"""Test cases for Hancho""" import os from os import path @@ -6,137 +7,169 @@ import unittest # min delta seems to be 4 msec -#os.system("touch blahblah.txt") -#old_mtime = path.getmtime("blahblah.txt") -#min_delta = 1000000 -#for _ in range(1000): -# os.system("touch blahblah.txt") -# new_mtime = path.getmtime("blahblah.txt") -# delta = new_mtime - old_mtime -# if delta and delta < min_delta: -# log(str(delta)) -# min_delta = delta -# old_mtime = new_mtime +# os.system("touch blahblah.txt") +# old_mtime = path.getmtime("blahblah.txt") +# min_delta = 1000000 +# for _ in range(1000): +# os.system("touch blahblah.txt") +# new_mtime = path.getmtime("blahblah.txt") +# delta = new_mtime - old_mtime +# if delta and delta < min_delta: +# log(str(delta)) +# min_delta = delta +# old_mtime = new_mtime -def mtime(file): - return path.getmtime(file) - -def run(cmd): - return subprocess.check_output(cmd, shell=True, text=True).strip() - -def run_hancho(name): - return os.system(f"../hancho.py --quiet {name}.hancho") - -def touch(name): - os.system(f"touch {name}") - -################################################################################ - -class TestHancho(unittest.TestCase): - - def setUp(self): - os.system("rm -rf build") - os.system("mkdir build") - - def test_should_pass(self): - self.assertEqual(0, run_hancho("should_pass")) - - def test_check_output(self): - self.assertNotEqual(0, run_hancho("check_output")) - - def test_check_missing_src(self): - self.assertNotEqual(0, run_hancho("missing_src")) - - def test_recursive_base_is_bad(self): - self.assertNotEqual(0, run_hancho("recursive_base_is_bad")) - def test_should_fail(self): - self.assertNotEqual(0, run_hancho("should_fail")) - - def test_command_missing(self): - self.assertNotEqual(0, run_hancho("command_missing")) - - def test_expand_failed_to_terminate(self): - self.assertNotEqual(0, run_hancho("expand_failed_to_terminate")) - - def test_garbage_command(self): - self.assertNotEqual(0, run_hancho("garbage_command")) - - def test_always_rebuild_if_no_inputs(self): - run_hancho("always_rebuild_if_no_inputs") - mtime1 = mtime(f"build/result.txt") - - run_hancho("always_rebuild_if_no_inputs") - mtime2 = mtime(f"build/result.txt") - - run_hancho("always_rebuild_if_no_inputs") - mtime3 = mtime(f"build/result.txt") - self.assertLess(mtime1, mtime2) - self.assertLess(mtime2, mtime3) - - def test_build_dir_works(self): - run_hancho("build_dir_works") - self.assertTrue(path.exists("build/build_dir_works/result.txt")) - - def test_dep_changed(self): - touch("build/dummy.txt") - run_hancho("dep_changed") - mtime1 = mtime(f"build/result.txt") - - run_hancho("dep_changed") - mtime2 = mtime(f"build/result.txt") +def mtime(file): + """Shorthand for path.getmtime()""" + return path.getmtime(file) - touch("build/dummy.txt") - run_hancho("dep_changed") - mtime3 = mtime(f"build/result.txt") - self.assertEqual(mtime1, mtime2) - self.assertLess(mtime2, mtime3) - def test_does_create_output(self): - run_hancho("does_create_output") - self.assertTrue(path.exists("build/result.txt")) +def run(cmd): + """Runs a command line and returns its stdout with whitespace stripped""" + return subprocess.check_output(cmd, shell=True, text=True).strip() - def test_doesnt_create_output(self): - run_hancho("doesnt_create_output") - self.assertFalse(path.exists("build/result.txt")) - def test_header_changed(self): - run_hancho("header_changed") - mtime1 = mtime(f"build/src/test.o") +def run_hancho(name): + """Runs a Hancho build script, quietly.""" + return os.system(f"../hancho.py --quiet {name}.hancho") - run_hancho("header_changed") - mtime2 = mtime(f"build/src/test.o") - os.system("touch src/test.hpp") - run_hancho("header_changed") - mtime3 = mtime(f"build/src/test.o") - self.assertEqual(mtime1, mtime2) - self.assertLess(mtime2, mtime3) +def touch(name): + """Convenience helper method""" + os.system(f"touch {name}") - def test_input_changed(self): - run_hancho("input_changed") - mtime1 = mtime(f"build/src/test.o") - run_hancho("input_changed") - mtime2 = mtime(f"build/src/test.o") +################################################################################ - os.system("touch src/test.cpp") - run_hancho("input_changed") - mtime3 = mtime(f"build/src/test.o") - self.assertEqual(mtime1, mtime2) - self.assertLess(mtime2, mtime3) - def test_multiple_commands(self): - run_hancho("multiple_commands") - self.assertTrue(path.exists("build/foo.txt")) - self.assertTrue(path.exists("build/bar.txt")) - self.assertTrue(path.exists("build/baz.txt")) +class TestHancho(unittest.TestCase): + """Basic test cases""" + + def setUp(self): + """Always wipe the build dir before a test""" + os.system("rm -rf build") + + def test_should_pass(self): + """Sanity check""" + self.assertEqual(0, run_hancho("should_pass")) + + def test_should_fail(self): + """Sanity check""" + self.assertNotEqual(0, run_hancho("should_fail")) + + def test_check_output(self): + """A build rule that doesn't update one of its outputs should fail""" + self.assertNotEqual(0, run_hancho("check_output")) + + def test_check_missing_src(self): + """We should fail if a source file is missing""" + self.assertNotEqual(0, run_hancho("missing_src")) + + def test_recursive_base_is_bad(self): + """Referring to base.attrib in a template is a bad idea""" + self.assertNotEqual(0, run_hancho("recursive_base_is_bad")) + + def test_command_missing(self): + """Rules with missing commands should fail""" + self.assertNotEqual(0, run_hancho("command_missing")) + + def test_expand_failed_to_terminate(self): + """A recursive text template should cause an 'expand failed to terminate' error.""" + self.assertNotEqual(0, run_hancho("expand_failed_to_terminate")) + + def test_garbage_command(self): + """Non-existent command line commands should cause Hancho to fail the build.""" + self.assertNotEqual(0, run_hancho("garbage_command")) + + def test_always_rebuild_if_no_inputs(self): + """A rule with no inputs should always rebuild""" + run_hancho("always_rebuild_if_no_inputs") + mtime1 = mtime("build/result.txt") + + run_hancho("always_rebuild_if_no_inputs") + mtime2 = mtime("build/result.txt") + + run_hancho("always_rebuild_if_no_inputs") + mtime3 = mtime("build/result.txt") + self.assertLess(mtime1, mtime2) + self.assertLess(mtime2, mtime3) + + def test_build_dir_works(self): + """Customizing build_dir should put output files in build_dir""" + run_hancho("build_dir_works") + self.assertTrue(path.exists("build/build_dir_works/result.txt")) + + def test_dep_changed(self): + """Changing a file in deps[] should trigger a rebuild""" + os.system("mkdir build") + touch("build/dummy.txt") + run_hancho("dep_changed") + mtime1 = mtime("build/result.txt") + + run_hancho("dep_changed") + mtime2 = mtime("build/result.txt") + + touch("build/dummy.txt") + run_hancho("dep_changed") + mtime3 = mtime("build/result.txt") + self.assertEqual(mtime1, mtime2) + self.assertLess(mtime2, mtime3) + + def test_does_create_output(self): + """Output files should appear in build/ by default""" + run_hancho("does_create_output") + self.assertTrue(path.exists("build/result.txt")) + + def test_doesnt_create_output(self): + """Having a file mentioned in files_out should not magically create it""" + run_hancho("doesnt_create_output") + self.assertFalse(path.exists("build/result.txt")) + + def test_header_changed(self): + """Changing a header file tracked in the GCC depfile should trigger a rebuild""" + run_hancho("header_changed") + mtime1 = mtime("build/src/test.o") + + run_hancho("header_changed") + mtime2 = mtime("build/src/test.o") + + os.system("touch src/test.hpp") + run_hancho("header_changed") + mtime3 = mtime("build/src/test.o") + self.assertEqual(mtime1, mtime2) + self.assertLess(mtime2, mtime3) + + def test_input_changed(self): + """Changing a source file should trigger a rebuild""" + run_hancho("input_changed") + mtime1 = mtime("build/src/test.o") + + run_hancho("input_changed") + mtime2 = mtime("build/src/test.o") + + os.system("touch src/test.cpp") + run_hancho("input_changed") + mtime3 = mtime("build/src/test.o") + self.assertEqual(mtime1, mtime2) + self.assertLess(mtime2, mtime3) + + def test_multiple_commands(self): + """Rules with arrays of commands should run all of them""" + run_hancho("multiple_commands") + self.assertTrue(path.exists("build/foo.txt")) + self.assertTrue(path.exists("build/bar.txt")) + self.assertTrue(path.exists("build/baz.txt")) + + def test_arbitrary_flags(self): + """Passing arbitrary flags to Hancho should work""" + os.system( + "../hancho.py --build_dir=build/some/other/dir --quiet does_create_output.hancho" + ) + self.assertTrue(path.exists("build/some/other/dir/result.txt")) - def test_arbitrary_flags(self): - os.system(f"../hancho.py --build_dir=build/some/other/dir --quiet does_create_output.hancho") - self.assertTrue(path.exists("build/some/other/dir/result.txt")) ################################################################################ -if __name__ == '__main__': +if __name__ == "__main__": unittest.main()