4 # Permission is hereby granted, free of charge, to any person obtaining
5 # a copy of this software and associated documentation files (the
6 # "Software"), to deal in the Software without restriction, including
7 # without limitation the rights to use, copy, modify, merge, publish,
8 # distribute, sublicense, and/or sell copies of the Software, and to
9 # permit persons to whom the Software is furnished to do so, subject to
10 # the following conditions:
12 # The above copyright notice and this permission notice shall be included
13 # in all copies or substantial portions of the Software.
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
16 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
17 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
36 import SCons.Scanner.C
38 test = TestCmd.TestCmd(workdir = '')
40 os.chdir(test.workpath(''))
42 # create some source files and headers:
44 test.write('f1.cpp',"""
54 test.write('f2.cpp',"""
66 test.write('f3.cpp',"""
69 # \t include "f3-test.h"
73 # \t include <d1/f3-test.h>
77 const char* x = "#include <never.h>"
88 test.subdir('d1', ['d1', 'd2'])
90 headers = ['f1.h','f2.h', 'f3-test.h', 'fi.h', 'fj.h', 'never.h',
91 'd1/f1.h', 'd1/f2.h', 'd1/f3-test.h', 'd1/fi.h', 'd1/fj.h',
92 'd1/d2/f1.h', 'd1/d2/f2.h', 'd1/d2/f3-test.h',
93 'd1/d2/f4.h', 'd1/d2/fi.h', 'd1/d2/fj.h']
102 test.write('f3-test.h',"""
107 test.subdir('include', 'subdir', ['subdir', 'include'])
109 test.write('fa.cpp',"""
119 test.write(['include', 'fa.h'], "\n")
120 test.write(['include', 'fb.h'], "\n")
121 test.write(['subdir', 'include', 'fa.h'], "\n")
122 test.write(['subdir', 'include', 'fb.h'], "\n")
125 test.subdir('repository', ['repository', 'include'],
126 ['repository', 'src' ])
127 test.subdir('work', ['work', 'src'])
129 test.write(['repository', 'include', 'iii.h'], "\n")
131 test.write(['work', 'src', 'fff.c'], """
141 test.write([ 'work', 'src', 'aaa.c'], """
150 test.write([ 'work', 'src', 'bbb.h'], "\n")
152 test.write([ 'repository', 'src', 'ccc.c'], """
161 test.write([ 'repository', 'src', 'ddd.h'], "\n")
163 test.write('f5.c', """\
168 test.write("f5a.h", "\n")
169 test.write("f5b.h", "\n")
171 # define some helpers:
173 class DummyEnvironment(UserDict.UserDict):
174 def __init__(self, **kw):
175 UserDict.UserDict.__init__(self)
177 self.fs = SCons.Node.FS.FS(test.workpath(''))
179 def Dictionary(self, *args):
182 def subst(self, strSubst, target=None, source=None, conv=None):
183 if strSubst[0] == '$':
184 return self.data[strSubst[1:]]
187 def subst_list(self, strSubst, target=None, source=None, conv=None):
188 if strSubst[0] == '$':
189 return [self.data[strSubst[1:]]]
192 def subst_path(self, path, target=None, source=None, conv=None):
193 if not isinstance(path, list):
195 return list(map(self.subst, path))
197 def get_calculator(self):
200 def get_factory(self, factory):
201 return factory or self.fs.File
203 def Dir(self, filename):
204 return self.fs.Dir(filename)
206 def File(self, filename):
207 return self.fs.File(filename)
209 if os.path.normcase('foo') == os.path.normcase('FOO'):
210 my_normpath = os.path.normcase
212 my_normpath = os.path.normpath
214 def deps_match(self, deps, headers):
216 scanned = list(map(my_normpath, list(map(str, deps))))
217 expect = list(map(my_normpath, headers))
218 self.failUnless(scanned == expect, "expect %s != scanned %s" % (expect, scanned))
222 class CScannerTestCase1(unittest.TestCase):
224 """Find local files with no CPPPATH"""
225 env = DummyEnvironment(CPPPATH=[])
226 s = SCons.Scanner.C.CScanner()
228 deps = s(env.File('f1.cpp'), env, path)
229 headers = ['f1.h', 'f2.h']
230 deps_match(self, deps, headers)
232 class CScannerTestCase2(unittest.TestCase):
234 """Find a file in a CPPPATH directory"""
235 env = DummyEnvironment(CPPPATH=[test.workpath("d1")])
236 s = SCons.Scanner.C.CScanner()
238 deps = s(env.File('f1.cpp'), env, path)
239 headers = ['f1.h', 'd1/f2.h']
240 deps_match(self, deps, headers)
242 class CScannerTestCase3(unittest.TestCase):
244 """Find files in explicit subdirectories, ignore missing file"""
245 env = DummyEnvironment(CPPPATH=[test.workpath("d1")])
246 s = SCons.Scanner.C.CScanner()
248 deps = s(env.File('f2.cpp'), env, path)
249 headers = ['d1/f1.h', 'f1.h', 'd1/d2/f1.h']
250 deps_match(self, deps, headers)
252 class CScannerTestCase4(unittest.TestCase):
254 """Find files in explicit subdirectories"""
255 env = DummyEnvironment(CPPPATH=[test.workpath("d1"), test.workpath("d1/d2")])
256 s = SCons.Scanner.C.CScanner()
258 deps = s(env.File('f2.cpp'), env, path)
259 headers = ['d1/f1.h', 'f1.h', 'd1/d2/f1.h', 'd1/d2/f4.h']
260 deps_match(self, deps, headers)
262 class CScannerTestCase5(unittest.TestCase):
264 """Make sure files in repositories will get scanned"""
265 env = DummyEnvironment(CPPPATH=[])
266 s = SCons.Scanner.C.CScanner()
269 n = env.File('f3.cpp')
272 return s.old_rexists()
273 setattr(n, 'old_rexists', n.rexists)
274 setattr(n, 'rexists', my_rexists)
276 deps = s(n, env, path)
278 # Make sure rexists() got called on the file node being
279 # scanned, essential for cooperation with VariantDir functionality.
280 assert n.rexists_called
282 headers = ['f1.h', 'f2.h', 'f3-test.h',
283 'd1/f1.h', 'd1/f2.h', 'd1/f3-test.h']
284 deps_match(self, deps, headers)
286 class CScannerTestCase6(unittest.TestCase):
288 """Find a same-named file in different directories when CPPPATH changes"""
289 env1 = DummyEnvironment(CPPPATH=[test.workpath("d1")])
290 env2 = DummyEnvironment(CPPPATH=[test.workpath("d1/d2")])
291 s = SCons.Scanner.C.CScanner()
294 deps1 = s(env1.File('f1.cpp'), env1, path1)
295 deps2 = s(env2.File('f1.cpp'), env2, path2)
296 headers1 = ['f1.h', 'd1/f2.h']
297 headers2 = ['f1.h', 'd1/d2/f2.h']
298 deps_match(self, deps1, headers1)
299 deps_match(self, deps2, headers2)
301 class CScannerTestCase8(unittest.TestCase):
303 """Find files in a subdirectory relative to the current directory"""
304 env = DummyEnvironment(CPPPATH=["include"])
305 s = SCons.Scanner.C.CScanner()
307 deps1 = s(env.File('fa.cpp'), env, path)
308 env.fs.chdir(env.Dir('subdir'))
309 dir = env.fs.getcwd()
310 env.fs.chdir(env.Dir(''))
311 path = s.path(env, dir)
312 deps2 = s(env.File('#fa.cpp'), env, path)
313 headers1 = list(map(test.workpath, ['include/fa.h', 'include/fb.h']))
314 headers2 = ['include/fa.h', 'include/fb.h']
315 deps_match(self, deps1, headers1)
316 deps_match(self, deps2, headers2)
318 class CScannerTestCase9(unittest.TestCase):
320 """Generate a warning when we can't find a #included file"""
321 SCons.Warnings.enableWarningClass(SCons.Warnings.DependencyWarning)
323 def __call__(self, x):
328 SCons.Warnings._warningOut = to
329 test.write('fa.h','\n')
330 fs = SCons.Node.FS.FS(test.workpath(''))
331 env = DummyEnvironment(CPPPATH=[])
333 s = SCons.Scanner.C.CScanner()
335 deps = s(fs.File('fa.cpp'), env, path)
337 # Did we catch the warning associated with not finding fb.h?
340 deps_match(self, deps, [ 'fa.h' ])
343 class CScannerTestCase10(unittest.TestCase):
345 """Find files in the local directory when the scanned file is elsewhere"""
346 fs = SCons.Node.FS.FS(test.workpath(''))
347 fs.chdir(fs.Dir('include'))
348 env = DummyEnvironment(CPPPATH=[])
350 s = SCons.Scanner.C.CScanner()
352 test.write('include/fa.cpp', test.read('fa.cpp'))
353 fs.chdir(fs.Dir('..'))
354 deps = s(fs.File('#include/fa.cpp'), env, path)
355 deps_match(self, deps, [ 'include/fa.h', 'include/fb.h' ])
356 test.unlink('include/fa.cpp')
358 class CScannerTestCase11(unittest.TestCase):
360 """Handle dependencies on a derived .h file in a non-existent directory"""
361 os.chdir(test.workpath('work'))
362 fs = SCons.Node.FS.FS(test.workpath('work'))
363 fs.Repository(test.workpath('repository'))
365 # Create a derived file in a directory that does not exist yet.
366 # This was a bug at one time.
367 f1=fs.File('include2/jjj.h')
369 env = DummyEnvironment(CPPPATH=['include', 'include2'])
371 s = SCons.Scanner.C.CScanner()
373 deps = s(fs.File('src/fff.c'), env, path)
374 deps_match(self, deps, [ test.workpath('repository/include/iii.h'),
376 os.chdir(test.workpath(''))
378 class CScannerTestCase12(unittest.TestCase):
380 """Find files in VariantDir() directories"""
381 os.chdir(test.workpath('work'))
382 fs = SCons.Node.FS.FS(test.workpath('work'))
383 fs.VariantDir('build1', 'src', 1)
384 fs.VariantDir('build2', 'src', 0)
385 fs.Repository(test.workpath('repository'))
386 env = DummyEnvironment(CPPPATH=[])
388 s = SCons.Scanner.C.CScanner()
390 deps1 = s(fs.File('build1/aaa.c'), env, path)
391 deps_match(self, deps1, [ 'build1/bbb.h' ])
392 deps2 = s(fs.File('build2/aaa.c'), env, path)
393 deps_match(self, deps2, [ 'src/bbb.h' ])
394 deps3 = s(fs.File('build1/ccc.c'), env, path)
395 deps_match(self, deps3, [ 'build1/ddd.h' ])
396 deps4 = s(fs.File('build2/ccc.c'), env, path)
397 deps_match(self, deps4, [ test.workpath('repository/src/ddd.h') ])
398 os.chdir(test.workpath(''))
400 class CScannerTestCase13(unittest.TestCase):
402 """Find files in directories named in a substituted environment variable"""
403 class SubstEnvironment(DummyEnvironment):
404 def subst(self, arg, target=None, source=None, conv=None, test=test):
406 return test.workpath("d1")
409 env = SubstEnvironment(CPPPATH=["$blah"])
410 s = SCons.Scanner.C.CScanner()
412 deps = s(env.File('f1.cpp'), env, path)
413 headers = ['f1.h', 'd1/f2.h']
414 deps_match(self, deps, headers)
416 class CScannerTestCase14(unittest.TestCase):
418 """Find files when there's no space between "#include" and the name"""
419 env = DummyEnvironment(CPPPATH=[])
420 s = SCons.Scanner.C.CScanner()
422 deps = s(env.File('f5.c'), env, path)
423 headers = ['f5a.h', 'f5b.h']
424 deps_match(self, deps, headers)
426 class CScannerTestCase15(unittest.TestCase):
428 """Verify scanner initialization with the suffixes in $CPPSUFFIXES"""
429 suffixes = [".c", ".C", ".cxx", ".cpp", ".c++", ".cc",
430 ".h", ".H", ".hxx", ".hpp", ".hh",
431 ".F", ".fpp", ".FPP",
432 ".S", ".spp", ".SPP"]
433 env = DummyEnvironment(CPPSUFFIXES = suffixes)
434 s = SCons.Scanner.C.CScanner()
435 for suffix in suffixes:
436 assert suffix in s.get_skeys(env), "%s not in skeys" % suffix
441 suite = unittest.TestSuite()
442 suite.addTest(CScannerTestCase1())
443 suite.addTest(CScannerTestCase2())
444 suite.addTest(CScannerTestCase3())
445 suite.addTest(CScannerTestCase4())
446 suite.addTest(CScannerTestCase5())
447 suite.addTest(CScannerTestCase6())
448 suite.addTest(CScannerTestCase8())
449 suite.addTest(CScannerTestCase9())
450 suite.addTest(CScannerTestCase10())
451 suite.addTest(CScannerTestCase11())
452 suite.addTest(CScannerTestCase12())
453 suite.addTest(CScannerTestCase13())
454 suite.addTest(CScannerTestCase14())
455 suite.addTest(CScannerTestCase15())
458 if __name__ == "__main__":
459 runner = unittest.TextTestRunner()
460 result = runner.run(suite())
461 if not result.wasSuccessful():
466 # indent-tabs-mode:nil
468 # vim: set expandtab tabstop=4 shiftwidth=4: