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__"
32 class DummyEnvironment(UserDict.UserDict):
33 def __init__(self, dict=None, **kw):
34 UserDict.UserDict.__init__(self, dict)
36 def subst(self, strSubst):
37 if strSubst[0] == '$':
38 return self.data[strSubst[1:]]
40 def subst_list(self, strSubst):
41 if strSubst[0] == '$':
42 return [self.data[strSubst[1:]]]
44 def subst_path(self, path):
45 if type(path) != type([]):
47 return map(self.subst, path)
49 class FindPathDirsTestCase(unittest.TestCase):
50 def test_FindPathDirs(self):
51 """Test the FindPathDirs callable class"""
54 def Rsearchall(self, nodes, must_exist=0, clazz=None, cwd=dir):
55 return ['xxx'] + nodes
57 env = DummyEnvironment(LIBPATH = [ 'foo' ])
59 fpd = SCons.Scanner.FindPathDirs('LIBPATH', FS())
60 result = fpd(env, dir)
61 assert result == ('xxx', 'foo'), result
63 class ScannerTestCase(unittest.TestCase):
65 def func(self, filename, env, target, *args):
66 self.filename = filename
75 def test(self, scanner, env, filename, deps, *args):
77 path = scanner.path(env)
78 scanned = scanner(filename, env, path)
79 scanned_strs = map(lambda x: str(x), scanned)
81 self.failUnless(self.filename == filename, "the filename was passed incorrectly")
82 self.failUnless(self.env == env, "the environment was passed incorrectly")
83 self.failUnless(scanned_strs == deps, "the dependencies were returned incorrectly")
85 self.failUnless(type(d) != type(""), "got a string in the dependencies")
88 self.failUnless(self.arg == args[0], "the argument was passed incorrectly")
90 self.failIf(hasattr(self, "arg"), "an argument was given when it shouldn't have been")
92 def test_positional(self):
93 """Test the Scanner.Base class using positional arguments"""
94 s = SCons.Scanner.Base(self.func, "Pos")
95 env = DummyEnvironment()
97 self.test(s, env, 'f1.cpp', ['f1.h', 'f1.hpp'])
99 env = DummyEnvironment()
101 self.test(s, env, 'i1.cpp', ['i1.h', 'i1.hpp'])
103 def test_keywords(self):
104 """Test the Scanner.Base class using keyword arguments"""
105 s = SCons.Scanner.Base(function = self.func, name = "Key")
106 env = DummyEnvironment()
107 env.VARIABLE = "var2"
108 self.test(s, env, 'f2.cpp', ['f2.h', 'f2.hpp'])
110 env = DummyEnvironment()
112 self.test(s, env, 'i2.cpp', ['i2.h', 'i2.hpp'])
114 def test_pos_opt(self):
115 """Test the Scanner.Base class using both position and optional arguments"""
116 arg = "this is the argument"
117 s = SCons.Scanner.Base(self.func, "PosArg", arg)
118 env = DummyEnvironment()
119 env.VARIABLE = "var3"
120 self.test(s, env, 'f3.cpp', ['f3.h', 'f3.hpp'], arg)
122 env = DummyEnvironment()
124 self.test(s, env, 'i3.cpp', ['i3.h', 'i3.hpp'], arg)
126 def test_key_opt(self):
127 """Test the Scanner.Base class using both keyword and optional arguments"""
128 arg = "this is another argument"
129 s = SCons.Scanner.Base(function = self.func, name = "KeyArg",
131 env = DummyEnvironment()
132 env.VARIABLE = "var4"
133 self.test(s, env, 'f4.cpp', ['f4.h', 'f4.hpp'], arg)
135 env = DummyEnvironment()
137 self.test(s, env, 'i4.cpp', ['i4.h', 'i4.hpp'], arg)
140 """Test the Scanner.Base class __hash__() method"""
141 s = SCons.Scanner.Base(self.func, "Hash")
144 self.failUnless(hash(dict.keys()[0]) == hash(repr(s)),
145 "did not hash Scanner base class as expected")
147 def test_scan_check(self):
148 """Test the Scanner.Base class scan_check() method"""
149 def my_scan(filename, env, target, *args):
151 def check(node, s=self):
154 env = DummyEnvironment()
155 s = SCons.Scanner.Base(my_scan, "Check", scan_check = check)
158 scanned = s('x', env, path)
159 self.failUnless(self.checked['x'] == 1,
160 "did not call check function")
162 def test_recursive(self):
163 """Test the Scanner.Base class recursive flag"""
164 s = SCons.Scanner.Base(function = self.func)
165 self.failUnless(s.recursive == None,
166 "incorrect default recursive value")
167 s = SCons.Scanner.Base(function = self.func, recursive = None)
168 self.failUnless(s.recursive == None,
169 "did not set recursive flag to None")
170 s = SCons.Scanner.Base(function = self.func, recursive = 1)
171 self.failUnless(s.recursive == 1,
172 "did not set recursive flag to 1")
174 def test_get_skeys(self):
175 """Test the Scanner.Base get_skeys() method"""
176 s = SCons.Scanner.Base(function = self.func)
178 self.failUnless(sk == [],
179 "did not initialize to expected []")
181 s = SCons.Scanner.Base(function = self.func, skeys = ['.1', '.2'])
183 self.failUnless(sk == ['.1', '.2'],
184 "sk was %s, not ['.1', '.2']")
186 s = SCons.Scanner.Base(function = self.func, skeys = '$LIST')
187 env = DummyEnvironment(LIST = ['.3', '.4'])
188 sk = s.get_skeys(env)
189 self.failUnless(sk == ['.3', '.4'],
190 "sk was %s, not ['.3', '.4']")
192 class CurrentTestCase(unittest.TestCase):
193 def test_class(self):
194 """Test the Scanner.Current class"""
197 self.called_has_builder = None
198 self.called_current = None
199 self.func_called = None
200 class HasNoBuilder(MyNode):
201 def has_builder(self):
202 self.called_has_builder = 1
204 class IsNotCurrent(MyNode):
205 def has_builder(self):
206 self.called_has_builder = 1
208 def current(self, sig):
209 self.called_current = 1
211 class IsCurrent(MyNode):
212 def has_builder(self):
213 self.called_has_builder = 1
215 def current(self, sig):
216 self.called_current = 1
218 def func(node, env, path):
221 env = DummyEnvironment()
222 s = SCons.Scanner.Current(func)
226 self.failUnless(hnb.called_has_builder, "did not call has_builder()")
227 self.failUnless(not hnb.called_current, "did call current()")
228 self.failUnless(hnb.func_called, "did not call func()")
231 self.failUnless(inc.called_has_builder, "did not call has_builder()")
232 self.failUnless(inc.called_current, "did not call current()")
233 self.failUnless(not inc.func_called, "did call func()")
236 self.failUnless(ic.called_has_builder, "did not call has_builder()")
237 self.failUnless(ic.called_current, "did not call current()")
238 self.failUnless(ic.func_called, "did not call func()")
240 class ClassicTestCase(unittest.TestCase):
241 def test_find_include(self):
242 """Test the Scanner.Classic find_include() method"""
243 env = DummyEnvironment()
244 s = SCons.Scanner.Classic("t", ['.suf'], 'MYPATH', '^my_inc (\S+)')
246 def _find_file(filename, paths, factory):
247 return paths[0]+'/'+filename
249 save = SCons.Node.FS.find_file
250 SCons.Node.FS.find_file = _find_file
253 n, i = s.find_include('aaa', 'foo', ('path',))
254 assert n == 'foo/aaa', n
258 SCons.Node.FS.find_file = save
261 """Test setting the Scanner.Classic name"""
262 s = SCons.Scanner.Classic("my_name", ['.s'], 'MYPATH', '^my_inc (\S+)')
263 assert s.name == "my_name", s.name
266 """Test the Scanner.Classic scan() method"""
268 def __init__(self, name):
276 def get_contents(self):
277 return self._contents
281 class MyScanner(SCons.Scanner.Classic):
282 def find_include(self, include, source_dir, path):
283 return include, include
285 env = DummyEnvironment()
286 s = MyScanner("t", ['.suf'], 'MYPATH', '^my_inc (\S+)')
288 # If the node doesn't exist, scanning turns up nothing.
291 ret = s.scan(n1, env)
292 assert ret == [], ret
294 # Verify that it finds includes from the contents.
297 n._dir = MyNode("n._dir")
298 n._contents = 'my_inc abc\n'
300 assert ret == ['abc'], ret
302 # Verify that it uses the cached include info.
303 n._contents = 'my_inc def\n'
305 assert ret == ['abc'], ret
307 # Verify that if we wipe the cache, it uses the new contents.
310 assert ret == ['def'], ret
312 # Verify that it sorts what it finds.
313 n.includes = ['xyz', 'uvw']
315 assert ret == ['uvw', 'xyz'], ret
317 # Verify that we use the rfile() node.
320 nr._dir = MyNode("nr._dir")
321 nr.includes = ['jkl', 'mno']
324 assert ret == ['jkl', 'mno'], ret
326 class ClassicCPPTestCase(unittest.TestCase):
327 def test_find_include(self):
328 """Test the Scanner.ClassicCPP find_include() method"""
329 env = DummyEnvironment()
330 s = SCons.Scanner.ClassicCPP("Test", [], None, "")
332 def _find_file(filename, paths, factory):
333 return paths[0]+'/'+filename
335 save = SCons.Node.FS.find_file
336 SCons.Node.FS.find_file = _find_file
339 n, i = s.find_include(('"', 'aaa'), 'foo', ('path',))
340 assert n == 'foo/aaa', n
343 n, i = s.find_include(('<', 'bbb'), 'foo', ('path',))
344 assert n == 'path/bbb', n
348 SCons.Node.FS.find_file = _find_file
351 suite = unittest.TestSuite()
353 FindPathDirsTestCase,
359 for tclass in tclasses:
360 names = unittest.getTestCaseNames(tclass, 'test_')
361 suite.addTests(map(tclass, names))
364 if __name__ == "__main__":
365 runner = unittest.TextTestRunner()
366 result = runner.run(suite())
367 if not result.wasSuccessful():