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__"
33 class DummyEnvironment(UserDict.UserDict):
34 def __init__(self, dict=None, **kw):
35 UserDict.UserDict.__init__(self, dict)
37 def subst(self, strSubst):
38 if strSubst[0] == '$':
39 return self.data[strSubst[1:]]
41 def subst_list(self, strSubst):
42 if strSubst[0] == '$':
43 return [self.data[strSubst[1:]]]
45 def subst_path(self, path):
46 if type(path) != type([]):
48 return map(self.subst, path)
49 def get_calculator(self):
50 return SCons.Sig.default_calc
52 class FindPathDirsTestCase(unittest.TestCase):
53 def test_FindPathDirs(self):
54 """Test the FindPathDirs callable class"""
57 def Rsearchall(self, nodes, must_exist=0, clazz=None, cwd=dir):
58 return ['xxx'] + nodes
60 env = DummyEnvironment(LIBPATH = [ 'foo' ])
62 fpd = SCons.Scanner.FindPathDirs('LIBPATH', FS())
63 result = fpd(env, dir)
64 assert result == ('xxx', 'foo'), result
66 class ScannerTestCase(unittest.TestCase):
68 def func(self, filename, env, target, *args):
69 self.filename = filename
78 def test(self, scanner, env, filename, deps, *args):
80 path = scanner.path(env)
81 scanned = scanner(filename, env, path)
82 scanned_strs = map(lambda x: str(x), scanned)
84 self.failUnless(self.filename == filename, "the filename was passed incorrectly")
85 self.failUnless(self.env == env, "the environment was passed incorrectly")
86 self.failUnless(scanned_strs == deps, "the dependencies were returned incorrectly")
88 self.failUnless(type(d) != type(""), "got a string in the dependencies")
91 self.failUnless(self.arg == args[0], "the argument was passed incorrectly")
93 self.failIf(hasattr(self, "arg"), "an argument was given when it shouldn't have been")
95 def test_positional(self):
96 """Test the Scanner.Base class using positional arguments"""
97 s = SCons.Scanner.Base(self.func, "Pos")
98 env = DummyEnvironment()
100 self.test(s, env, 'f1.cpp', ['f1.h', 'f1.hpp'])
102 env = DummyEnvironment()
104 self.test(s, env, 'i1.cpp', ['i1.h', 'i1.hpp'])
106 def test_keywords(self):
107 """Test the Scanner.Base class using keyword arguments"""
108 s = SCons.Scanner.Base(function = self.func, name = "Key")
109 env = DummyEnvironment()
110 env.VARIABLE = "var2"
111 self.test(s, env, 'f2.cpp', ['f2.h', 'f2.hpp'])
113 env = DummyEnvironment()
115 self.test(s, env, 'i2.cpp', ['i2.h', 'i2.hpp'])
117 def test_pos_opt(self):
118 """Test the Scanner.Base class using both position and optional arguments"""
119 arg = "this is the argument"
120 s = SCons.Scanner.Base(self.func, "PosArg", arg)
121 env = DummyEnvironment()
122 env.VARIABLE = "var3"
123 self.test(s, env, 'f3.cpp', ['f3.h', 'f3.hpp'], arg)
125 env = DummyEnvironment()
127 self.test(s, env, 'i3.cpp', ['i3.h', 'i3.hpp'], arg)
129 def test_key_opt(self):
130 """Test the Scanner.Base class using both keyword and optional arguments"""
131 arg = "this is another argument"
132 s = SCons.Scanner.Base(function = self.func, name = "KeyArg",
134 env = DummyEnvironment()
135 env.VARIABLE = "var4"
136 self.test(s, env, 'f4.cpp', ['f4.h', 'f4.hpp'], arg)
138 env = DummyEnvironment()
140 self.test(s, env, 'i4.cpp', ['i4.h', 'i4.hpp'], arg)
143 """Test the Scanner.Base class __hash__() method"""
144 s = SCons.Scanner.Base(self.func, "Hash")
147 self.failUnless(hash(dict.keys()[0]) == hash(repr(s)),
148 "did not hash Scanner base class as expected")
150 def test_scan_check(self):
151 """Test the Scanner.Base class scan_check() method"""
152 def my_scan(filename, env, target, *args):
154 def check(node, env, s=self):
157 env = DummyEnvironment()
158 s = SCons.Scanner.Base(my_scan, "Check", scan_check = check)
161 scanned = s('x', env, path)
162 self.failUnless(self.checked['x'] == 1,
163 "did not call check function")
165 def test_recursive(self):
166 """Test the Scanner.Base class recursive flag"""
167 s = SCons.Scanner.Base(function = self.func)
168 self.failUnless(s.recursive == None,
169 "incorrect default recursive value")
170 s = SCons.Scanner.Base(function = self.func, recursive = None)
171 self.failUnless(s.recursive == None,
172 "did not set recursive flag to None")
173 s = SCons.Scanner.Base(function = self.func, recursive = 1)
174 self.failUnless(s.recursive == 1,
175 "did not set recursive flag to 1")
177 def test_get_skeys(self):
178 """Test the Scanner.Base get_skeys() method"""
179 s = SCons.Scanner.Base(function = self.func)
181 self.failUnless(sk == [],
182 "did not initialize to expected []")
184 s = SCons.Scanner.Base(function = self.func, skeys = ['.1', '.2'])
186 self.failUnless(sk == ['.1', '.2'],
187 "sk was %s, not ['.1', '.2']")
189 s = SCons.Scanner.Base(function = self.func, skeys = '$LIST')
190 env = DummyEnvironment(LIST = ['.3', '.4'])
191 sk = s.get_skeys(env)
192 self.failUnless(sk == ['.3', '.4'],
193 "sk was %s, not ['.3', '.4']")
195 class CurrentTestCase(unittest.TestCase):
196 def test_class(self):
197 """Test the Scanner.Current class"""
200 self.called_has_builder = None
201 self.called_current = None
202 self.func_called = None
203 class HasNoBuilder(MyNode):
204 def has_builder(self):
205 self.called_has_builder = 1
207 class IsNotCurrent(MyNode):
208 def has_builder(self):
209 self.called_has_builder = 1
211 def current(self, sig):
212 self.called_current = 1
214 class IsCurrent(MyNode):
215 def has_builder(self):
216 self.called_has_builder = 1
218 def current(self, sig):
219 self.called_current = 1
221 def func(node, env, path):
224 env = DummyEnvironment()
225 s = SCons.Scanner.Current(func)
229 self.failUnless(hnb.called_has_builder, "did not call has_builder()")
230 self.failUnless(not hnb.called_current, "did call current()")
231 self.failUnless(hnb.func_called, "did not call func()")
234 self.failUnless(inc.called_has_builder, "did not call has_builder()")
235 self.failUnless(inc.called_current, "did not call current()")
236 self.failUnless(not inc.func_called, "did call func()")
239 self.failUnless(ic.called_has_builder, "did not call has_builder()")
240 self.failUnless(ic.called_current, "did not call current()")
241 self.failUnless(ic.func_called, "did not call func()")
243 class ClassicTestCase(unittest.TestCase):
244 def test_find_include(self):
245 """Test the Scanner.Classic find_include() method"""
246 env = DummyEnvironment()
247 s = SCons.Scanner.Classic("t", ['.suf'], 'MYPATH', '^my_inc (\S+)')
249 def _find_file(filename, paths, factory):
250 return paths[0]+'/'+filename
252 save = SCons.Node.FS.find_file
253 SCons.Node.FS.find_file = _find_file
256 n, i = s.find_include('aaa', 'foo', ('path',))
257 assert n == 'foo/aaa', n
261 SCons.Node.FS.find_file = save
264 """Test setting the Scanner.Classic name"""
265 s = SCons.Scanner.Classic("my_name", ['.s'], 'MYPATH', '^my_inc (\S+)')
266 assert s.name == "my_name", s.name
269 """Test the Scanner.Classic scan() method"""
271 def __init__(self, name):
279 def get_contents(self):
280 return self._contents
284 class MyScanner(SCons.Scanner.Classic):
285 def find_include(self, include, source_dir, path):
286 return include, include
288 env = DummyEnvironment()
289 s = MyScanner("t", ['.suf'], 'MYPATH', '^my_inc (\S+)')
291 # If the node doesn't exist, scanning turns up nothing.
294 ret = s.scan(n1, env)
295 assert ret == [], ret
297 # Verify that it finds includes from the contents.
300 n._dir = MyNode("n._dir")
301 n._contents = 'my_inc abc\n'
303 assert ret == ['abc'], ret
305 # Verify that it uses the cached include info.
306 n._contents = 'my_inc def\n'
308 assert ret == ['abc'], ret
310 # Verify that if we wipe the cache, it uses the new contents.
313 assert ret == ['def'], ret
315 # Verify that it sorts what it finds.
316 n.includes = ['xyz', 'uvw']
318 assert ret == ['uvw', 'xyz'], ret
320 # Verify that we use the rfile() node.
323 nr._dir = MyNode("nr._dir")
324 nr.includes = ['jkl', 'mno']
327 assert ret == ['jkl', 'mno'], ret
329 class ClassicCPPTestCase(unittest.TestCase):
330 def test_find_include(self):
331 """Test the Scanner.ClassicCPP find_include() method"""
332 env = DummyEnvironment()
333 s = SCons.Scanner.ClassicCPP("Test", [], None, "")
335 def _find_file(filename, paths, factory):
336 return paths[0]+'/'+filename
338 save = SCons.Node.FS.find_file
339 SCons.Node.FS.find_file = _find_file
342 n, i = s.find_include(('"', 'aaa'), 'foo', ('path',))
343 assert n == 'foo/aaa', n
346 n, i = s.find_include(('<', 'bbb'), 'foo', ('path',))
347 assert n == 'path/bbb', n
351 SCons.Node.FS.find_file = _find_file
354 suite = unittest.TestSuite()
356 FindPathDirsTestCase,
362 for tclass in tclasses:
363 names = unittest.getTestCaseNames(tclass, 'test_')
364 suite.addTests(map(tclass, names))
367 if __name__ == "__main__":
368 runner = unittest.TextTestRunner()
369 result = runner.run(suite())
370 if not result.wasSuccessful():