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 f9 = fs.File('build/var2/new_dir/test9.out')
286 # Test for an interesting pathological case...we have a source
287 # file in a build path, but not in a source path. This can
288 # happen if you switch from duplicate=1 to duplicate=0, then
289 # delete a source file. At one time, this would cause exists()
290 # to return a 1 but get_contents() to throw.
291 test.write([ 'work', 'build', 'var1', 'asourcefile' ], 'stuff')
292 f10 = fs.File('build/var1/asourcefile')
294 assert f10.get_contents() == 'stuff', f10.get_contents()
296 f11 = fs.File('src/file11')
297 t, m = f11.alter_targets()
298 bdt = map(lambda n: n.path, t)
299 var1_file11 = os.path.normpath('build/var1/file11')
300 var2_file11 = os.path.normpath('build/var2/file11')
301 assert bdt == [var1_file11, var2_file11], bdt
303 f12 = fs.File('src/file12')
305 bdt, m = f12.alter_targets()
306 assert bdt == [], map(lambda n: n.path, bdt)
308 d13 = fs.Dir('src/new_dir')
309 t, m = d13.alter_targets()
310 bdt = map(lambda n: n.path, t)
311 var1_new_dir = os.path.normpath('build/var1/new_dir')
312 var2_new_dir = os.path.normpath('build/var2/new_dir')
313 assert bdt == [var1_new_dir, var2_new_dir], bdt
315 save_Mkdir = SCons.Node.FS.Mkdir
317 def mkdir_func(target, source, env, dir_made=dir_made):
318 dir_made.append(target)
319 SCons.Node.FS.Mkdir = mkdir_func
321 save_Link = SCons.Node.FS.Link
323 def link_func(target, source, env, link_made=link_made):
324 link_made.append(target)
325 SCons.Node.FS.Link = link_func
329 expect = os.path.join('build', 'var2', 'new_dir')
330 assert dir_made[0].path == expect, dir_made[0].path
331 expect = os.path.join('build', 'var2', 'new_dir', 'test9.out')
332 assert link_made[0].path == expect, link_made[0].path
335 SCons.Node.FS.Mkdir = save_Mkdir
336 SCons.Node.FS.Link = save_Link
338 # Test that an IOError trying to Link a src file
339 # into a BuildDir ends up throwing a StopError.
340 fIO = fs.File("build/var2/IOError")
342 save_Link = SCons.Node.FS.Link
343 def Link_IOError(target, source, env):
344 raise IOError, "Link_IOError"
345 SCons.Node.FS.Link = Link_IOError
347 test.write(['work', 'src', 'IOError'], "work/src/IOError\n")
353 except SCons.Errors.StopError:
355 assert exc_caught, "Should have caught a StopError"
358 SCons.Node.FS.Link = save_Link
360 # Test to see if Link() works...
361 test.subdir('src','build')
362 test.write('src/foo', 'src/foo\n')
363 os.chmod(test.workpath('src/foo'), stat.S_IRUSR)
364 SCons.Node.FS.Link(fs.File(test.workpath('build/foo')),
365 fs.File(test.workpath('src/foo')),
367 os.chmod(test.workpath('src/foo'), stat.S_IRUSR | stat.S_IWRITE)
368 st=os.stat(test.workpath('build/foo'))
369 assert (stat.S_IMODE(st[stat.ST_MODE]) & stat.S_IWRITE), \
370 stat.S_IMODE(st[stat.ST_MODE])
374 fs = SCons.Node.FS.FS()
375 fs.BuildDir('build', '/test/foo')
376 except SCons.Errors.UserError:
378 assert exc_caught, "Should have caught a UserError."
383 fs = SCons.Node.FS.FS()
384 fs.BuildDir('build', 'build/src')
385 except SCons.Errors.UserError:
387 assert exc_caught, "Should have caught a UserError."
389 test.unlink( "src/foo" )
390 test.unlink( "build/foo" )
392 fs = SCons.Node.FS.FS()
393 fs.BuildDir('build', 'src1')
395 # Calling the same BuildDir twice should work fine.
396 fs.BuildDir('build', 'src1')
398 # Trying to move a build dir to a second source dir
401 fs.BuildDir('build', 'src2')
402 except SCons.Errors.UserError:
405 assert 0, "Should have caught a UserError."
407 # Test against a former bug. Make sure we can get a repository
408 # path for the build directory itself!
409 fs=SCons.Node.FS.FS(test.workpath('work'))
411 fs.BuildDir('build/var3', 'src', duplicate=0)
412 d1 = fs.Dir('build/var3')
413 assert d1.rdir() == fs.Dir('src'), str(d1.rdir())
415 # verify the link creation attempts in file_link()
416 class LinkSimulator :
417 """A class to intercept os.[sym]link() calls and track them."""
419 def __init__( self, duplicate ) :
420 self.duplicate = duplicate
424 """Reset the simulator if necessary"""
425 if not self._need_reset() : return # skip if not needed now
426 self.links_to_be_called = self.duplicate
428 def _need_reset( self ) :
430 Determines whether or not the simulator needs to be reset.
431 A reset is necessary if the object is first being initialized,
432 or if all three methods have been tried already.
435 ( not hasattr( self , "links_to_be_called" ) )
437 (self.links_to_be_called == "")
440 def link_fail( self , src , dest ) :
442 l = string.split(self.links_to_be_called, "-")
444 assert next_link == "hard", \
445 "Wrong link order: expected %s to be called "\
446 "instead of hard" % next_link
447 self.links_to_be_called = string.join(l[1:], '-')
448 raise OSError( "Simulating hard link creation error." )
450 def symlink_fail( self , src , dest ) :
452 l = string.split(self.links_to_be_called, "-")
454 assert next_link == "soft", \
455 "Wrong link order: expected %s to be called "\
456 "instead of soft" % next_link
457 self.links_to_be_called = string.join(l[1:], '-')
458 raise OSError( "Simulating symlink creation error." )
460 def copy( self , src , dest ) :
462 l = string.split(self.links_to_be_called, "-")
464 assert next_link == "copy", \
465 "Wrong link order: expected %s to be called "\
466 "instead of copy" % next_link
467 self.links_to_be_called = string.join(l[1:], '-')
468 # copy succeeds, but use the real copy
469 self._real_copy(src, dest)
470 # end class LinkSimulator
473 SCons.Node.FS.set_duplicate("no-link-order")
474 assert 0, "Expected exception when passing an invalid duplicate to set_duplicate"
475 except SCons.Errors.InternalError:
478 for duplicate in SCons.Node.FS.Valid_Duplicates:
479 simulator = LinkSimulator(duplicate)
481 # save the real functions for later restoration
486 except AttributeError:
489 real_symlink = os.symlink
490 except AttributeError:
492 real_copy = shutil.copy2
493 simulator._real_copy = real_copy # the simulator needs the real one
495 # override the real functions with our simulation
496 os.link = simulator.link_fail
497 os.symlink = simulator.symlink_fail
498 shutil.copy2 = simulator.copy
499 SCons.Node.FS.set_duplicate(duplicate)
501 src_foo = test.workpath('src', 'foo')
502 build_foo = test.workpath('build', 'foo')
505 test.write(src_foo, 'src/foo\n')
506 os.chmod(src_foo, stat.S_IRUSR)
508 SCons.Node.FS.Link(fs.File(build_foo),
512 os.chmod(src_foo, stat.S_IRUSR | stat.S_IWRITE)
514 test.unlink(build_foo)
517 # restore the real functions
523 os.symlink = real_symlink
525 delattr(os, 'symlink')
526 shutil.copy2 = real_copy
528 class FSTestCase(unittest.TestCase):
530 """Test FS (file system) Node operations
532 This test case handles all of the file system node
533 tests in one environment, so we don't have to set up a
534 complicated directory structure for each test individually.
536 test = TestCmd(workdir = '')
537 test.subdir('sub', ['sub', 'dir'])
539 wp = test.workpath('')
540 sub = test.workpath('sub', '')
541 sub_dir = test.workpath('sub', 'dir', '')
542 sub_dir_foo = test.workpath('sub', 'dir', 'foo', '')
543 sub_dir_foo_bar = test.workpath('sub', 'dir', 'foo', 'bar', '')
544 sub_foo = test.workpath('sub', 'foo', '')
548 fs = SCons.Node.FS.FS()
551 assert isinstance(e1, SCons.Node.FS.Entry)
554 assert isinstance(d1, SCons.Node.FS.Dir)
555 assert d1.cwd is d1, d1
557 f1 = fs.File('f1', directory = d1)
558 assert isinstance(f1, SCons.Node.FS.File)
560 d1_f1 = os.path.join('d1', 'f1')
561 assert f1.path == d1_f1, "f1.path %s != %s" % (f1.path, d1_f1)
562 assert str(f1) == d1_f1, "str(f1) %s != %s" % (str(f1), d1_f1)
565 assert isinstance(x1, SCons.Node.FS.File)
566 assert str(x1) == os.path.join('d1', 'x1')
569 assert isinstance(x2, SCons.Node.FS.Dir)
570 assert str(x2) == os.path.join('d1', 'x2')
573 assert isinstance(x3, SCons.Node.FS.Entry)
574 assert str(x3) == os.path.join('d1', 'x3')
576 assert d1.File(x1) == x1
577 assert d1.Dir(x2) == x2
578 assert d1.Entry(x3) == x3
583 assert str(x4) == os.path.join('d1', 'x4')
586 assert str(x5) == os.path.join('d1', 'x5')
589 assert str(x6) == os.path.join('d1', 'x6')
591 assert str(x7) == os.path.join('d1', 'x7')
593 assert x1.File(x4) == x4
594 assert x1.Dir(x5) == x5
595 assert x1.Entry(x6) == x6
596 assert x1.Entry(x7) == x7
598 assert x1.Entry(x5) == x5
606 assert x1.Entry(x4) == x4
615 assert isinstance(x6, SCons.Node.FS.File)
618 assert isinstance(x7, SCons.Node.FS.Dir)
626 def Dir_test(lpath, path_, abspath_, up_path_, fileSys=fs, s=sep):
627 dir = fileSys.Dir(string.replace(lpath, '/', s))
630 path_ = string.replace(path_, '/', os.sep)
631 abspath_ = string.replace(abspath_, '/', os.sep)
632 up_path_ = string.replace(up_path_, '/', os.sep)
635 if p[-1] == os.sep and len(p) > 1:
638 path = strip_slash(path_)
639 abspath = strip_slash(abspath_)
640 up_path = strip_slash(up_path_)
641 name = string.split(abspath, os.sep)[-1]
643 assert dir.name == name, \
644 "dir.name %s != expected name %s" % \
646 assert dir.path == path, \
647 "dir.path %s != expected path %s" % \
649 assert str(dir) == path, \
650 "str(dir) %s != expected path %s" % \
652 assert dir.path_ == path_, \
653 "dir.path_ %s != expected path_ %s" % \
655 assert dir.get_abspath() == abspath, \
656 "dir.abspath %s != expected absolute path %s" % \
657 (dir.get_abspath(), abspath)
658 assert dir.abspath_ == abspath_, \
659 "dir.abspath_ %s != expected absolute path_ %s" % \
660 (dir.abspath_, abspath_)
661 assert dir.up().path == up_path, \
662 "dir.up().path %s != expected parent path %s" % \
663 (dir.up().path, up_path)
664 assert dir.up().path_ == up_path_, \
665 "dir.up().path_ %s != expected parent path_ %s" % \
666 (dir.up().path_, up_path_)
668 Dir_test('foo', 'foo/', sub_dir_foo, './')
669 Dir_test('foo/bar', 'foo/bar/', sub_dir_foo_bar, 'foo/')
670 Dir_test('/foo', '/foo/', '/foo/', '/')
671 Dir_test('/foo/bar', '/foo/bar/', '/foo/bar/', '/foo/')
672 Dir_test('..', sub, sub, wp)
673 Dir_test('foo/..', './', sub_dir, sub)
674 Dir_test('../foo', sub_foo, sub_foo, sub)
675 Dir_test('.', './', sub_dir, sub)
676 Dir_test('./.', './', sub_dir, sub)
677 Dir_test('foo/./bar', 'foo/bar/', sub_dir_foo_bar, 'foo/')
678 Dir_test('#../foo', sub_foo, sub_foo, sub)
679 Dir_test('#/../foo', sub_foo, sub_foo, sub)
680 Dir_test('#foo/bar', 'foo/bar/', sub_dir_foo_bar, 'foo/')
681 Dir_test('#/foo/bar', 'foo/bar/', sub_dir_foo_bar, 'foo/')
682 Dir_test('#', './', sub_dir, sub)
685 f2 = fs.File(string.join(['f1', 'f2'], sep), directory = d1)
687 assert str(x) == ("Tried to lookup File '%s' as a Dir." %
693 dir = fs.Dir(string.join(['d1', 'f1'], sep))
695 assert str(x) == ("Tried to lookup File '%s' as a Dir." %
703 assert str(x) == ("Tried to lookup Dir '%s' as a File." %
708 # Test that just specifying the drive works to identify
709 # its root directory.
710 p = os.path.abspath(test.workpath('root_file'))
711 drive, path = os.path.splitdrive(p)
713 # The assert below probably isn't correct for the
714 # general case, but it works for Win32, which covers a
717 assert str(dir) == drive + os.sep, str(dir)
719 # Test Dir.children()
721 fs.File(string.join(['ddd', 'f1'], sep))
722 fs.File(string.join(['ddd', 'f2'], sep))
723 fs.File(string.join(['ddd', 'f3'], sep))
724 fs.Dir(string.join(['ddd', 'd1'], sep))
725 fs.Dir(string.join(['ddd', 'd1', 'f4'], sep))
726 fs.Dir(string.join(['ddd', 'd1', 'f5'], sep))
727 kids = map(lambda x: x.path, dir.children(None))
729 assert kids == [os.path.join('ddd', 'd1'),
730 os.path.join('ddd', 'f1'),
731 os.path.join('ddd', 'f2'),
732 os.path.join('ddd', 'f3')]
733 kids = map(lambda x: x.path_, dir.children(None))
735 assert kids == [os.path.join('ddd', 'd1', ''),
736 os.path.join('ddd', 'f1'),
737 os.path.join('ddd', 'f2'),
738 os.path.join('ddd', 'f3')]
740 # Test for a bug in 0.04 that did not like looking up
741 # dirs with a trailing slash on Win32.
743 assert d.path_ == '.' + os.sep, d.abspath_
745 assert d.path_ == 'foo' + os.sep, d.path_
747 # Test for sub-classing of node building.
752 d1.add_source([SCons.Node.Node()]) # XXX FAKE SUBCLASS ATTRIBUTE
753 d1.builder_set(Builder(fs.File))
754 d1.env_set(Environment())
760 f1.add_source([SCons.Node.Node()]) # XXX FAKE SUBCLASS ATTRIBUTE
761 f1.builder_set(Builder(fs.File))
762 f1.env_set(Environment())
766 def match(path, expect):
767 expect = string.replace(expect, '/', os.sep)
768 assert path == expect, "path %s != expected %s" % (path, expect)
771 assert e1.__class__.__name__ == 'Dir'
773 match(e1.path_, "d1/")
774 match(e1.dir.path, ".")
776 e2 = fs.Entry("d1/f1")
777 assert e2.__class__.__name__ == 'File'
778 match(e2.path, "d1/f1")
779 match(e2.path_, "d1/f1")
780 match(e2.dir.path, "d1")
783 assert e3.__class__.__name__ == 'Entry'
785 match(e3.path_, "e3")
786 match(e3.dir.path, ".")
788 e4 = fs.Entry("d1/e4")
789 assert e4.__class__.__name__ == 'Entry'
790 match(e4.path, "d1/e4")
791 match(e4.path_, "d1/e4")
792 match(e4.dir.path, "d1")
794 e5 = fs.Entry("e3/e5")
795 assert e3.__class__.__name__ == 'Dir'
797 match(e3.path_, "e3/")
798 match(e3.dir.path, ".")
799 assert e5.__class__.__name__ == 'Entry'
800 match(e5.path, "e3/e5")
801 match(e5.path_, "e3/e5")
802 match(e5.dir.path, "e3")
806 assert e4.__class__.__name__ == 'Dir'
807 match(e4.path, "d1/e4")
808 match(e4.path_, "d1/e4/")
809 match(e4.dir.path, "d1")
811 e7 = fs.File("e3/e5")
813 assert e5.__class__.__name__ == 'File'
814 match(e5.path, "e3/e5")
815 match(e5.path_, "e3/e5")
816 match(e5.dir.path, "e3")
818 fs.chdir(fs.Dir('subdir'))
820 match(f11.path, "subdir/f11")
822 match(d12.path_, "subdir/d12/")
823 e13 = fs.Entry("subdir/e13")
824 match(e13.path, "subdir/subdir/e13")
825 fs.chdir(fs.Dir('..'))
828 f1.builder_set(Builder(fs.File))
829 f1.env_set(Environment())
831 f1.target_scanner = Scanner(xyz)
834 assert f1.implicit[0].path_ == "xyz"
837 assert f1.implicit == []
840 assert f1.implicit[0].path_ == "xyz"
842 # Test underlying scanning functionality in get_found_includes()
847 deps = f12.get_found_includes(env, None, t1)
848 assert deps == [], deps
850 class MyScanner(Scanner):
852 def __call__(self, node, env, path):
853 self.call_count = self.call_count + 1
854 return Scanner.__call__(self, node, env, path)
857 deps = f12.get_found_includes(env, s, t1)
858 assert deps == [xyz], deps
859 assert s.call_count == 1, s.call_count
861 deps = f12.get_found_includes(env, s, t1)
862 assert deps == [xyz], deps
863 assert s.call_count == 1, s.call_count
867 deps = f12.get_found_includes(env, s, t1)
868 assert deps == [xyz], deps
869 assert s.call_count == 2, s.call_count
871 # Make sure we can scan this file even if the target isn't
872 # a file that has a scanner (it might be an Alias, e.g.).
876 deps = f12.get_found_includes(env, s, DummyNode())
877 assert deps == [xyz], deps
879 # Test building a file whose directory is not there yet...
880 f1 = fs.File(test.workpath("foo/bar/baz/ack"))
881 assert not f1.dir.exists()
884 assert f1.dir.exists()
889 fs = SCons.Node.FS.FS()
890 assert str(fs.getcwd()) == ".", str(fs.getcwd())
891 fs.chdir(fs.Dir('subdir'))
892 # The cwd's path is always "."
893 assert str(fs.getcwd()) == ".", str(fs.getcwd())
894 assert fs.getcwd().path == 'subdir', fs.getcwd().path
895 fs.chdir(fs.Dir('../..'))
896 assert fs.getcwd().path == test.workdir, fs.getcwd().path
898 f1 = fs.File(test.workpath("do_i_exist"))
899 assert not f1.exists()
900 test.write("do_i_exist","\n")
901 assert not f1.exists()
904 test.unlink("do_i_exist")
907 assert not f1.exists()
909 # For some reason, in Win32, the \x1a character terminates
910 # the reading of files in text mode. This tests that
911 # get_contents() returns the binary contents.
912 test.write("binary_file", "Foo\x1aBar")
913 f1 = SCons.Node.FS.default_fs.File(test.workpath("binary_file"))
914 assert f1.get_contents() == "Foo\x1aBar", f1.get_contents()
916 def nonexistent(method, s):
918 x = method(s, create = 0)
919 except SCons.Errors.UserError:
922 raise TestFailed, "did not catch expected UserError"
924 nonexistent(fs.Entry, 'nonexistent')
925 nonexistent(fs.Entry, 'nonexistent/foo')
927 nonexistent(fs.File, 'nonexistent')
928 nonexistent(fs.File, 'nonexistent/foo')
930 nonexistent(fs.Dir, 'nonexistent')
931 nonexistent(fs.Dir, 'nonexistent/foo')
933 test.write("preserve_me", "\n")
934 assert os.path.exists(test.workpath("preserve_me"))
935 f1 = fs.File(test.workpath("preserve_me"))
937 assert os.path.exists(test.workpath("preserve_me"))
939 test.write("remove_me", "\n")
940 assert os.path.exists(test.workpath("remove_me"))
941 f1 = fs.File(test.workpath("remove_me"))
942 f1.builder = Builder(fs.File)
943 f1.env_set(Environment())
945 assert not os.path.exists(test.workpath("remove_me"))
947 e = fs.Entry('e_local')
948 assert not hasattr(e, '_local')
951 f = fs.File('e_local')
953 f = fs.File('f_local')
956 #XXX test current() for directories
958 #XXX test sconsign() for directories
960 #XXX test set_signature() for directories
962 #XXX test build() for directories
966 # test Entry.get_contents()
967 e = fs.Entry('does_not_exist')
971 except AttributeError:
973 assert exc_caught, "Should have caught an AttributError"
975 test.write("file", "file\n")
979 assert c == "file\n", c
980 assert e.__class__ == SCons.Node.FS.File
988 assert e.__class__ == SCons.Node.FS.Dir
990 test.write("tstamp", "tstamp\n")
992 # Okay, *this* manipulation accomodates Windows FAT file systems
993 # that only have two-second granularity on their timestamps.
994 # We round down the current time to the nearest even integer
995 # value, subtract two to make sure the timestamp is not "now,"
996 # and then convert it back to a float.
997 tstamp = float(int(time.time() / 2) * 2) - 2
998 os.utime(test.workpath("tstamp"), (tstamp - 2.0, tstamp))
999 f = fs.File("tstamp")
1000 t = f.get_timestamp()
1001 assert t == tstamp, "expected %f, got %f" % (tstamp, t)
1003 test.unlink("tstamp")
1005 test.subdir('tdir1')
1007 t = d.get_timestamp()
1008 assert t == 0, "expected 0, got %s" % str(t)
1010 test.subdir('tdir2')
1012 f1 = test.workpath('tdir2', 'file1')
1013 f2 = test.workpath('tdir2', 'file2')
1014 test.write(f1, 'file1\n')
1015 test.write(f2, 'file2\n')
1018 current_time = float(int(time.time() / 2) * 2)
1019 t1 = current_time - 4.0
1020 t2 = current_time - 2.0
1021 os.utime(f1, (t1 - 2.0, t1))
1022 os.utime(f2, (t2 - 2.0, t2))
1023 t = d.get_timestamp()
1024 assert t == t2, "expected %f, got %f" % (t2, t)
1026 skey = fs.Entry('eee.x').scanner_key()
1027 assert skey == '.x', skey
1028 skey = fs.Entry('eee.xyz').scanner_key()
1029 assert skey == '.xyz', skey
1031 skey = fs.File('fff.x').scanner_key()
1032 assert skey == '.x', skey
1033 skey = fs.File('fff.xyz').scanner_key()
1034 assert skey == '.xyz', skey
1036 skey = fs.Dir('ddd.x').scanner_key()
1037 assert skey is None, skey
1039 test.write("i_am_not_a_directory", "\n")
1043 fs.Dir(test.workpath("i_am_not_a_directory"))
1046 assert exc_caught, "Should have caught a TypeError"
1048 test.unlink("i_am_not_a_directory")
1055 assert exc_caught, "Should have caught a TypeError"
1057 # XXX test calc_signature()
1059 # XXX test current()
1065 f = fs.File('does_not_exist')
1069 test.write('exists', "exists\n")
1070 f = fs.File('exists')
1073 assert not os.path.exists(test.workpath('exists')), "exists was not removed"
1075 symlink = test.workpath('symlink')
1077 os.symlink(test.workpath('does_not_exist'), symlink)
1078 assert os.path.islink(symlink)
1079 f = fs.File('symlink')
1082 assert not os.path.islink(symlink), "symlink was not removed"
1083 except AttributeError:
1086 test.write('can_not_remove', "can_not_remove\n")
1087 test.writable(test.workpath('.'), 0)
1088 fp = open(test.workpath('can_not_remove'))
1090 f = fs.File('can_not_remove')
1099 assert exc_caught, "Should have caught an OSError, r = " + str(r)
1101 f = fs.Entry('foo/bar/baz')
1102 assert f.for_signature() == 'baz', f.for_signature()
1103 assert f.get_string(0) == os.path.normpath('foo/bar/baz'), \
1105 assert f.get_string(1) == 'baz', f.get_string(1)
1108 t = x.target_from_source('pre-', '-suf')
1109 assert str(t) == 'pre-x-suf', str(t)
1111 y = fs.File('dir/y')
1112 t = y.target_from_source('pre-', '-suf')
1113 assert str(t) == os.path.join('dir', 'pre-y-suf'), str(t)
1116 t = z.target_from_source('pre-', '-suf', lambda x: x[:-1])
1117 assert str(t) == 'pre-z-suf', str(t)
1119 class EntryTestCase(unittest.TestCase):
1121 """Test methods specific to the Entry sub-class.
1123 test = TestCmd(workdir='')
1124 # FS doesn't like the cwd to be something other than its root.
1125 os.chdir(test.workpath(""))
1127 fs = SCons.Node.FS.FS()
1131 assert e1.__class__ is SCons.Node.FS.File, e1.__class__
1134 e2.get_found_includes(None, None, None)
1135 assert e2.__class__ is SCons.Node.FS.File, e2.__class__
1138 test.write('e3f', "e3f\n")
1140 e3d = fs.Entry('e3d')
1142 assert e3d.__class__ is SCons.Node.FS.Dir, e3d.__class__
1144 e3f = fs.Entry('e3f')
1146 assert e3f.__class__ is SCons.Node.FS.File, e3f.__class__
1148 e3n = fs.Entry('e3n')
1152 except AttributeError:
1154 assert exc_caught, "did not catch expected AttributeError"
1157 test.write('e4f', "e4f\n")
1159 e4d = fs.Entry('e4d')
1160 exists = e4d.exists()
1161 assert e4d.__class__ is SCons.Node.FS.Dir, e4d.__class__
1162 assert exists, "e4d does not exist?"
1164 e4f = fs.Entry('e4f')
1165 exists = e4f.exists()
1166 assert e4f.__class__ is SCons.Node.FS.File, e4f.__class__
1167 assert exists, "e4f does not exist?"
1169 e4n = fs.Entry('e4n')
1170 exists = e4n.exists()
1171 assert e4n.__class__ is SCons.Node.FS.File, e4n.__class__
1172 assert not exists, "e4n exists?"
1175 def __init__(self, val):
1178 def __init__(self, val):
1180 def collect(self, args):
1181 return reduce(lambda x, y: x+y, args)
1182 def signature(self, executor):
1183 return self.val + 222
1184 self.module = M(val)
1187 test.write('e5f', "e5f\n")
1189 e5d = fs.Entry('e5d')
1190 sig = e5d.calc_signature(MyCalc(555))
1191 assert e5d.__class__ is SCons.Node.FS.Dir, e5d.__class__
1192 assert sig == 777, sig
1194 e5f = fs.Entry('e5f')
1195 sig = e5f.calc_signature(MyCalc(666))
1196 assert e5f.__class__ is SCons.Node.FS.File, e5f.__class__
1197 assert sig == 888, sig
1199 e5n = fs.Entry('e5n')
1200 sig = e5n.calc_signature(MyCalc(777))
1201 assert e5n.__class__ is SCons.Node.FS.File, e5n.__class__
1202 assert sig is None, sig
1206 class RepositoryTestCase(unittest.TestCase):
1208 """Test FS (file system) Repository operations
1211 fs = SCons.Node.FS.FS()
1213 fs.Repository('foo')
1214 fs.Repository(os.path.join('foo', 'bar'))
1215 fs.Repository(os.path.join('bar', 'foo'))
1216 fs.Repository('bar')
1218 rep = fs.Dir('#').getRepositories()
1219 assert len(rep) == 4, map(str, rep)
1220 r = map(lambda x, np=os.path.normpath: np(str(x)), rep)
1222 os.path.join('foo', 'bar'),
1223 os.path.join('bar', 'foo'),
1226 test = TestCmd(workdir = '')
1227 test.subdir('rep1', 'rep2', 'rep3', 'work')
1229 rep1 = test.workpath('rep1')
1230 rep2 = test.workpath('rep2')
1231 rep3 = test.workpath('rep3')
1233 os.chdir(test.workpath('work'))
1235 fs = SCons.Node.FS.FS()
1236 fs.Repository(rep1, rep2, rep3)
1238 f1 = fs.File(os.path.join('f1'))
1239 assert f1.rfile() is f1
1241 test.write([rep1, 'f2'], "")
1244 assert not f2.rfile() is f2, f2.rfile()
1245 assert str(f2.rfile()) == os.path.join(rep1, 'f2'), str(f2.rfile())
1247 test.subdir([rep2, 'f3'])
1248 test.write([rep3, 'f3'], "")
1251 assert not f3.rfile() is f3, f3.rfile()
1252 assert f3.rstr() == os.path.join(rep3, 'f3'), f3.rstr()
1254 assert fs.Rsearch('f1') is None
1255 assert fs.Rsearch('f2')
1256 assert fs.Rsearch(f3) is f3
1258 list = fs.Rsearchall(fs.Dir('d1'))
1259 assert len(list) == 1, list
1260 assert list[0].path == 'd1', list[0].path
1262 list = fs.Rsearchall([fs.Dir('d1')])
1263 assert len(list) == 1, list
1264 assert list[0].path == 'd1', list[0].path
1266 list = fs.Rsearchall('d2')
1267 assert list == [], list
1269 list = fs.Rsearchall('#d2')
1270 assert list == [], list
1272 test.subdir(['work', 'd2'])
1273 fs.File('d2').built() # Clear exists cache
1274 list = fs.Rsearchall('d2')
1275 assert map(str, list) == ['d2'], list
1277 test.subdir(['rep2', 'd2'])
1278 fs.File('../rep2/d2').built() # Clear exists cache
1279 list = fs.Rsearchall('d2')
1280 assert map(str, list) == ['d2', test.workpath('rep2', 'd2')], list
1282 test.subdir(['rep1', 'd2'])
1283 fs.File('../rep1/d2').built() # Clear exists cache
1284 list = fs.Rsearchall('d2')
1285 assert map(str, list) == ['d2',
1286 test.workpath('rep1', 'd2'),
1287 test.workpath('rep2', 'd2')], list
1289 list = fs.Rsearchall(['d3', 'd4'])
1290 assert list == [], list
1292 test.subdir(['work', 'd3'])
1293 fs.File('d3').built() # Clear exists cache
1294 list = map(str, fs.Rsearchall(['d3', 'd4']))
1295 assert list == ['d3'], list
1297 test.subdir(['rep3', 'd4'])
1298 fs.File('../rep3/d4').built() # Clear exists cache
1299 list = map(str, fs.Rsearchall(['d3', 'd4']))
1300 assert list == ['d3', test.workpath('rep3', 'd4')], list
1302 list = map(str, fs.Rsearchall(string.join(['d3', 'd4'], os.pathsep)))
1303 assert list == ['d3', test.workpath('rep3', 'd4')], list
1305 work_d4 = fs.File(os.path.join('work', 'd4'))
1306 list = map(str, fs.Rsearchall(['d3', work_d4]))
1307 assert list == ['d3', str(work_d4)], list
1309 fs.BuildDir('build', '.')
1311 f = fs.File(test.workpath("work", "i_do_not_exist"))
1312 assert not f.rexists()
1314 test.write(["rep2", "i_exist"], "\n")
1315 f = fs.File(test.workpath("work", "i_exist"))
1318 test.write(["work", "i_exist_too"], "\n")
1319 f = fs.File(test.workpath("work", "i_exist_too"))
1322 f1 = fs.File(os.path.join('build', 'f1'))
1323 assert not f1.rexists()
1325 f2 = fs.File(os.path.join('build', 'f2'))
1328 test.write(["rep2", "tstamp"], "tstamp\n")
1330 # Okay, *this* manipulation accomodates Windows FAT file systems
1331 # that only have two-second granularity on their timestamps.
1332 # We round down the current time to the nearest even integer
1333 # value, subtract two to make sure the timestamp is not "now,"
1334 # and then convert it back to a float.
1335 tstamp = float(int(time.time() / 2) * 2) - 2
1336 os.utime(test.workpath("rep2", "tstamp"), (tstamp - 2.0, tstamp))
1337 f = fs.File("tstamp")
1338 t = f.get_timestamp()
1339 assert t == tstamp, "expected %f, got %f" % (tstamp, t)
1341 test.unlink(["rep2", "tstamp"])
1343 # Make sure get_contents() returns the binary contents.
1344 test.write(["rep3", "contents"], "Con\x1aTents\n")
1346 c = fs.File("contents").get_contents()
1347 assert c == "Con\x1aTents\n", "got '%s'" % c
1349 test.unlink(["rep3", "contents"])
1351 # XXX test calc_signature()
1353 # XXX test current()
1355 class find_fileTestCase(unittest.TestCase):
1357 """Testing find_file function"""
1358 test = TestCmd(workdir = '')
1359 test.write('./foo', 'Some file\n')
1360 fs = SCons.Node.FS.FS(test.workpath(""))
1361 os.chdir(test.workpath("")) # FS doesn't like the cwd to be something other than it's root
1362 node_derived = fs.File(test.workpath('bar/baz'))
1363 node_derived.builder_set(1) # Any non-zero value.
1364 node_pseudo = fs.File(test.workpath('pseudo'))
1365 node_pseudo.set_src_builder(1) # Any non-zero value.
1366 paths = map(fs.Dir, ['.', './bar'])
1367 nodes = [SCons.Node.FS.find_file('foo', paths, fs.File),
1368 SCons.Node.FS.find_file('baz', paths, fs.File),
1369 SCons.Node.FS.find_file('pseudo', paths, fs.File)]
1370 file_names = map(str, nodes)
1371 file_names = map(os.path.normpath, file_names)
1372 assert os.path.normpath('./foo') in file_names, file_names
1373 assert os.path.normpath('./bar/baz') in file_names, file_names
1374 assert os.path.normpath('./pseudo') in file_names, file_names
1376 class StringDirTestCase(unittest.TestCase):
1378 """Test using a string as the second argument of
1381 test = TestCmd(workdir = '')
1383 fs = SCons.Node.FS.FS(test.workpath(''))
1385 d = fs.Dir('sub', '.')
1386 assert str(d) == 'sub'
1388 f = fs.File('file', 'sub')
1389 assert str(f) == os.path.join('sub', 'file')
1390 assert not f.exists()
1392 class has_src_builderTestCase(unittest.TestCase):
1394 """Test the has_src_builder() method"""
1395 test = TestCmd(workdir = '')
1396 fs = SCons.Node.FS.FS(test.workpath(''))
1397 os.chdir(test.workpath(''))
1399 test.subdir('sub2', ['sub2', 'SCCS'], ['sub2', 'RCS'])
1401 sub1 = fs.Dir('sub1', '.')
1402 f1 = fs.File('f1', sub1)
1403 f2 = fs.File('f2', sub1)
1404 f3 = fs.File('f3', sub1)
1405 sub2 = fs.Dir('sub2', '.')
1406 f4 = fs.File('f4', sub2)
1407 f5 = fs.File('f5', sub2)
1408 f6 = fs.File('f6', sub2)
1409 f7 = fs.File('f7', sub2)
1411 h = f1.has_src_builder()
1413 h = f1.has_builder()
1416 b1 = Builder(fs.File)
1417 sub1.set_src_builder(b1)
1419 test.write(['sub1', 'f2'], "sub1/f2\n")
1420 h = f1.has_src_builder() # cached from previous call
1422 h = f1.has_builder() # cached from previous call
1424 h = f2.has_src_builder()
1426 h = f2.has_builder()
1428 h = f3.has_src_builder()
1430 h = f3.has_builder()
1432 assert f3.builder is b1, f3.builder
1434 f7.set_src_builder(b1)
1436 test.write(['sub2', 'SCCS', 's.f5'], "sub2/SCCS/s.f5\n")
1437 test.write(['sub2', 'RCS', 'f6,v'], "sub2/RCS/f6,v\n")
1438 h = f4.has_src_builder()
1440 h = f4.has_builder()
1442 h = f5.has_src_builder()
1444 h = f5.has_builder()
1446 h = f6.has_src_builder()
1448 h = f6.has_builder()
1450 h = f7.has_src_builder()
1452 h = f7.has_builder()
1455 class prepareTestCase(unittest.TestCase):
1457 """Test the prepare() method"""
1459 class MyFile(SCons.Node.FS.File):
1460 def _createDir(self):
1461 raise SCons.Errors.StopError
1465 fs = SCons.Node.FS.FS()
1466 file = MyFile('foo', fs.Dir('.'), fs)
1471 except SCons.Errors.StopError:
1473 assert exc_caught, "Should have caught a StopError."
1475 save_Mkdir = SCons.Node.FS.Mkdir
1477 def mkdir_func(target, source, env, dir_made=dir_made):
1478 dir_made.append(target)
1479 SCons.Node.FS.Mkdir = mkdir_func
1481 file = fs.File(os.path.join("new_dir", "xyz"))
1483 file.set_state(SCons.Node.up_to_date)
1485 assert dir_made == [], dir_made
1488 assert dir_made[0].path == "new_dir", dir_made[0].path
1490 SCons.Node.FS.Mkdir = save_Mkdir
1495 class get_actionsTestCase(unittest.TestCase):
1497 """Test the Dir's get_action() method"""
1499 fs = SCons.Node.FS.FS()
1501 a = dir.get_actions()
1504 class SConstruct_dirTestCase(unittest.TestCase):
1506 """Test setting the SConstruct directory"""
1508 fs = SCons.Node.FS.FS()
1509 fs.set_SConstruct_dir(fs.Dir('xxx'))
1510 assert fs.SConstruct_dir.path == 'xxx'
1512 class CacheDirTestCase(unittest.TestCase):
1514 """Test CacheDir functionality"""
1515 test = TestCmd(workdir='')
1519 fs = SCons.Node.FS.FS()
1520 assert fs.CachePath is None, fs.CachePath
1521 assert fs.cache_force is None, fs.cache_force
1522 assert fs.cache_show is None, fs.cache_show
1524 fs.CacheDir('cache')
1525 assert fs.CachePath == 'cache', fs.CachePath
1527 save_CacheRetrieve = SCons.Node.FS.CacheRetrieve
1529 def retrieve_succeed(target, source, env, self=self):
1530 self.retrieved.append(target)
1532 def retrieve_fail(target, source, env, self=self):
1533 self.retrieved.append(target)
1536 f1 = fs.File("cd.f1")
1537 f1.builder_set(Builder(fs.File))
1538 f1.env_set(Environment())
1540 SCons.Node.FS.CacheRetrieve = retrieve_succeed
1544 r = f1.retrieve_from_cache()
1546 assert self.retrieved == [f1], self.retrieved
1547 assert built_it is None, built_it
1549 SCons.Node.FS.CacheRetrieve = retrieve_fail
1553 r = f1.retrieve_from_cache()
1555 assert self.retrieved == [f1], self.retrieved
1556 assert built_it is None, built_it
1558 SCons.Node.FS.CacheRetrieve = save_CacheRetrieve
1560 save_CacheRetrieveSilent = SCons.Node.FS.CacheRetrieveSilent
1564 f2 = fs.File("cd.f2")
1565 f2.builder_set(Builder(fs.File))
1566 f2.env_set(Environment())
1568 SCons.Node.FS.CacheRetrieveSilent = retrieve_succeed
1572 r = f2.retrieve_from_cache()
1574 assert self.retrieved == [f2], self.retrieved
1575 assert built_it is None, built_it
1577 SCons.Node.FS.CacheRetrieveSilent = retrieve_fail
1581 r = f2.retrieve_from_cache()
1583 assert self.retrieved == [f2], self.retrieved
1584 assert built_it is None, built_it
1586 SCons.Node.FS.CacheRetrieveSilent = save_CacheRetrieveSilent
1588 save_CachePush = SCons.Node.FS.CachePush
1589 def push(target, source, env, self=self):
1590 self.pushed.append(target)
1592 SCons.Node.FS.CachePush = push
1597 cd_f3 = test.workpath("cd.f3")
1600 assert self.pushed == [], self.pushed
1601 test.write(cd_f3, "cd.f3\n")
1603 assert self.pushed == [f3], self.pushed
1607 cd_f4 = test.workpath("cd.f4")
1610 assert self.pushed == [], self.pushed
1611 test.write(cd_f4, "cd.f4\n")
1613 assert self.pushed == [], self.pushed
1616 assert self.pushed == [f4], self.pushed
1618 SCons.Node.FS.CachePush = save_CachePush
1620 # Verify how the cachepath() method determines the name
1621 # of the file in cache.
1622 def my_collect(list):
1624 save_collect = SCons.Sig.MD5.collect
1625 SCons.Sig.MD5.collect = my_collect
1627 f5 = fs.File("cd.f5")
1628 f5.binfo = f5.new_binfo()
1629 f5.binfo.bsig = 'a_fake_bsig'
1631 dirname = os.path.join('cache', 'A')
1632 filename = os.path.join(dirname, 'a_fake_bsig')
1633 assert cp == (dirname, filename), cp
1635 SCons.Sig.MD5.collect = save_collect
1637 # Verify that no bsig raises an InternalERror
1638 f6 = fs.File("cd.f6")
1639 f6.binfo = f6.new_binfo()
1643 except SCons.Errors.InternalError:
1647 # Verify that we raise a warning if we can't copy a file to cache.
1648 save_copy2 = shutil.copy2
1649 def copy2(src, dst):
1651 shutil.copy2 = copy2
1652 save_mkdir = os.mkdir
1653 def mkdir(dir, mode=0):
1656 old_warn_exceptions = SCons.Warnings.warningAsException(1)
1657 SCons.Warnings.enableWarningClass(SCons.Warnings.CacheWriteErrorWarning)
1660 cd_f7 = test.workpath("cd.f7")
1661 test.write(cd_f7, "cd.f7\n")
1663 f7.binfo = f7.new_binfo()
1664 f7.binfo.bsig = 'f7_bsig'
1669 except SCons.Warnings.CacheWriteErrorWarning:
1673 shutil.copy2 = save_copy2
1674 os.mkdir = save_mkdir
1675 SCons.Warnings.warningAsException(old_warn_exceptions)
1676 SCons.Warnings.suppressWarningClass(SCons.Warnings.CacheWriteErrorWarning)
1678 # Verify that we don't blow up if there's no strfunction()
1681 act.strfunction = None
1682 f8 = fs.File("cd.f8")
1683 f8.builder_set(Builder(fs.File, action=act))
1684 f8.env_set(Environment())
1686 SCons.Node.FS.CacheRetrieveSilent = retrieve_succeed
1690 r = f8.retrieve_from_cache()
1692 assert self.retrieved == [f8], self.retrieved
1693 assert built_it is None, built_it
1695 SCons.Node.FS.CacheRetrieveSilent = retrieve_fail
1699 r = f8.retrieve_from_cache()
1701 assert self.retrieved == [f8], self.retrieved
1702 assert built_it is None, built_it
1704 SCons.Node.FS.CacheRetrieveSilent = save_CacheRetrieveSilent
1706 class clearTestCase(unittest.TestCase):
1708 """Test clearing FS nodes of cached data."""
1709 fs = SCons.Node.FS.FS()
1716 assert not hasattr(e, '_exists')
1717 assert not hasattr(e, '_rexists')
1718 assert not hasattr(e, '_str_val')
1725 assert not hasattr(d, '_exists')
1726 assert not hasattr(d, '_rexists')
1727 assert not hasattr(d, '_str_val')
1734 assert not hasattr(f, '_exists')
1735 assert not hasattr(f, '_rexists')
1736 assert not hasattr(f, '_str_val')
1738 class postprocessTestCase(unittest.TestCase):
1740 """Test calling the postprocess() method."""
1741 fs = SCons.Node.FS.FS()
1752 class SpecialAttrTestCase(unittest.TestCase):
1754 """Test special attributes of file nodes."""
1755 test=TestCmd(workdir='')
1756 fs = SCons.Node.FS.FS(test.workpath('work'))
1758 f = fs.Entry('foo/bar/baz.blat').get_subst_proxy()
1761 assert s == os.path.normpath('foo/bar'), s
1762 assert f.dir.is_literal(), f.dir
1763 for_sig = f.dir.for_signature()
1764 assert for_sig == 'bar', for_sig
1767 assert s == 'baz.blat', s
1768 assert f.file.is_literal(), f.file
1769 for_sig = f.file.for_signature()
1770 assert for_sig == 'baz.blat_file', for_sig
1773 assert s == os.path.normpath('foo/bar/baz'), s
1774 assert f.base.is_literal(), f.base
1775 for_sig = f.base.for_signature()
1776 assert for_sig == 'baz.blat_base', for_sig
1779 assert s == 'baz', s
1780 assert f.filebase.is_literal(), f.filebase
1781 for_sig = f.filebase.for_signature()
1782 assert for_sig == 'baz.blat_filebase', for_sig
1785 assert s == '.blat', s
1786 assert f.suffix.is_literal(), f.suffix
1787 for_sig = f.suffix.for_signature()
1788 assert for_sig == 'baz.blat_suffix', for_sig
1791 assert s == test.workpath('work', 'foo', 'bar', 'baz.blat'), s
1792 assert f.abspath.is_literal(), f.abspath
1793 for_sig = f.abspath.for_signature()
1794 assert for_sig == 'baz.blat_abspath', for_sig
1797 assert s == 'foo/bar/baz.blat', s
1798 assert f.posix.is_literal(), f.posix
1800 for_sig = f.posix.for_signature()
1801 assert for_sig == 'baz.blat_posix', for_sig
1803 # And now, combinations!!!
1804 s = str(f.srcpath.base)
1805 assert s == os.path.normpath('foo/bar/baz'), s
1806 s = str(f.srcpath.dir)
1807 assert s == str(f.srcdir), s
1808 s = str(f.srcpath.posix)
1809 assert s == 'foo/bar/baz.blat', s
1811 # Test what happens with BuildDir()
1812 fs.BuildDir('foo', 'baz')
1815 assert s == os.path.normpath('baz/bar/baz.blat'), s
1816 assert f.srcpath.is_literal(), f.srcpath
1818 assert isinstance(g, SCons.Node.FS.Entry), g.__class__
1821 assert s == os.path.normpath('baz/bar'), s
1822 assert f.srcdir.is_literal(), f.srcdir
1824 assert isinstance(g, SCons.Node.FS.Dir), g.__class__
1826 # And now what happens with BuildDir() + Repository()
1827 fs.Repository(test.workpath('repository'))
1829 f = fs.Entry('foo/sub/file.suffix').get_subst_proxy()
1830 test.subdir('repository',
1831 ['repository', 'baz'],
1832 ['repository', 'baz', 'sub'])
1834 rd = test.workpath('repository', 'baz', 'sub')
1835 rf = test.workpath('repository', 'baz', 'sub', 'file.suffix')
1836 test.write(rf, "\n")
1839 assert s == os.path.normpath('baz/sub/file.suffix'), s
1840 assert f.srcpath.is_literal(), f.srcpath
1842 assert isinstance(g, SCons.Node.FS.Entry), g.__class__
1845 assert s == os.path.normpath('baz/sub'), s
1846 assert f.srcdir.is_literal(), f.srcdir
1848 assert isinstance(g, SCons.Node.FS.Dir), g.__class__
1852 assert f.rsrcpath.is_literal(), f.rsrcpath
1853 g = f.rsrcpath.get()
1854 assert isinstance(g, SCons.Node.FS.File), g.__class__
1858 assert f.rsrcdir.is_literal(), f.rsrcdir
1860 assert isinstance(g, SCons.Node.FS.Dir), g.__class__
1862 # Check that attempts to access non-existent attributes of the
1863 # subst proxy generate the right exceptions and messages.
1866 fs.Dir('ddd').get_subst_proxy().no_such_attr
1867 except AttributeError, e:
1868 assert str(e) == "Dir instance 'ddd' has no attribute 'no_such_attr'", e
1870 assert caught, "did not catch expected AttributeError"
1874 fs.Entry('eee').get_subst_proxy().no_such_attr
1875 except AttributeError, e:
1876 assert str(e) == "Entry instance 'eee' has no attribute 'no_such_attr'", e
1878 assert caught, "did not catch expected AttributeError"
1882 fs.File('fff').get_subst_proxy().no_such_attr
1883 except AttributeError, e:
1884 assert str(e) == "File instance 'fff' has no attribute 'no_such_attr'", e
1886 assert caught, "did not catch expected AttributeError"
1888 class SaveStringsTestCase(unittest.TestCase):
1890 """Test caching string values of nodes."""
1891 test=TestCmd(workdir='')
1898 d0_f = fs.File('d0/f')
1899 d1_f = fs.File('d1/f')
1900 d0_b = fs.File('d0/b')
1901 d1_b = fs.File('d1/b')
1907 return [d0_f, d1_f, d0_b, d1_b]
1910 d0_f, d1_f, d0_b, d1_b = nodes
1916 fs1 = SCons.Node.FS.FS(test.workpath('fs1'))
1918 fs1.BuildDir('d0', 'src', duplicate=0)
1919 fs1.BuildDir('d1', 'src', duplicate=1)
1922 expect = map(os.path.normpath, ['src/f', 'd1/f', 'd0/b', 'd1/b'])
1923 assert s == expect, s
1928 expect = map(os.path.normpath, ['src/f', 'src/f', 'd0/b', 'd1/b'])
1929 assert s == expect, s
1931 SCons.Node.FS.save_strings(1)
1932 fs2 = SCons.Node.FS.FS(test.workpath('fs2'))
1934 fs2.BuildDir('d0', 'src', duplicate=0)
1935 fs2.BuildDir('d1', 'src', duplicate=1)
1938 expect = map(os.path.normpath, ['src/f', 'd1/f', 'd0/b', 'd1/b'])
1939 assert s == expect, s
1944 expect = map(os.path.normpath, ['src/f', 'd1/f', 'd0/b', 'd1/b'])
1945 assert s == expect, s
1949 if __name__ == "__main__":
1950 suite = unittest.TestSuite()
1951 suite.addTest(FSTestCase())
1952 suite.addTest(BuildDirTestCase())
1953 suite.addTest(EntryTestCase())
1954 suite.addTest(RepositoryTestCase())
1955 suite.addTest(find_fileTestCase())
1956 suite.addTest(StringDirTestCase())
1957 suite.addTest(has_src_builderTestCase())
1958 suite.addTest(prepareTestCase())
1959 suite.addTest(get_actionsTestCase())
1960 suite.addTest(SConstruct_dirTestCase())
1961 suite.addTest(CacheDirTestCase())
1962 suite.addTest(clearTestCase())
1963 suite.addTest(postprocessTestCase())
1964 suite.addTest(SpecialAttrTestCase())
1965 suite.addTest(SaveStringsTestCase())
1966 if not unittest.TextTestRunner().run(suite).wasSuccessful():