diff options
Diffstat (limited to 'SCons/Scanner/CTests.py')
-rw-r--r-- | SCons/Scanner/CTests.py | 157 |
1 files changed, 103 insertions, 54 deletions
diff --git a/SCons/Scanner/CTests.py b/SCons/Scanner/CTests.py index 14e156e71..6860a10ce 100644 --- a/SCons/Scanner/CTests.py +++ b/SCons/Scanner/CTests.py @@ -91,6 +91,27 @@ int main(void) } """) +# include using a macro, defined in source file +test.write('f9a.c', """\ +#define HEADER "f9.h" +#include HEADER + +int main(void) +{ + return 0; +} +""") + +# include using a macro, not defined in source file +test.write('f9b.c', """\ +#include HEADER + +int main(void) +{ + return 0; +} +""") + # for Emacs -> " @@ -99,7 +120,7 @@ test.subdir('d1', ['d1', 'd2']) headers = ['f1.h','f2.h', 'f3-test.h', 'fi.h', 'fj.h', 'never.h', 'd1/f1.h', 'd1/f2.h', 'd1/f3-test.h', 'd1/fi.h', 'd1/fj.h', 'd1/d2/f1.h', 'd1/d2/f2.h', 'd1/d2/f3-test.h', - 'd1/d2/f4.h', 'd1/d2/fi.h', 'd1/d2/fj.h'] + 'd1/d2/f4.h', 'd1/d2/fi.h', 'd1/d2/fj.h', 'f9.h'] for h in headers: test.write(h, " ") @@ -180,7 +201,7 @@ test.write("f5b.h", "\n") # define some helpers: class DummyEnvironment(collections.UserDict): - def __init__(self, **kwargs): + def __init__(self, **kwargs) -> None: super().__init__() self.data.update(kwargs) self.fs = SCons.Node.FS.FS(test.workpath('')) @@ -220,16 +241,16 @@ if os.path.normcase('foo') == os.path.normcase('FOO'): else: my_normpath = os.path.normpath -def deps_match(self, deps, headers): +def deps_match(self, deps, headers) -> None: global my_normpath scanned = list(map(my_normpath, list(map(str, deps)))) expect = list(map(my_normpath, headers)) - self.assertTrue(scanned == expect, "expect %s != scanned %s" % (expect, scanned)) + self.assertTrue(scanned == expect, f"expect {expect} != scanned {scanned}") # define some tests: class CScannerTestCase1(unittest.TestCase): - def runTest(self): + def runTest(self) -> None: """Find local files with no CPPPATH""" env = DummyEnvironment(CPPPATH=[]) s = SCons.Scanner.C.CScanner() @@ -239,7 +260,7 @@ class CScannerTestCase1(unittest.TestCase): deps_match(self, deps, headers) class CScannerTestCase2(unittest.TestCase): - def runTest(self): + def runTest(self) -> None: """Find a file in a CPPPATH directory""" env = DummyEnvironment(CPPPATH=[test.workpath("d1")]) s = SCons.Scanner.C.CScanner() @@ -249,7 +270,7 @@ class CScannerTestCase2(unittest.TestCase): deps_match(self, deps, headers) class CScannerTestCase3(unittest.TestCase): - def runTest(self): + def runTest(self) -> None: """Find files in explicit subdirectories, ignore missing file""" env = DummyEnvironment(CPPPATH=[test.workpath("d1")]) s = SCons.Scanner.C.CScanner() @@ -259,7 +280,7 @@ class CScannerTestCase3(unittest.TestCase): deps_match(self, deps, headers) class CScannerTestCase4(unittest.TestCase): - def runTest(self): + def runTest(self) -> None: """Find files in explicit subdirectories""" env = DummyEnvironment(CPPPATH=[test.workpath("d1"), test.workpath("d1/d2")]) s = SCons.Scanner.C.CScanner() @@ -269,7 +290,7 @@ class CScannerTestCase4(unittest.TestCase): deps_match(self, deps, headers) class CScannerTestCase5(unittest.TestCase): - def runTest(self): + def runTest(self) -> None: """Make sure files in repositories will get scanned""" env = DummyEnvironment(CPPPATH=[]) s = SCons.Scanner.C.CScanner() @@ -294,7 +315,7 @@ class CScannerTestCase5(unittest.TestCase): deps_match(self, deps, headers) class CScannerTestCase6(unittest.TestCase): - def runTest(self): + def runTest(self) -> None: """Find a same-named file in different directories when CPPPATH changes""" env1 = DummyEnvironment(CPPPATH=[test.workpath("d1")]) env2 = DummyEnvironment(CPPPATH=[test.workpath("d1/d2")]) @@ -309,7 +330,7 @@ class CScannerTestCase6(unittest.TestCase): deps_match(self, deps2, headers2) class CScannerTestCase8(unittest.TestCase): - def runTest(self): + def runTest(self) -> None: """Find files in a subdirectory relative to the current directory""" env = DummyEnvironment(CPPPATH=["include"]) s = SCons.Scanner.C.CScanner() @@ -326,11 +347,11 @@ class CScannerTestCase8(unittest.TestCase): deps_match(self, deps2, headers2) class CScannerTestCase9(unittest.TestCase): - def runTest(self): + def runTest(self) -> None: """Generate a warning when we can't find a #included file""" SCons.Warnings.enableWarningClass(SCons.Warnings.DependencyWarning) class TestOut: - def __call__(self, x): + def __call__(self, x) -> None: self.out = x to = TestOut() @@ -351,7 +372,7 @@ class CScannerTestCase9(unittest.TestCase): test.unlink('fa.h') class CScannerTestCase10(unittest.TestCase): - def runTest(self): + def runTest(self) -> None: """Find files in the local directory when the scanned file is elsewhere""" fs = SCons.Node.FS.FS(test.workpath('')) fs.chdir(fs.Dir('include')) @@ -366,7 +387,7 @@ class CScannerTestCase10(unittest.TestCase): test.unlink('include/fa.cpp') class CScannerTestCase11(unittest.TestCase): - def runTest(self): + def runTest(self) -> None: """Handle dependencies on a derived .h file in a non-existent directory""" os.chdir(test.workpath('work')) fs = SCons.Node.FS.FS(test.workpath('work')) @@ -386,7 +407,7 @@ class CScannerTestCase11(unittest.TestCase): os.chdir(test.workpath('')) class CScannerTestCase12(unittest.TestCase): - def runTest(self): + def runTest(self) -> None: """Find files in VariantDir() directories""" os.chdir(test.workpath('work')) fs = SCons.Node.FS.FS(test.workpath('work')) @@ -408,7 +429,7 @@ class CScannerTestCase12(unittest.TestCase): os.chdir(test.workpath('')) class CScannerTestCase13(unittest.TestCase): - def runTest(self): + def runTest(self) -> None: """Find files in directories named in a substituted environment variable""" class SubstEnvironment(DummyEnvironment): def subst(self, arg, target=None, source=None, conv=None, test=test): @@ -424,7 +445,7 @@ class CScannerTestCase13(unittest.TestCase): deps_match(self, deps, headers) class CScannerTestCase14(unittest.TestCase): - def runTest(self): + def runTest(self) -> None: """Find files when there's no space between "#include" and the name""" env = DummyEnvironment(CPPPATH=[]) s = SCons.Scanner.C.CScanner() @@ -434,7 +455,7 @@ class CScannerTestCase14(unittest.TestCase): deps_match(self, deps, headers) class CScannerTestCase15(unittest.TestCase): - def runTest(self): + def runTest(self) -> None: """Verify scanner initialization with the suffixes in $CPPSUFFIXES""" suffixes = [".c", ".C", ".cxx", ".cpp", ".c++", ".cc", ".h", ".H", ".hxx", ".hpp", ".hh", @@ -443,11 +464,11 @@ class CScannerTestCase15(unittest.TestCase): env = DummyEnvironment(CPPSUFFIXES = suffixes) s = SCons.Scanner.C.CScanner() for suffix in suffixes: - assert suffix in s.get_skeys(env), "%s not in skeys" % suffix + assert suffix in s.get_skeys(env), f"{suffix} not in skeys" class CConditionalScannerTestCase1(unittest.TestCase): - def runTest(self): + def runTest(self) -> None: """Find local files with no CPPPATH""" env = DummyEnvironment(CPPPATH=[]) s = SCons.Scanner.C.CConditionalScanner() @@ -458,7 +479,7 @@ class CConditionalScannerTestCase1(unittest.TestCase): class CConditionalScannerTestCase2(unittest.TestCase): - def runTest(self): + def runTest(self) -> None: """Find local files with no CPPPATH based on #ifdef""" env = DummyEnvironment(CPPPATH=[], CPPDEFINES=["INCLUDE_F2"]) s = SCons.Scanner.C.CConditionalScanner() @@ -469,7 +490,7 @@ class CConditionalScannerTestCase2(unittest.TestCase): class CConditionalScannerTestCase3(unittest.TestCase): - def runTest(self): + def runTest(self) -> None: """Find files in explicit subdirectories, ignore missing file""" env = DummyEnvironment( CPPPATH=[test.workpath("d1")], @@ -490,42 +511,70 @@ class CConditionalScannerTestCase3(unittest.TestCase): headers = ['d1/f1.h'] deps_match(self, deps, headers) + +class CConditionalScannerTestCase4(unittest.TestCase): + def runTest(self) -> None: + """Test that dependency is detected if #include uses a macro.""" + + with self.subTest("macro defined in the source file"): + env = DummyEnvironment() + s = SCons.Scanner.C.CConditionalScanner() + deps = s(env.File('f9a.c'), env, s.path(env)) + headers = ['f9.h'] + deps_match(self, deps, headers) + + with self.subTest("macro defined on the command line"): + env = DummyEnvironment(CPPDEFINES='HEADER=\\"f9.h\\"') + #env = DummyEnvironment(CPPDEFINES=['HEADER=\\"f9.h\\"']) + s = SCons.Scanner.C.CConditionalScanner() + deps = s(env.File('f9b.c'), env, s.path(env)) + headers = ['f9.h'] + deps_match(self, deps, headers) + + class dictify_CPPDEFINESTestCase(unittest.TestCase): - def runTest(self): - """Make sure single-item tuples convert correctly. + def runTest(self) -> None: + """Make sure CPPDEFINES converts correctly. - This is a regression test: AppendUnique turns sequences into - lists of tuples, and dictify could gack on these. + Various types and combinations of types could fail if not handled + specifically by dictify_CPPDEFINES - this is a regression test. """ - env = DummyEnvironment(CPPDEFINES=(("VALUED_DEFINE", 1), ("UNVALUED_DEFINE", ))) - d = SCons.Scanner.C.dictify_CPPDEFINES(env) - expect = {'VALUED_DEFINE': 1, 'UNVALUED_DEFINE': None} - assert d == expect - -def suite(): - suite = unittest.TestSuite() - suite.addTest(CScannerTestCase1()) - suite.addTest(CScannerTestCase2()) - suite.addTest(CScannerTestCase3()) - suite.addTest(CScannerTestCase4()) - suite.addTest(CScannerTestCase5()) - suite.addTest(CScannerTestCase6()) - suite.addTest(CScannerTestCase8()) - suite.addTest(CScannerTestCase9()) - suite.addTest(CScannerTestCase10()) - suite.addTest(CScannerTestCase11()) - suite.addTest(CScannerTestCase12()) - suite.addTest(CScannerTestCase13()) - suite.addTest(CScannerTestCase14()) - suite.addTest(CScannerTestCase15()) - suite.addTest(CConditionalScannerTestCase1()) - suite.addTest(CConditionalScannerTestCase2()) - suite.addTest(CConditionalScannerTestCase3()) - suite.addTest(dictify_CPPDEFINESTestCase()) - return suite + with self.subTest("tuples in a sequence, including one without value"): + env = DummyEnvironment(CPPDEFINES=[("VALUED", 1), ("UNVALUED",)]) + d = SCons.Scanner.C.dictify_CPPDEFINES(env) + expect = {"VALUED": 1, "UNVALUED": None} + self.assertEqual(d, expect) + + with self.subTest("tuple-valued define by itself"): + env = DummyEnvironment(CPPDEFINES=("STRING", "VALUE")) + d = SCons.Scanner.C.dictify_CPPDEFINES(env) + expect = {"STRING": "VALUE"} + self.assertEqual(d, expect) + + with self.subTest("string-valued define in a sequence"): + env = DummyEnvironment(CPPDEFINES=[("STRING=VALUE")]) + d = SCons.Scanner.C.dictify_CPPDEFINES(env) + expect = {"STRING": "VALUE"} + self.assertEqual(d, expect) + + with self.subTest("string-valued define by itself"): + env = DummyEnvironment(CPPDEFINES="STRING=VALUE") + d = SCons.Scanner.C.dictify_CPPDEFINES(env) + expect = {"STRING": "VALUE"} + self.assertEqual(d, expect) + + from collections import deque + with self.subTest("compound CPPDEFINES in internal format"): + env = DummyEnvironment( + CPPDEFINES=deque([("STRING", "VALUE"), ("UNVALUED",)]) + ) + d = SCons.Scanner.C.dictify_CPPDEFINES(env) + expect = {"STRING": "VALUE", "UNVALUED": None} + self.assertEqual(d, expect) + if __name__ == "__main__": - TestUnit.run(suite()) + unittest.main() # Local Variables: # tab-width:4 |