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 from TestCmd import TestCmd
42 # This will be built-in in 2.3. For now fake it.
52 def __init__(self, node=None):
54 scanner_count = scanner_count + 1
55 self.hash = scanner_count
57 def path(self, env, target):
59 def __call__(self, node, env, path):
63 def select(self, node):
68 self.scanner = Scanner()
69 def Dictionary(self, *args):
71 def autogenerate(self, **kw):
73 def get_scanner(self, skey):
75 def Override(self, overrides):
77 def _update(self, dict):
81 def __call__(self, targets, sources, env, errfunc, **kw):
83 if kw.get('execute', 1):
86 def show(self, string):
88 def strfunction(self, targets, sources, env):
90 def get_actions(self):
94 def __init__(self, factory, action=Action()):
95 self.factory = factory
96 self.env = Environment()
100 def get_actions(self):
103 def targets(self, t):
106 def source_factory(self, name):
107 return self.factory(name)
109 class BuildDirTestCase(unittest.TestCase):
111 """Test build dir functionality"""
112 test=TestCmd(workdir='')
114 fs = SCons.Node.FS.FS()
115 f1 = fs.File('build/test1')
116 fs.BuildDir('build', 'src')
117 f2 = fs.File('build/test2')
119 assert f1.srcnode().path == os.path.normpath('src/test1'), f1.srcnode().path
120 assert f2.srcnode().path == os.path.normpath('src/test2'), f2.srcnode().path
121 assert d1.srcnode().path == 'src', d1.srcnode().path
123 fs = SCons.Node.FS.FS()
124 f1 = fs.File('build/test1')
125 fs.BuildDir('build', '.')
126 f2 = fs.File('build/test2')
128 assert f1.srcnode().path == 'test1', f1.srcnode().path
129 assert f2.srcnode().path == 'test2', f2.srcnode().path
130 assert d1.srcnode().path == '.', d1.srcnode().path
132 fs = SCons.Node.FS.FS()
133 fs.BuildDir('build/var1', 'src')
134 fs.BuildDir('build/var2', 'src')
135 f1 = fs.File('build/var1/test1')
136 f2 = fs.File('build/var2/test1')
137 assert f1.srcnode().path == os.path.normpath('src/test1'), f1.srcnode().path
138 assert f2.srcnode().path == os.path.normpath('src/test1'), f2.srcnode().path
140 fs = SCons.Node.FS.FS()
141 fs.BuildDir('../var1', 'src')
142 fs.BuildDir('../var2', 'src')
143 f1 = fs.File('../var1/test1')
144 f2 = fs.File('../var2/test1')
145 assert hasattr(f1, 'overrides')
146 assert f1.srcnode().path == os.path.normpath('src/test1'), f1.srcnode().path
147 assert f2.srcnode().path == os.path.normpath('src/test1'), f2.srcnode().path
150 test.subdir('work', ['work', 'src'])
151 test.subdir(['work', 'build'], ['work', 'build', 'var1'])
152 test.subdir(['work', 'build', 'var2'])
153 test.subdir('rep1', ['rep1', 'src'])
154 test.subdir(['rep1', 'build'], ['rep1', 'build', 'var1'])
155 test.subdir(['rep1', 'build', 'var2'])
157 # A source file in the source directory
158 test.write([ 'work', 'src', 'test.in' ], 'test.in')
160 # A source file in a subdir of the source directory
161 test.subdir([ 'work', 'src', 'new_dir' ])
162 test.write([ 'work', 'src', 'new_dir', 'test9.out' ], 'test9.out\n')
164 # A source file in the repository
165 test.write([ 'rep1', 'src', 'test2.in' ], 'test2.in')
167 # Some source files in the build directory
168 test.write([ 'work', 'build', 'var2', 'test.in' ], 'test.old')
169 test.write([ 'work', 'build', 'var2', 'test2.in' ], 'test2.old')
171 # An old derived file in the build directories
172 test.write([ 'work', 'build', 'var1', 'test.out' ], 'test.old')
173 test.write([ 'work', 'build', 'var2', 'test.out' ], 'test.old')
175 # And just in case we are weird, a derived file in the source
177 test.write([ 'work', 'src', 'test.out' ], 'test.out.src')
179 # A derived file in the repository
180 test.write([ 'rep1', 'build', 'var1', 'test2.out' ], 'test2.out_rep')
181 test.write([ 'rep1', 'build', 'var2', 'test2.out' ], 'test2.out_rep')
183 os.chdir(test.workpath('work'))
185 fs = SCons.Node.FS.FS(test.workpath('work'))
186 fs.BuildDir('build/var1', 'src', duplicate=0)
187 fs.BuildDir('build/var2', 'src')
188 f1 = fs.File('build/var1/test.in')
189 f1out = fs.File('build/var1/test.out')
191 f1out_2 = fs.File('build/var1/test2.out')
193 f2 = fs.File('build/var2/test.in')
194 f2out = fs.File('build/var2/test.out')
196 f2out_2 = fs.File('build/var2/test2.out')
198 fs.Repository(test.workpath('rep1'))
200 assert f1.srcnode().path == os.path.normpath('src/test.in'),\
202 # str(node) returns source path for duplicate = 0
203 assert str(f1) == os.path.normpath('src/test.in'), str(f1)
204 # Build path does not exist
205 assert not f1.exists()
206 # ...but the actual file is not there...
207 assert not os.path.exists(f1.get_abspath())
208 # And duplicate=0 should also work just like a Repository
210 # rfile() should point to the source path
211 assert f1.rfile().path == os.path.normpath('src/test.in'),\
214 assert f2.srcnode().path == os.path.normpath('src/test.in'),\
216 # str(node) returns build path for duplicate = 1
217 assert str(f2) == os.path.normpath('build/var2/test.in'), str(f2)
220 # ...and should copy the file from src to build path
221 assert test.read(['work', 'build', 'var2', 'test.in']) == 'test.in',\
222 test.read(['work', 'build', 'var2', 'test.in'])
223 # Since exists() is true, so should rexists() be
226 f3 = fs.File('build/var1/test2.in')
227 f4 = fs.File('build/var2/test2.in')
229 assert f3.srcnode().path == os.path.normpath('src/test2.in'),\
231 # str(node) returns source path for duplicate = 0
232 assert str(f3) == os.path.normpath('src/test2.in'), str(f3)
233 # Build path does not exist
234 assert not f3.exists()
235 # Source path does not either
236 assert not f3.srcnode().exists()
237 # But we do have a file in the Repository
239 # rfile() should point to the source path
240 assert f3.rfile().path == os.path.normpath(test.workpath('rep1/src/test2.in')),\
243 assert f4.srcnode().path == os.path.normpath('src/test2.in'),\
245 # str(node) returns build path for duplicate = 1
246 assert str(f4) == os.path.normpath('build/var2/test2.in'), str(f4)
247 # Build path should exist
249 # ...and copy over the file into the local build path
250 assert test.read(['work', 'build', 'var2', 'test2.in']) == 'test2.in'
251 # should exist in repository, since exists() is true
253 # rfile() should point to ourselves
254 assert f4.rfile().path == os.path.normpath('build/var2/test2.in'),\
257 f5 = fs.File('build/var1/test.out')
258 f6 = fs.File('build/var2/test.out')
261 # We should not copy the file from the source dir, since this is
263 assert test.read(['work', 'build', 'var1', 'test.out']) == 'test.old'
266 # We should not copy the file from the source dir, since this is
268 assert test.read(['work', 'build', 'var2', 'test.out']) == 'test.old'
270 f7 = fs.File('build/var1/test2.out')
271 f8 = fs.File('build/var2/test2.out')
273 assert not f7.exists()
275 assert f7.rfile().path == os.path.normpath(test.workpath('rep1/build/var1/test2.out')),\
278 assert not f8.exists()
280 assert f8.rfile().path == os.path.normpath(test.workpath('rep1/build/var2/test2.out')),\
283 # Verify the Mkdir and Link actions are called
284 d9 = fs.Dir('build/var2/new_dir')
285 f9 = fs.File('build/var2/new_dir/test9.out')
287 class MkdirAction(Action):
288 def __init__(self, dir_made):
289 self.dir_made = dir_made
290 def __call__(self, target, source, env, errfunc):
291 self.dir_made.extend(target)
293 save_Link = SCons.Node.FS.Link
295 def link_func(target, source, env, link_made=link_made):
296 link_made.append(target)
297 SCons.Node.FS.Link = link_func
301 d9.builder = Builder(fs.Dir, action=MkdirAction(dir_made))
303 expect = os.path.join('build', 'var2', 'new_dir')
304 assert dir_made[0].path == expect, dir_made[0].path
305 expect = os.path.join('build', 'var2', 'new_dir', 'test9.out')
306 assert link_made[0].path == expect, link_made[0].path
309 SCons.Node.FS.Link = save_Link
311 # Test for an interesting pathological case...we have a source
312 # file in a build path, but not in a source path. This can
313 # happen if you switch from duplicate=1 to duplicate=0, then
314 # delete a source file. At one time, this would cause exists()
315 # to return a 1 but get_contents() to throw.
316 test.write([ 'work', 'build', 'var1', 'asourcefile' ], 'stuff')
317 f10 = fs.File('build/var1/asourcefile')
319 assert f10.get_contents() == 'stuff', f10.get_contents()
321 f11 = fs.File('src/file11')
322 t, m = f11.alter_targets()
323 bdt = map(lambda n: n.path, t)
324 var1_file11 = os.path.normpath('build/var1/file11')
325 var2_file11 = os.path.normpath('build/var2/file11')
326 assert bdt == [var1_file11, var2_file11], bdt
328 f12 = fs.File('src/file12')
330 bdt, m = f12.alter_targets()
331 assert bdt == [], map(lambda n: n.path, bdt)
333 d13 = fs.Dir('src/new_dir')
334 t, m = d13.alter_targets()
335 bdt = map(lambda n: n.path, t)
336 var1_new_dir = os.path.normpath('build/var1/new_dir')
337 var2_new_dir = os.path.normpath('build/var2/new_dir')
338 assert bdt == [var1_new_dir, var2_new_dir], bdt
340 # Test that an IOError trying to Link a src file
341 # into a BuildDir ends up throwing a StopError.
342 fIO = fs.File("build/var2/IOError")
344 save_Link = SCons.Node.FS.Link
345 def Link_IOError(target, source, env):
346 raise IOError, "Link_IOError"
347 SCons.Node.FS.Link = SCons.Action.Action(Link_IOError, None)
349 test.write(['work', 'src', 'IOError'], "work/src/IOError\n")
355 except SCons.Errors.StopError:
357 assert exc_caught, "Should have caught a StopError"
360 SCons.Node.FS.Link = save_Link
362 # Test to see if Link() works...
363 test.subdir('src','build')
364 test.write('src/foo', 'src/foo\n')
365 os.chmod(test.workpath('src/foo'), stat.S_IRUSR)
366 SCons.Node.FS.Link(fs.File(test.workpath('build/foo')),
367 fs.File(test.workpath('src/foo')),
369 os.chmod(test.workpath('src/foo'), stat.S_IRUSR | stat.S_IWRITE)
370 st=os.stat(test.workpath('build/foo'))
371 assert (stat.S_IMODE(st[stat.ST_MODE]) & stat.S_IWRITE), \
372 stat.S_IMODE(st[stat.ST_MODE])
376 fs = SCons.Node.FS.FS()
377 fs.BuildDir('build', '/test/foo')
378 except SCons.Errors.UserError:
380 assert exc_caught, "Should have caught a UserError."
385 fs = SCons.Node.FS.FS()
386 fs.BuildDir('build', 'build/src')
387 except SCons.Errors.UserError:
389 assert exc_caught, "Should have caught a UserError."
391 test.unlink( "src/foo" )
392 test.unlink( "build/foo" )
394 fs = SCons.Node.FS.FS()
395 fs.BuildDir('build', 'src1')
397 # Calling the same BuildDir twice should work fine.
398 fs.BuildDir('build', 'src1')
400 # Trying to move a build dir to a second source dir
403 fs.BuildDir('build', 'src2')
404 except SCons.Errors.UserError:
407 assert 0, "Should have caught a UserError."
409 # Test against a former bug. Make sure we can get a repository
410 # path for the build directory itself!
411 fs=SCons.Node.FS.FS(test.workpath('work'))
413 fs.BuildDir('build/var3', 'src', duplicate=0)
414 d1 = fs.Dir('build/var3')
415 assert d1.rdir() == fs.Dir('src'), str(d1.rdir())
417 # verify the link creation attempts in file_link()
418 class LinkSimulator :
419 """A class to intercept os.[sym]link() calls and track them."""
421 def __init__( self, duplicate ) :
422 self.duplicate = duplicate
426 """Reset the simulator if necessary"""
427 if not self._need_reset() : return # skip if not needed now
428 self.links_to_be_called = self.duplicate
430 def _need_reset( self ) :
432 Determines whether or not the simulator needs to be reset.
433 A reset is necessary if the object is first being initialized,
434 or if all three methods have been tried already.
437 ( not hasattr( self , "links_to_be_called" ) )
439 (self.links_to_be_called == "")
442 def link_fail( self , src , dest ) :
444 l = string.split(self.links_to_be_called, "-")
446 assert next_link == "hard", \
447 "Wrong link order: expected %s to be called "\
448 "instead of hard" % next_link
449 self.links_to_be_called = string.join(l[1:], '-')
450 raise OSError( "Simulating hard link creation error." )
452 def symlink_fail( self , src , dest ) :
454 l = string.split(self.links_to_be_called, "-")
456 assert next_link == "soft", \
457 "Wrong link order: expected %s to be called "\
458 "instead of soft" % next_link
459 self.links_to_be_called = string.join(l[1:], '-')
460 raise OSError( "Simulating symlink creation error." )
462 def copy( self , src , dest ) :
464 l = string.split(self.links_to_be_called, "-")
466 assert next_link == "copy", \
467 "Wrong link order: expected %s to be called "\
468 "instead of copy" % next_link
469 self.links_to_be_called = string.join(l[1:], '-')
470 # copy succeeds, but use the real copy
471 self._real_copy(src, dest)
472 # end class LinkSimulator
475 SCons.Node.FS.set_duplicate("no-link-order")
476 assert 0, "Expected exception when passing an invalid duplicate to set_duplicate"
477 except SCons.Errors.InternalError:
480 for duplicate in SCons.Node.FS.Valid_Duplicates:
481 simulator = LinkSimulator(duplicate)
483 # save the real functions for later restoration
488 except AttributeError:
491 real_symlink = os.symlink
492 except AttributeError:
494 real_copy = shutil.copy2
495 simulator._real_copy = real_copy # the simulator needs the real one
497 # override the real functions with our simulation
498 os.link = simulator.link_fail
499 os.symlink = simulator.symlink_fail
500 shutil.copy2 = simulator.copy
501 SCons.Node.FS.set_duplicate(duplicate)
503 src_foo = test.workpath('src', 'foo')
504 build_foo = test.workpath('build', 'foo')
507 test.write(src_foo, 'src/foo\n')
508 os.chmod(src_foo, stat.S_IRUSR)
510 SCons.Node.FS.Link(fs.File(build_foo),
514 os.chmod(src_foo, stat.S_IRUSR | stat.S_IWRITE)
516 test.unlink(build_foo)
519 # restore the real functions
525 os.symlink = real_symlink
527 delattr(os, 'symlink')
528 shutil.copy2 = real_copy
530 class FSTestCase(unittest.TestCase):
532 """Test FS (file system) Node operations
534 This test case handles all of the file system node
535 tests in one environment, so we don't have to set up a
536 complicated directory structure for each test individually.
538 test = TestCmd(workdir = '')
539 test.subdir('sub', ['sub', 'dir'])
541 wp = test.workpath('')
542 sub = test.workpath('sub', '')
543 sub_dir = test.workpath('sub', 'dir', '')
544 sub_dir_foo = test.workpath('sub', 'dir', 'foo', '')
545 sub_dir_foo_bar = test.workpath('sub', 'dir', 'foo', 'bar', '')
546 sub_foo = test.workpath('sub', 'foo', '')
550 fs = SCons.Node.FS.FS()
553 assert isinstance(e1, SCons.Node.FS.Entry)
556 assert isinstance(d1, SCons.Node.FS.Dir)
557 assert d1.cwd is d1, d1
559 f1 = fs.File('f1', directory = d1)
560 assert isinstance(f1, SCons.Node.FS.File)
562 d1_f1 = os.path.join('d1', 'f1')
563 assert f1.path == d1_f1, "f1.path %s != %s" % (f1.path, d1_f1)
564 assert str(f1) == d1_f1, "str(f1) %s != %s" % (str(f1), d1_f1)
567 assert isinstance(x1, SCons.Node.FS.File)
568 assert str(x1) == os.path.join('d1', 'x1')
571 assert isinstance(x2, SCons.Node.FS.Dir)
572 assert str(x2) == os.path.join('d1', 'x2')
575 assert isinstance(x3, SCons.Node.FS.Entry)
576 assert str(x3) == os.path.join('d1', 'x3')
578 assert d1.File(x1) == x1
579 assert d1.Dir(x2) == x2
580 assert d1.Entry(x3) == x3
585 assert str(x4) == os.path.join('d1', 'x4')
588 assert str(x5) == os.path.join('d1', 'x5')
591 assert str(x6) == os.path.join('d1', 'x6')
593 assert str(x7) == os.path.join('d1', 'x7')
595 assert x1.File(x4) == x4
596 assert x1.Dir(x5) == x5
597 assert x1.Entry(x6) == x6
598 assert x1.Entry(x7) == x7
600 assert x1.Entry(x5) == x5
608 assert x1.Entry(x4) == x4
617 assert isinstance(x6, SCons.Node.FS.File)
620 assert isinstance(x7, SCons.Node.FS.Dir)
628 def Dir_test(lpath, path_, abspath_, up_path_, fileSys=fs, s=sep):
629 dir = fileSys.Dir(string.replace(lpath, '/', s))
632 path_ = string.replace(path_, '/', os.sep)
633 abspath_ = string.replace(abspath_, '/', os.sep)
634 up_path_ = string.replace(up_path_, '/', os.sep)
637 if p[-1] == os.sep and len(p) > 1:
640 path = strip_slash(path_)
641 abspath = strip_slash(abspath_)
642 up_path = strip_slash(up_path_)
643 name = string.split(abspath, os.sep)[-1]
645 assert dir.name == name, \
646 "dir.name %s != expected name %s" % \
648 assert dir.path == path, \
649 "dir.path %s != expected path %s" % \
651 assert str(dir) == path, \
652 "str(dir) %s != expected path %s" % \
654 assert dir.get_abspath() == abspath, \
655 "dir.abspath %s != expected absolute path %s" % \
656 (dir.get_abspath(), abspath)
657 assert dir.up().path == up_path, \
658 "dir.up().path %s != expected parent path %s" % \
659 (dir.up().path, up_path)
661 Dir_test('foo', 'foo/', sub_dir_foo, './')
662 Dir_test('foo/bar', 'foo/bar/', sub_dir_foo_bar, 'foo/')
663 Dir_test('/foo', '/foo/', '/foo/', '/')
664 Dir_test('/foo/bar', '/foo/bar/', '/foo/bar/', '/foo/')
665 Dir_test('..', sub, sub, wp)
666 Dir_test('foo/..', './', sub_dir, sub)
667 Dir_test('../foo', sub_foo, sub_foo, sub)
668 Dir_test('.', './', sub_dir, sub)
669 Dir_test('./.', './', sub_dir, sub)
670 Dir_test('foo/./bar', 'foo/bar/', sub_dir_foo_bar, 'foo/')
671 Dir_test('#../foo', sub_foo, sub_foo, sub)
672 Dir_test('#/../foo', sub_foo, sub_foo, sub)
673 Dir_test('#foo/bar', 'foo/bar/', sub_dir_foo_bar, 'foo/')
674 Dir_test('#/foo/bar', 'foo/bar/', sub_dir_foo_bar, 'foo/')
675 Dir_test('#', './', sub_dir, sub)
678 f2 = fs.File(string.join(['f1', 'f2'], sep), directory = d1)
680 assert str(x) == ("Tried to lookup File '%s' as a Dir." %
686 dir = fs.Dir(string.join(['d1', 'f1'], sep))
688 assert str(x) == ("Tried to lookup File '%s' as a Dir." %
696 assert str(x) == ("Tried to lookup Dir '%s' as a File." %
701 # Test that just specifying the drive works to identify
702 # its root directory.
703 p = os.path.abspath(test.workpath('root_file'))
704 drive, path = os.path.splitdrive(p)
706 # The assert below probably isn't correct for the
707 # general case, but it works for Win32, which covers a
710 assert str(dir) == drive + os.sep, str(dir)
714 fs.File(string.join(['ddd', 'f1'], sep))
715 fs.File(string.join(['ddd', 'f2'], sep))
716 fs.File(string.join(['ddd', 'f3'], sep))
717 fs.Dir(string.join(['ddd', 'd1'], sep))
718 fs.Dir(string.join(['ddd', 'd1', 'f4'], sep))
719 fs.Dir(string.join(['ddd', 'd1', 'f5'], sep))
721 kids = map(lambda x: x.path, dir.children(None))
723 assert kids == [os.path.join('ddd', 'd1'),
724 os.path.join('ddd', 'f1'),
725 os.path.join('ddd', 'f2'),
726 os.path.join('ddd', 'f3')], kids
728 # Test for a bug in 0.04 that did not like looking up
729 # dirs with a trailing slash on Win32.
731 assert d.path == '.', d.abspath
733 assert d.path == 'foo', d.abspath
735 # Test for sub-classing of node building.
740 d1.add_source([SCons.Node.Node()]) # XXX FAKE SUBCLASS ATTRIBUTE
741 d1.builder_set(Builder(fs.File))
742 d1.env_set(Environment())
748 f1.add_source([SCons.Node.Node()]) # XXX FAKE SUBCLASS ATTRIBUTE
749 f1.builder_set(Builder(fs.File))
750 f1.env_set(Environment())
754 def match(path, expect):
755 expect = string.replace(expect, '/', os.sep)
756 assert path == expect, "path %s != expected %s" % (path, expect)
759 assert e1.__class__.__name__ == 'Dir'
761 match(e1.dir.path, ".")
763 e2 = fs.Entry("d1/f1")
764 assert e2.__class__.__name__ == 'File'
765 match(e2.path, "d1/f1")
766 match(e2.dir.path, "d1")
769 assert e3.__class__.__name__ == 'Entry'
771 match(e3.dir.path, ".")
773 e4 = fs.Entry("d1/e4")
774 assert e4.__class__.__name__ == 'Entry'
775 match(e4.path, "d1/e4")
776 match(e4.dir.path, "d1")
778 e5 = fs.Entry("e3/e5")
779 assert e3.__class__.__name__ == 'Dir'
781 match(e3.dir.path, ".")
782 assert e5.__class__.__name__ == 'Entry'
783 match(e5.path, "e3/e5")
784 match(e5.dir.path, "e3")
788 assert e4.__class__.__name__ == 'Dir'
789 match(e4.path, "d1/e4")
790 match(e4.dir.path, "d1")
792 e7 = fs.File("e3/e5")
794 assert e5.__class__.__name__ == 'File'
795 match(e5.path, "e3/e5")
796 match(e5.dir.path, "e3")
798 fs.chdir(fs.Dir('subdir'))
800 match(f11.path, "subdir/f11")
802 e13 = fs.Entry("subdir/e13")
803 match(e13.path, "subdir/subdir/e13")
804 fs.chdir(fs.Dir('..'))
807 f1.builder_set(Builder(fs.File))
808 f1.env_set(Environment())
810 f1.target_scanner = Scanner(xyz)
813 assert f1.implicit[0].path == "xyz"
816 assert f1.implicit == []
819 assert f1.implicit[0].path == "xyz"
821 # Test underlying scanning functionality in get_found_includes()
826 deps = f12.get_found_includes(env, None, t1)
827 assert deps == [], deps
829 class MyScanner(Scanner):
831 def __call__(self, node, env, path):
832 self.call_count = self.call_count + 1
833 return Scanner.__call__(self, node, env, path)
836 deps = f12.get_found_includes(env, s, t1)
837 assert deps == [xyz], deps
838 assert s.call_count == 1, s.call_count
840 deps = f12.get_found_includes(env, s, t1)
841 assert deps == [xyz], deps
842 assert s.call_count == 1, s.call_count
846 deps = f12.get_found_includes(env, s, t1)
847 assert deps == [xyz], deps
848 assert s.call_count == 2, s.call_count
850 # Make sure we can scan this file even if the target isn't
851 # a file that has a scanner (it might be an Alias, e.g.).
855 deps = f12.get_found_includes(env, s, DummyNode())
856 assert deps == [xyz], deps
858 # Test building a file whose directory is not there yet...
859 f1 = fs.File(test.workpath("foo/bar/baz/ack"))
860 assert not f1.dir.exists()
863 assert f1.dir.exists()
868 fs = SCons.Node.FS.FS()
869 assert str(fs.getcwd()) == ".", str(fs.getcwd())
870 fs.chdir(fs.Dir('subdir'))
871 # The cwd's path is always "."
872 assert str(fs.getcwd()) == ".", str(fs.getcwd())
873 assert fs.getcwd().path == 'subdir', fs.getcwd().path
874 fs.chdir(fs.Dir('../..'))
875 assert fs.getcwd().path == test.workdir, fs.getcwd().path
877 f1 = fs.File(test.workpath("do_i_exist"))
878 assert not f1.exists()
879 test.write("do_i_exist","\n")
880 assert not f1.exists()
883 test.unlink("do_i_exist")
886 assert not f1.exists()
888 # For some reason, in Win32, the \x1a character terminates
889 # the reading of files in text mode. This tests that
890 # get_contents() returns the binary contents.
891 test.write("binary_file", "Foo\x1aBar")
892 f1 = SCons.Node.FS.default_fs.File(test.workpath("binary_file"))
893 assert f1.get_contents() == "Foo\x1aBar", f1.get_contents()
895 def nonexistent(method, s):
897 x = method(s, create = 0)
898 except SCons.Errors.UserError:
901 raise TestFailed, "did not catch expected UserError"
903 nonexistent(fs.Entry, 'nonexistent')
904 nonexistent(fs.Entry, 'nonexistent/foo')
906 nonexistent(fs.File, 'nonexistent')
907 nonexistent(fs.File, 'nonexistent/foo')
909 nonexistent(fs.Dir, 'nonexistent')
910 nonexistent(fs.Dir, 'nonexistent/foo')
912 test.write("preserve_me", "\n")
913 assert os.path.exists(test.workpath("preserve_me"))
914 f1 = fs.File(test.workpath("preserve_me"))
916 assert os.path.exists(test.workpath("preserve_me"))
918 test.write("remove_me", "\n")
919 assert os.path.exists(test.workpath("remove_me"))
920 f1 = fs.File(test.workpath("remove_me"))
921 f1.builder = Builder(fs.File)
922 f1.env_set(Environment())
924 assert not os.path.exists(test.workpath("remove_me"))
926 e = fs.Entry('e_local')
927 assert not hasattr(e, '_local')
930 f = fs.File('e_local')
932 f = fs.File('f_local')
935 #XXX test current() for directories
937 #XXX test sconsign() for directories
939 #XXX test set_signature() for directories
941 #XXX test build() for directories
945 # test Entry.get_contents()
946 e = fs.Entry('does_not_exist')
950 except AttributeError:
952 assert exc_caught, "Should have caught an AttributError"
954 test.write("file", "file\n")
958 assert c == "file\n", c
959 assert e.__class__ == SCons.Node.FS.File
967 assert e.__class__ == SCons.Node.FS.Dir
969 if hasattr(os, 'symlink'):
970 os.symlink('nonexistent', test.workpath('dangling_symlink'))
971 e = fs.Entry('dangling_symlink')
973 assert e.__class__ == SCons.Node.FS.Entry
976 test.write("tstamp", "tstamp\n")
978 # Okay, *this* manipulation accomodates Windows FAT file systems
979 # that only have two-second granularity on their timestamps.
980 # We round down the current time to the nearest even integer
981 # value, subtract two to make sure the timestamp is not "now,"
982 # and then convert it back to a float.
983 tstamp = float(int(time.time() / 2) * 2) - 2
984 os.utime(test.workpath("tstamp"), (tstamp - 2.0, tstamp))
985 f = fs.File("tstamp")
986 t = f.get_timestamp()
987 assert t == tstamp, "expected %f, got %f" % (tstamp, t)
989 test.unlink("tstamp")
993 t = d.get_timestamp()
994 assert t == 0, "expected 0, got %s" % str(t)
998 f1 = test.workpath('tdir2', 'file1')
999 f2 = test.workpath('tdir2', 'file2')
1000 test.write(f1, 'file1\n')
1001 test.write(f2, 'file2\n')
1004 current_time = float(int(time.time() / 2) * 2)
1005 t1 = current_time - 4.0
1006 t2 = current_time - 2.0
1007 os.utime(f1, (t1 - 2.0, t1))
1008 os.utime(f2, (t2 - 2.0, t2))
1009 t = d.get_timestamp()
1010 assert t == t2, "expected %f, got %f" % (t2, t)
1012 skey = fs.Entry('eee.x').scanner_key()
1013 assert skey == '.x', skey
1014 skey = fs.Entry('eee.xyz').scanner_key()
1015 assert skey == '.xyz', skey
1017 skey = fs.File('fff.x').scanner_key()
1018 assert skey == '.x', skey
1019 skey = fs.File('fff.xyz').scanner_key()
1020 assert skey == '.xyz', skey
1022 skey = fs.Dir('ddd.x').scanner_key()
1023 assert skey is None, skey
1025 test.write("i_am_not_a_directory", "\n")
1029 fs.Dir(test.workpath("i_am_not_a_directory"))
1032 assert exc_caught, "Should have caught a TypeError"
1034 test.unlink("i_am_not_a_directory")
1041 assert exc_caught, "Should have caught a TypeError"
1043 # XXX test calc_signature()
1045 # XXX test current()
1051 f = fs.File('does_not_exist')
1055 test.write('exists', "exists\n")
1056 f = fs.File('exists')
1059 assert not os.path.exists(test.workpath('exists')), "exists was not removed"
1061 symlink = test.workpath('symlink')
1063 os.symlink(test.workpath('does_not_exist'), symlink)
1064 assert os.path.islink(symlink)
1065 f = fs.File('symlink')
1068 assert not os.path.islink(symlink), "symlink was not removed"
1069 except AttributeError:
1072 test.write('can_not_remove', "can_not_remove\n")
1073 test.writable(test.workpath('.'), 0)
1074 fp = open(test.workpath('can_not_remove'))
1076 f = fs.File('can_not_remove')
1085 assert exc_caught, "Should have caught an OSError, r = " + str(r)
1087 f = fs.Entry('foo/bar/baz')
1088 assert f.for_signature() == 'baz', f.for_signature()
1089 assert f.get_string(0) == os.path.normpath('foo/bar/baz'), \
1091 assert f.get_string(1) == 'baz', f.get_string(1)
1094 t = x.target_from_source('pre-', '-suf')
1095 assert str(t) == 'pre-x-suf', str(t)
1097 y = fs.File('dir/y')
1098 t = y.target_from_source('pre-', '-suf')
1099 assert str(t) == os.path.join('dir', 'pre-y-suf'), str(t)
1102 t = z.target_from_source('pre-', '-suf', lambda x: x[:-1])
1103 assert str(t) == 'pre-z-suf', str(t)
1105 class EntryTestCase(unittest.TestCase):
1107 """Test methods specific to the Entry sub-class.
1109 test = TestCmd(workdir='')
1110 # FS doesn't like the cwd to be something other than its root.
1111 os.chdir(test.workpath(""))
1113 fs = SCons.Node.FS.FS()
1117 assert e1.__class__ is SCons.Node.FS.File, e1.__class__
1120 e2.get_found_includes(None, None, None)
1121 assert e2.__class__ is SCons.Node.FS.File, e2.__class__
1124 test.write('e3f', "e3f\n")
1126 e3d = fs.Entry('e3d')
1128 assert e3d.__class__ is SCons.Node.FS.Dir, e3d.__class__
1130 e3f = fs.Entry('e3f')
1132 assert e3f.__class__ is SCons.Node.FS.File, e3f.__class__
1134 e3n = fs.Entry('e3n')
1138 except AttributeError:
1140 assert exc_caught, "did not catch expected AttributeError"
1143 test.write('e4f', "e4f\n")
1145 e4d = fs.Entry('e4d')
1146 exists = e4d.exists()
1147 assert e4d.__class__ is SCons.Node.FS.Dir, e4d.__class__
1148 assert exists, "e4d does not exist?"
1150 e4f = fs.Entry('e4f')
1151 exists = e4f.exists()
1152 assert e4f.__class__ is SCons.Node.FS.File, e4f.__class__
1153 assert exists, "e4f does not exist?"
1155 e4n = fs.Entry('e4n')
1156 exists = e4n.exists()
1157 assert e4n.__class__ is SCons.Node.FS.File, e4n.__class__
1158 assert not exists, "e4n exists?"
1161 def __init__(self, val):
1164 def __init__(self, val):
1166 def collect(self, args):
1167 return reduce(lambda x, y: x+y, args)
1168 def signature(self, executor):
1169 return self.val + 222
1170 self.module = M(val)
1173 test.write('e5f', "e5f\n")
1175 e5d = fs.Entry('e5d')
1176 sig = e5d.calc_signature(MyCalc(555))
1177 assert e5d.__class__ is SCons.Node.FS.Dir, e5d.__class__
1178 assert sig == 777, sig
1180 e5f = fs.Entry('e5f')
1181 sig = e5f.calc_signature(MyCalc(666))
1182 assert e5f.__class__ is SCons.Node.FS.File, e5f.__class__
1183 assert sig == 888, sig
1185 e5n = fs.Entry('e5n')
1186 sig = e5n.calc_signature(MyCalc(777))
1187 assert e5n.__class__ is SCons.Node.FS.File, e5n.__class__
1188 assert sig is None, sig
1192 class RepositoryTestCase(unittest.TestCase):
1194 """Test FS (file system) Repository operations
1197 fs = SCons.Node.FS.FS()
1199 fs.Repository('foo')
1200 fs.Repository(os.path.join('foo', 'bar'))
1201 fs.Repository(os.path.join('bar', 'foo'))
1202 fs.Repository('bar')
1204 rep = fs.Dir('#').getRepositories()
1205 assert len(rep) == 4, map(str, rep)
1206 r = map(lambda x, np=os.path.normpath: np(str(x)), rep)
1208 os.path.join('foo', 'bar'),
1209 os.path.join('bar', 'foo'),
1212 test = TestCmd(workdir = '')
1213 test.subdir('rep1', 'rep2', 'rep3', 'work')
1215 rep1 = test.workpath('rep1')
1216 rep2 = test.workpath('rep2')
1217 rep3 = test.workpath('rep3')
1219 os.chdir(test.workpath('work'))
1221 fs = SCons.Node.FS.FS()
1222 fs.Repository(rep1, rep2, rep3)
1224 f1 = fs.File(os.path.join('f1'))
1225 assert f1.rfile() is f1
1227 test.write([rep1, 'f2'], "")
1230 assert not f2.rfile() is f2, f2.rfile()
1231 assert str(f2.rfile()) == os.path.join(rep1, 'f2'), str(f2.rfile())
1233 test.subdir([rep2, 'f3'])
1234 test.write([rep3, 'f3'], "")
1237 assert not f3.rfile() is f3, f3.rfile()
1238 assert f3.rstr() == os.path.join(rep3, 'f3'), f3.rstr()
1240 assert fs.Rsearch('f1') is None
1241 assert fs.Rsearch('f2')
1242 assert fs.Rsearch(f3) is f3
1244 list = fs.Rsearchall(fs.Dir('d1'))
1245 assert len(list) == 1, list
1246 assert list[0].path == 'd1', list[0].path
1248 list = fs.Rsearchall([fs.Dir('d1')])
1249 assert len(list) == 1, list
1250 assert list[0].path == 'd1', list[0].path
1252 list = fs.Rsearchall('d2')
1253 assert list == [], list
1255 list = fs.Rsearchall('#d2')
1256 assert list == [], list
1258 test.subdir(['work', 'd2'])
1259 fs.File('d2').built() # Clear exists cache
1260 list = fs.Rsearchall('d2')
1261 assert map(str, list) == ['d2'], list
1263 test.subdir(['rep2', 'd2'])
1264 fs.File('../rep2/d2').built() # Clear exists cache
1265 list = fs.Rsearchall('d2')
1266 assert map(str, list) == ['d2', test.workpath('rep2', 'd2')], list
1268 test.subdir(['rep1', 'd2'])
1269 fs.File('../rep1/d2').built() # Clear exists cache
1270 list = fs.Rsearchall('d2')
1271 assert map(str, list) == ['d2',
1272 test.workpath('rep1', 'd2'),
1273 test.workpath('rep2', 'd2')], list
1275 list = fs.Rsearchall(['d3', 'd4'])
1276 assert list == [], list
1278 test.subdir(['work', 'd3'])
1279 fs.File('d3').built() # Clear exists cache
1280 list = map(str, fs.Rsearchall(['d3', 'd4']))
1281 assert list == ['d3'], list
1283 test.subdir(['rep3', 'd4'])
1284 fs.File('../rep3/d4').built() # Clear exists cache
1285 list = map(str, fs.Rsearchall(['d3', 'd4']))
1286 assert list == ['d3', test.workpath('rep3', 'd4')], list
1288 list = map(str, fs.Rsearchall(string.join(['d3', 'd4'], os.pathsep)))
1289 assert list == ['d3', test.workpath('rep3', 'd4')], list
1291 work_d4 = fs.File(os.path.join('work', 'd4'))
1292 list = map(str, fs.Rsearchall(['d3', work_d4]))
1293 assert list == ['d3', str(work_d4)], list
1295 list = fs.Rsearchall('')
1296 assert list == [], list
1298 list = fs.Rsearchall([None])
1299 assert list == [], list
1301 list = fs.Rsearchall([''])
1302 assert list == [], list
1304 fs.BuildDir('build', '.')
1306 f = fs.File(test.workpath("work", "i_do_not_exist"))
1307 assert not f.rexists()
1309 test.write(["rep2", "i_exist"], "\n")
1310 f = fs.File(test.workpath("work", "i_exist"))
1313 test.write(["work", "i_exist_too"], "\n")
1314 f = fs.File(test.workpath("work", "i_exist_too"))
1317 f1 = fs.File(os.path.join('build', 'f1'))
1318 assert not f1.rexists()
1320 f2 = fs.File(os.path.join('build', 'f2'))
1323 test.write(["rep2", "tstamp"], "tstamp\n")
1325 # Okay, *this* manipulation accomodates Windows FAT file systems
1326 # that only have two-second granularity on their timestamps.
1327 # We round down the current time to the nearest even integer
1328 # value, subtract two to make sure the timestamp is not "now,"
1329 # and then convert it back to a float.
1330 tstamp = float(int(time.time() / 2) * 2) - 2
1331 os.utime(test.workpath("rep2", "tstamp"), (tstamp - 2.0, tstamp))
1332 f = fs.File("tstamp")
1333 t = f.get_timestamp()
1334 assert t == tstamp, "expected %f, got %f" % (tstamp, t)
1336 test.unlink(["rep2", "tstamp"])
1338 # Make sure get_contents() returns the binary contents.
1339 test.write(["rep3", "contents"], "Con\x1aTents\n")
1341 c = fs.File("contents").get_contents()
1342 assert c == "Con\x1aTents\n", "got '%s'" % c
1344 test.unlink(["rep3", "contents"])
1346 # XXX test calc_signature()
1348 # XXX test current()
1350 class find_fileTestCase(unittest.TestCase):
1352 """Testing find_file function"""
1353 test = TestCmd(workdir = '')
1354 test.write('./foo', 'Some file\n')
1355 fs = SCons.Node.FS.FS(test.workpath(""))
1356 os.chdir(test.workpath("")) # FS doesn't like the cwd to be something other than it's root
1357 node_derived = fs.File(test.workpath('bar/baz'))
1358 node_derived.builder_set(1) # Any non-zero value.
1359 node_pseudo = fs.File(test.workpath('pseudo'))
1360 node_pseudo.set_src_builder(1) # Any non-zero value.
1361 paths = map(fs.Dir, ['.', './bar'])
1362 nodes = [SCons.Node.FS.find_file('foo', paths, fs.File),
1363 SCons.Node.FS.find_file('baz', paths, fs.File),
1364 SCons.Node.FS.find_file('pseudo', paths, fs.File)]
1365 file_names = map(str, nodes)
1366 file_names = map(os.path.normpath, file_names)
1367 assert os.path.normpath('./foo') in file_names, file_names
1368 assert os.path.normpath('./bar/baz') in file_names, file_names
1369 assert os.path.normpath('./pseudo') in file_names, file_names
1371 class StringDirTestCase(unittest.TestCase):
1373 """Test using a string as the second argument of
1376 test = TestCmd(workdir = '')
1378 fs = SCons.Node.FS.FS(test.workpath(''))
1380 d = fs.Dir('sub', '.')
1381 assert str(d) == 'sub'
1383 f = fs.File('file', 'sub')
1384 assert str(f) == os.path.join('sub', 'file')
1385 assert not f.exists()
1387 class stored_infoTestCase(unittest.TestCase):
1389 """Test how storing build information"""
1390 test = TestCmd(workdir = '')
1392 fs = SCons.Node.FS.FS(test.workpath(''))
1395 f = fs.File('file1', d)
1396 bi = f.get_stored_info()
1397 assert bi.bsig == None, bi.bsig
1403 def get_entry(self, name):
1406 f = fs.File('file2', d)
1407 f.dir.sconsign = MySConsign
1408 bi = f.get_stored_info()
1409 assert bi.xyzzy == 7, bi
1411 class has_src_builderTestCase(unittest.TestCase):
1413 """Test the has_src_builder() method"""
1414 test = TestCmd(workdir = '')
1415 fs = SCons.Node.FS.FS(test.workpath(''))
1416 os.chdir(test.workpath(''))
1418 test.subdir('sub2', ['sub2', 'SCCS'], ['sub2', 'RCS'])
1420 sub1 = fs.Dir('sub1', '.')
1421 f1 = fs.File('f1', sub1)
1422 f2 = fs.File('f2', sub1)
1423 f3 = fs.File('f3', sub1)
1424 sub2 = fs.Dir('sub2', '.')
1425 f4 = fs.File('f4', sub2)
1426 f5 = fs.File('f5', sub2)
1427 f6 = fs.File('f6', sub2)
1428 f7 = fs.File('f7', sub2)
1429 f8 = fs.File('f8', sub2)
1431 h = f1.has_src_builder()
1433 h = f1.has_builder()
1436 b1 = Builder(fs.File)
1437 sub1.set_src_builder(b1)
1439 test.write(['sub1', 'f2'], "sub1/f2\n")
1440 h = f1.has_src_builder() # cached from previous call
1442 h = f1.has_builder() # cached from previous call
1444 h = f2.has_src_builder()
1446 h = f2.has_builder()
1448 h = f3.has_src_builder()
1450 h = f3.has_builder()
1452 assert f3.builder is b1, f3.builder
1454 f7.set_src_builder(b1)
1457 test.write(['sub2', 'SCCS', 's.f5'], "sub2/SCCS/s.f5\n")
1458 test.write(['sub2', 'RCS', 'f6,v'], "sub2/RCS/f6,v\n")
1459 h = f4.has_src_builder()
1461 h = f4.has_builder()
1463 h = f5.has_src_builder()
1465 h = f5.has_builder()
1467 h = f6.has_src_builder()
1469 h = f6.has_builder()
1471 h = f7.has_src_builder()
1473 h = f7.has_builder()
1475 h = f8.has_src_builder()
1477 h = f8.has_builder()
1480 class prepareTestCase(unittest.TestCase):
1482 """Test the prepare() method"""
1484 class MyFile(SCons.Node.FS.File):
1485 def _createDir(self):
1486 raise SCons.Errors.StopError
1490 fs = SCons.Node.FS.FS()
1491 file = MyFile('foo', fs.Dir('.'), fs)
1496 except SCons.Errors.StopError:
1498 assert exc_caught, "Should have caught a StopError."
1500 class MkdirAction(Action):
1501 def __init__(self, dir_made):
1502 self.dir_made = dir_made
1503 def __call__(self, target, source, env, errfunc):
1504 self.dir_made.extend(target)
1507 new_dir = fs.Dir("new_dir")
1508 new_dir.builder = Builder(fs.Dir, action=MkdirAction(dir_made))
1509 xyz = fs.File(os.path.join("new_dir", "xyz"))
1511 xyz.set_state(SCons.Node.up_to_date)
1513 assert dir_made == [], dir_made
1516 assert dir_made[0].path == "new_dir", dir_made[0]
1521 class get_actionsTestCase(unittest.TestCase):
1523 """Test the Dir's get_action() method"""
1525 fs = SCons.Node.FS.FS()
1527 a = dir.get_actions()
1530 class SConstruct_dirTestCase(unittest.TestCase):
1532 """Test setting the SConstruct directory"""
1534 fs = SCons.Node.FS.FS()
1535 fs.set_SConstruct_dir(fs.Dir('xxx'))
1536 assert fs.SConstruct_dir.path == 'xxx'
1538 class CacheDirTestCase(unittest.TestCase):
1540 """Test CacheDir functionality"""
1541 test = TestCmd(workdir='')
1545 fs = SCons.Node.FS.FS()
1546 assert fs.CachePath is None, fs.CachePath
1547 assert fs.cache_force is None, fs.cache_force
1548 assert fs.cache_show is None, fs.cache_show
1550 fs.CacheDir('cache')
1551 assert fs.CachePath == 'cache', fs.CachePath
1553 save_CacheRetrieve = SCons.Node.FS.CacheRetrieve
1555 def retrieve_succeed(target, source, env, self=self, execute=1):
1556 self.retrieved.append(target)
1558 def retrieve_fail(target, source, env, self=self, execute=1):
1559 self.retrieved.append(target)
1562 f1 = fs.File("cd.f1")
1563 f1.builder_set(Builder(fs.File))
1564 f1.env_set(Environment())
1566 SCons.Node.FS.CacheRetrieve = retrieve_succeed
1570 r = f1.retrieve_from_cache()
1572 assert self.retrieved == [f1], self.retrieved
1573 assert built_it is None, built_it
1575 SCons.Node.FS.CacheRetrieve = retrieve_fail
1579 r = f1.retrieve_from_cache()
1581 assert self.retrieved == [f1], self.retrieved
1582 assert built_it is None, built_it
1584 SCons.Node.FS.CacheRetrieve = save_CacheRetrieve
1586 save_CacheRetrieveSilent = SCons.Node.FS.CacheRetrieveSilent
1590 f2 = fs.File("cd.f2")
1591 f2.builder_set(Builder(fs.File))
1592 f2.env_set(Environment())
1594 SCons.Node.FS.CacheRetrieveSilent = retrieve_succeed
1598 r = f2.retrieve_from_cache()
1600 assert self.retrieved == [f2], self.retrieved
1601 assert built_it is None, built_it
1603 SCons.Node.FS.CacheRetrieveSilent = retrieve_fail
1607 r = f2.retrieve_from_cache()
1609 assert self.retrieved == [f2], self.retrieved
1610 assert built_it is None, built_it
1612 SCons.Node.FS.CacheRetrieveSilent = save_CacheRetrieveSilent
1614 save_CachePush = SCons.Node.FS.CachePush
1615 def push(target, source, env, self=self):
1616 self.pushed.append(target)
1618 SCons.Node.FS.CachePush = push
1623 cd_f3 = test.workpath("cd.f3")
1626 assert self.pushed == [], self.pushed
1627 test.write(cd_f3, "cd.f3\n")
1629 assert self.pushed == [f3], self.pushed
1633 cd_f4 = test.workpath("cd.f4")
1636 assert self.pushed == [], self.pushed
1637 test.write(cd_f4, "cd.f4\n")
1639 assert self.pushed == [], self.pushed
1642 assert self.pushed == [f4], self.pushed
1644 SCons.Node.FS.CachePush = save_CachePush
1646 # Verify how the cachepath() method determines the name
1647 # of the file in cache.
1648 def my_collect(list):
1650 save_collect = SCons.Sig.MD5.collect
1651 SCons.Sig.MD5.collect = my_collect
1653 f5 = fs.File("cd.f5")
1654 f5.binfo = f5.new_binfo()
1655 f5.binfo.bsig = 'a_fake_bsig'
1657 dirname = os.path.join('cache', 'A')
1658 filename = os.path.join(dirname, 'a_fake_bsig')
1659 assert cp == (dirname, filename), cp
1661 SCons.Sig.MD5.collect = save_collect
1663 # Verify that no bsig raises an InternalERror
1664 f6 = fs.File("cd.f6")
1665 f6.binfo = f6.new_binfo()
1669 except SCons.Errors.InternalError:
1673 # Verify that we raise a warning if we can't copy a file to cache.
1674 save_copy2 = shutil.copy2
1675 def copy2(src, dst):
1677 shutil.copy2 = copy2
1678 save_mkdir = os.mkdir
1679 def mkdir(dir, mode=0):
1682 old_warn_exceptions = SCons.Warnings.warningAsException(1)
1683 SCons.Warnings.enableWarningClass(SCons.Warnings.CacheWriteErrorWarning)
1686 cd_f7 = test.workpath("cd.f7")
1687 test.write(cd_f7, "cd.f7\n")
1689 f7.binfo = f7.new_binfo()
1690 f7.binfo.bsig = 'f7_bsig'
1695 except SCons.Warnings.CacheWriteErrorWarning:
1699 shutil.copy2 = save_copy2
1700 os.mkdir = save_mkdir
1701 SCons.Warnings.warningAsException(old_warn_exceptions)
1702 SCons.Warnings.suppressWarningClass(SCons.Warnings.CacheWriteErrorWarning)
1704 # Verify that we don't blow up if there's no strfunction()
1707 act.strfunction = None
1708 f8 = fs.File("cd.f8")
1709 f8.builder_set(Builder(fs.File, action=act))
1710 f8.env_set(Environment())
1712 SCons.Node.FS.CacheRetrieveSilent = retrieve_succeed
1716 r = f8.retrieve_from_cache()
1718 assert self.retrieved == [f8], self.retrieved
1719 assert built_it is None, built_it
1721 SCons.Node.FS.CacheRetrieveSilent = retrieve_fail
1725 r = f8.retrieve_from_cache()
1727 assert self.retrieved == [f8], self.retrieved
1728 assert built_it is None, built_it
1730 SCons.Node.FS.CacheRetrieveSilent = save_CacheRetrieveSilent
1732 class clearTestCase(unittest.TestCase):
1734 """Test clearing FS nodes of cached data."""
1735 fs = SCons.Node.FS.FS()
1742 assert not hasattr(e, '_exists')
1743 assert not hasattr(e, '_rexists')
1744 assert not hasattr(e, '_str_val')
1751 assert not hasattr(d, '_exists')
1752 assert not hasattr(d, '_rexists')
1753 assert not hasattr(d, '_str_val')
1760 assert not hasattr(f, '_exists')
1761 assert not hasattr(f, '_rexists')
1762 assert not hasattr(f, '_str_val')
1764 class postprocessTestCase(unittest.TestCase):
1766 """Test calling the postprocess() method."""
1767 fs = SCons.Node.FS.FS()
1778 class SpecialAttrTestCase(unittest.TestCase):
1780 """Test special attributes of file nodes."""
1781 test=TestCmd(workdir='')
1782 fs = SCons.Node.FS.FS(test.workpath('work'))
1784 f = fs.Entry('foo/bar/baz.blat').get_subst_proxy()
1787 assert s == os.path.normpath('foo/bar'), s
1788 assert f.dir.is_literal(), f.dir
1789 for_sig = f.dir.for_signature()
1790 assert for_sig == 'bar', for_sig
1793 assert s == 'baz.blat', s
1794 assert f.file.is_literal(), f.file
1795 for_sig = f.file.for_signature()
1796 assert for_sig == 'baz.blat_file', for_sig
1799 assert s == os.path.normpath('foo/bar/baz'), s
1800 assert f.base.is_literal(), f.base
1801 for_sig = f.base.for_signature()
1802 assert for_sig == 'baz.blat_base', for_sig
1805 assert s == 'baz', s
1806 assert f.filebase.is_literal(), f.filebase
1807 for_sig = f.filebase.for_signature()
1808 assert for_sig == 'baz.blat_filebase', for_sig
1811 assert s == '.blat', s
1812 assert f.suffix.is_literal(), f.suffix
1813 for_sig = f.suffix.for_signature()
1814 assert for_sig == 'baz.blat_suffix', for_sig
1817 assert s == test.workpath('work', 'foo', 'bar', 'baz.blat'), s
1818 assert f.abspath.is_literal(), f.abspath
1819 for_sig = f.abspath.for_signature()
1820 assert for_sig == 'baz.blat_abspath', for_sig
1823 assert s == 'foo/bar/baz.blat', s
1824 assert f.posix.is_literal(), f.posix
1826 for_sig = f.posix.for_signature()
1827 assert for_sig == 'baz.blat_posix', for_sig
1830 assert s == 'foo\\bar\\baz.blat', repr(s)
1831 assert f.win32.is_literal(), f.win32
1833 for_sig = f.win32.for_signature()
1834 assert for_sig == 'baz.blat_win32', for_sig
1836 # And now, combinations!!!
1837 s = str(f.srcpath.base)
1838 assert s == os.path.normpath('foo/bar/baz'), s
1839 s = str(f.srcpath.dir)
1840 assert s == str(f.srcdir), s
1841 s = str(f.srcpath.posix)
1842 assert s == 'foo/bar/baz.blat', s
1843 s = str(f.srcpath.win32)
1844 assert s == 'foo\\bar\\baz.blat', s
1846 # Test what happens with BuildDir()
1847 fs.BuildDir('foo', 'baz')
1850 assert s == os.path.normpath('baz/bar/baz.blat'), s
1851 assert f.srcpath.is_literal(), f.srcpath
1853 assert isinstance(g, SCons.Node.FS.Entry), g.__class__
1856 assert s == os.path.normpath('baz/bar'), s
1857 assert f.srcdir.is_literal(), f.srcdir
1859 assert isinstance(g, SCons.Node.FS.Dir), g.__class__
1861 # And now what happens with BuildDir() + Repository()
1862 fs.Repository(test.workpath('repository'))
1864 f = fs.Entry('foo/sub/file.suffix').get_subst_proxy()
1865 test.subdir('repository',
1866 ['repository', 'baz'],
1867 ['repository', 'baz', 'sub'])
1869 rd = test.workpath('repository', 'baz', 'sub')
1870 rf = test.workpath('repository', 'baz', 'sub', 'file.suffix')
1871 test.write(rf, "\n")
1874 assert s == os.path.normpath('baz/sub/file.suffix'), s
1875 assert f.srcpath.is_literal(), f.srcpath
1877 assert isinstance(g, SCons.Node.FS.Entry), g.__class__
1880 assert s == os.path.normpath('baz/sub'), s
1881 assert f.srcdir.is_literal(), f.srcdir
1883 assert isinstance(g, SCons.Node.FS.Dir), g.__class__
1887 assert f.rsrcpath.is_literal(), f.rsrcpath
1888 g = f.rsrcpath.get()
1889 assert isinstance(g, SCons.Node.FS.File), g.__class__
1893 assert f.rsrcdir.is_literal(), f.rsrcdir
1895 assert isinstance(g, SCons.Node.FS.Dir), g.__class__
1897 # Check that attempts to access non-existent attributes of the
1898 # subst proxy generate the right exceptions and messages.
1901 fs.Dir('ddd').get_subst_proxy().no_such_attr
1902 except AttributeError, e:
1903 assert str(e) == "Dir instance 'ddd' has no attribute 'no_such_attr'", e
1905 assert caught, "did not catch expected AttributeError"
1909 fs.Entry('eee').get_subst_proxy().no_such_attr
1910 except AttributeError, e:
1911 assert str(e) == "Entry instance 'eee' has no attribute 'no_such_attr'", e
1913 assert caught, "did not catch expected AttributeError"
1917 fs.File('fff').get_subst_proxy().no_such_attr
1918 except AttributeError, e:
1919 assert str(e) == "File instance 'fff' has no attribute 'no_such_attr'", e
1921 assert caught, "did not catch expected AttributeError"
1923 class SaveStringsTestCase(unittest.TestCase):
1925 """Test caching string values of nodes."""
1926 test=TestCmd(workdir='')
1933 d0_f = fs.File('d0/f')
1934 d1_f = fs.File('d1/f')
1935 d0_b = fs.File('d0/b')
1936 d1_b = fs.File('d1/b')
1942 return [d0_f, d1_f, d0_b, d1_b]
1945 d0_f, d1_f, d0_b, d1_b = nodes
1951 fs1 = SCons.Node.FS.FS(test.workpath('fs1'))
1953 fs1.BuildDir('d0', 'src', duplicate=0)
1954 fs1.BuildDir('d1', 'src', duplicate=1)
1957 expect = map(os.path.normpath, ['src/f', 'd1/f', 'd0/b', 'd1/b'])
1958 assert s == expect, s
1963 expect = map(os.path.normpath, ['src/f', 'src/f', 'd0/b', 'd1/b'])
1964 assert s == expect, s
1966 SCons.Node.FS.save_strings(1)
1967 fs2 = SCons.Node.FS.FS(test.workpath('fs2'))
1969 fs2.BuildDir('d0', 'src', duplicate=0)
1970 fs2.BuildDir('d1', 'src', duplicate=1)
1973 expect = map(os.path.normpath, ['src/f', 'd1/f', 'd0/b', 'd1/b'])
1974 assert s == expect, s
1979 expect = map(os.path.normpath, ['src/f', 'd1/f', 'd0/b', 'd1/b'])
1980 assert s == expect, s
1982 if __name__ == "__main__":
1983 suite = unittest.TestSuite()
1984 suite.addTest(FSTestCase())
1985 suite.addTest(BuildDirTestCase())
1986 suite.addTest(EntryTestCase())
1987 suite.addTest(RepositoryTestCase())
1988 suite.addTest(find_fileTestCase())
1989 suite.addTest(StringDirTestCase())
1990 suite.addTest(stored_infoTestCase())
1991 suite.addTest(has_src_builderTestCase())
1992 suite.addTest(prepareTestCase())
1993 suite.addTest(get_actionsTestCase())
1994 suite.addTest(SConstruct_dirTestCase())
1995 suite.addTest(CacheDirTestCase())
1996 suite.addTest(clearTestCase())
1997 suite.addTest(postprocessTestCase())
1998 suite.addTest(SpecialAttrTestCase())
1999 suite.addTest(SaveStringsTestCase())
2000 if not unittest.TextTestRunner().run(suite).wasSuccessful():