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, dir, target=None, source=None):
59 def __call__(self, node, env, path):
63 def select(self, node):
65 def recurse_nodes(self, nodes):
70 self.scanner = Scanner()
71 def Dictionary(self, *args):
73 def autogenerate(self, **kw):
75 def get_scanner(self, skey):
77 def Override(self, overrides):
79 def _update(self, dict):
83 def __call__(self, targets, sources, env, errfunc, **kw):
85 if kw.get('execute', 1):
88 def show(self, string):
90 def strfunction(self, targets, sources, env):
93 def __init__(self, factory, action=Action()):
94 self.factory = factory
95 self.env = Environment()
98 self.target_scanner = None
99 self.source_scanner = None
101 def targets(self, t):
104 def source_factory(self, name):
105 return self.factory(name)
107 class _tempdirTestCase(unittest.TestCase):
109 self.save_cwd = os.getcwd()
110 self.test = TestCmd(workdir='')
111 # FS doesn't like the cwd to be something other than its root.
112 os.chdir(self.test.workpath(""))
113 self.fs = SCons.Node.FS.FS()
116 os.chdir(self.save_cwd)
118 class BuildDirTestCase(unittest.TestCase):
120 """Test build dir functionality"""
121 test=TestCmd(workdir='')
123 fs = SCons.Node.FS.FS()
124 f1 = fs.File('build/test1')
125 fs.BuildDir('build', 'src')
126 f2 = fs.File('build/test2')
128 assert f1.srcnode().path == os.path.normpath('src/test1'), f1.srcnode().path
129 assert f2.srcnode().path == os.path.normpath('src/test2'), f2.srcnode().path
130 assert d1.srcnode().path == 'src', d1.srcnode().path
132 fs = SCons.Node.FS.FS()
133 f1 = fs.File('build/test1')
134 fs.BuildDir('build', '.')
135 f2 = fs.File('build/test2')
137 assert f1.srcnode().path == 'test1', f1.srcnode().path
138 assert f2.srcnode().path == 'test2', f2.srcnode().path
139 assert d1.srcnode().path == '.', d1.srcnode().path
141 fs = SCons.Node.FS.FS()
142 fs.BuildDir('build/var1', 'src')
143 fs.BuildDir('build/var2', 'src')
144 f1 = fs.File('build/var1/test1')
145 f2 = fs.File('build/var2/test1')
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
149 fs = SCons.Node.FS.FS()
150 fs.BuildDir('../var1', 'src')
151 fs.BuildDir('../var2', 'src')
152 f1 = fs.File('../var1/test1')
153 f2 = fs.File('../var2/test1')
154 assert f1.srcnode().path == os.path.normpath('src/test1'), f1.srcnode().path
155 assert f2.srcnode().path == os.path.normpath('src/test1'), f2.srcnode().path
158 test.subdir('work', ['work', 'src'])
159 test.subdir(['work', 'build'], ['work', 'build', 'var1'])
160 test.subdir(['work', 'build', 'var2'])
161 test.subdir('rep1', ['rep1', 'src'])
162 test.subdir(['rep1', 'build'], ['rep1', 'build', 'var1'])
163 test.subdir(['rep1', 'build', 'var2'])
165 # A source file in the source directory
166 test.write([ 'work', 'src', 'test.in' ], 'test.in')
168 # A source file in a subdir of the source directory
169 test.subdir([ 'work', 'src', 'new_dir' ])
170 test.write([ 'work', 'src', 'new_dir', 'test9.out' ], 'test9.out\n')
172 # A source file in the repository
173 test.write([ 'rep1', 'src', 'test2.in' ], 'test2.in')
175 # Some source files in the build directory
176 test.write([ 'work', 'build', 'var2', 'test.in' ], 'test.old')
177 test.write([ 'work', 'build', 'var2', 'test2.in' ], 'test2.old')
179 # An old derived file in the build directories
180 test.write([ 'work', 'build', 'var1', 'test.out' ], 'test.old')
181 test.write([ 'work', 'build', 'var2', 'test.out' ], 'test.old')
183 # And just in case we are weird, a derived file in the source
185 test.write([ 'work', 'src', 'test.out' ], 'test.out.src')
187 # A derived file in the repository
188 test.write([ 'rep1', 'build', 'var1', 'test2.out' ], 'test2.out_rep')
189 test.write([ 'rep1', 'build', 'var2', 'test2.out' ], 'test2.out_rep')
191 os.chdir(test.workpath('work'))
193 fs = SCons.Node.FS.FS(test.workpath('work'))
194 fs.BuildDir('build/var1', 'src', duplicate=0)
195 fs.BuildDir('build/var2', 'src')
196 f1 = fs.File('build/var1/test.in')
197 f1out = fs.File('build/var1/test.out')
199 f1out_2 = fs.File('build/var1/test2.out')
201 f2 = fs.File('build/var2/test.in')
202 f2out = fs.File('build/var2/test.out')
204 f2out_2 = fs.File('build/var2/test2.out')
206 fs.Repository(test.workpath('rep1'))
208 assert f1.srcnode().path == os.path.normpath('src/test.in'),\
210 # str(node) returns source path for duplicate = 0
211 assert str(f1) == os.path.normpath('src/test.in'), str(f1)
212 # Build path does not exist
213 assert not f1.exists()
214 # ...but the actual file is not there...
215 assert not os.path.exists(f1.get_abspath())
216 # And duplicate=0 should also work just like a Repository
218 # rfile() should point to the source path
219 assert f1.rfile().path == os.path.normpath('src/test.in'),\
222 assert f2.srcnode().path == os.path.normpath('src/test.in'),\
224 # str(node) returns build path for duplicate = 1
225 assert str(f2) == os.path.normpath('build/var2/test.in'), str(f2)
228 # ...and exists() should copy the file from src to build path
229 assert test.read(['work', 'build', 'var2', 'test.in']) == 'test.in',\
230 test.read(['work', 'build', 'var2', 'test.in'])
231 # Since exists() is true, so should rexists() be
234 f3 = fs.File('build/var1/test2.in')
235 f4 = fs.File('build/var2/test2.in')
237 assert f3.srcnode().path == os.path.normpath('src/test2.in'),\
239 # str(node) returns source path for duplicate = 0
240 assert str(f3) == os.path.normpath('src/test2.in'), str(f3)
241 # Build path does not exist
242 assert not f3.exists()
243 # Source path does not either
244 assert not f3.srcnode().exists()
245 # But we do have a file in the Repository
247 # rfile() should point to the source path
248 assert f3.rfile().path == os.path.normpath(test.workpath('rep1/src/test2.in')),\
251 assert f4.srcnode().path == os.path.normpath('src/test2.in'),\
253 # str(node) returns build path for duplicate = 1
254 assert str(f4) == os.path.normpath('build/var2/test2.in'), str(f4)
255 # Build path should exist
257 # ...and copy over the file into the local build path
258 assert test.read(['work', 'build', 'var2', 'test2.in']) == 'test2.in'
259 # should exist in repository, since exists() is true
261 # rfile() should point to ourselves
262 assert f4.rfile().path == os.path.normpath('build/var2/test2.in'),\
265 f5 = fs.File('build/var1/test.out')
266 f6 = fs.File('build/var2/test.out')
269 # We should not copy the file from the source dir, since this is
271 assert test.read(['work', 'build', 'var1', 'test.out']) == 'test.old'
274 # We should not copy the file from the source dir, since this is
276 assert test.read(['work', 'build', 'var2', 'test.out']) == 'test.old'
278 f7 = fs.File('build/var1/test2.out')
279 f8 = fs.File('build/var2/test2.out')
281 assert not f7.exists()
283 assert f7.rfile().path == os.path.normpath(test.workpath('rep1/build/var1/test2.out')),\
286 assert not f8.exists()
288 assert f8.rfile().path == os.path.normpath(test.workpath('rep1/build/var2/test2.out')),\
291 # Verify the Mkdir and Link actions are called
292 d9 = fs.Dir('build/var2/new_dir')
293 f9 = fs.File('build/var2/new_dir/test9.out')
295 class MkdirAction(Action):
296 def __init__(self, dir_made):
297 self.dir_made = dir_made
298 def __call__(self, target, source, env, errfunc):
299 self.dir_made.extend(target)
301 save_Link = SCons.Node.FS.Link
303 def link_func(target, source, env, link_made=link_made):
304 link_made.append(target)
305 SCons.Node.FS.Link = link_func
309 d9.builder = Builder(fs.Dir, action=MkdirAction(dir_made))
312 expect = os.path.join('build', 'var2', 'new_dir')
313 assert dir_made[0].path == expect, dir_made[0].path
314 expect = os.path.join('build', 'var2', 'new_dir', 'test9.out')
315 assert link_made[0].path == expect, link_made[0].path
318 SCons.Node.FS.Link = save_Link
320 # Test for an interesting pathological case...we have a source
321 # file in a build path, but not in a source path. This can
322 # happen if you switch from duplicate=1 to duplicate=0, then
323 # delete a source file. At one time, this would cause exists()
324 # to return a 1 but get_contents() to throw.
325 test.write([ 'work', 'build', 'var1', 'asourcefile' ], 'stuff')
326 f10 = fs.File('build/var1/asourcefile')
328 assert f10.get_contents() == 'stuff', f10.get_contents()
330 f11 = fs.File('src/file11')
331 t, m = f11.alter_targets()
332 bdt = map(lambda n: n.path, t)
333 var1_file11 = os.path.normpath('build/var1/file11')
334 var2_file11 = os.path.normpath('build/var2/file11')
335 assert bdt == [var1_file11, var2_file11], bdt
337 f12 = fs.File('src/file12')
339 bdt, m = f12.alter_targets()
340 assert bdt == [], map(lambda n: n.path, bdt)
342 d13 = fs.Dir('src/new_dir')
343 t, m = d13.alter_targets()
344 bdt = map(lambda n: n.path, t)
345 var1_new_dir = os.path.normpath('build/var1/new_dir')
346 var2_new_dir = os.path.normpath('build/var2/new_dir')
347 assert bdt == [var1_new_dir, var2_new_dir], bdt
349 # Test that an IOError trying to Link a src file
350 # into a BuildDir ends up throwing a StopError.
351 fIO = fs.File("build/var2/IOError")
353 save_Link = SCons.Node.FS.Link
354 def Link_IOError(target, source, env):
355 raise IOError, "Link_IOError"
356 SCons.Node.FS.Link = SCons.Action.Action(Link_IOError, None)
358 test.write(['work', 'src', 'IOError'], "work/src/IOError\n")
364 except SCons.Errors.StopError:
366 assert exc_caught, "Should have caught a StopError"
369 SCons.Node.FS.Link = save_Link
371 # Test to see if Link() works...
372 test.subdir('src','build')
373 test.write('src/foo', 'src/foo\n')
374 os.chmod(test.workpath('src/foo'), stat.S_IRUSR)
375 SCons.Node.FS.Link(fs.File(test.workpath('build/foo')),
376 fs.File(test.workpath('src/foo')),
378 os.chmod(test.workpath('src/foo'), stat.S_IRUSR | stat.S_IWRITE)
379 st=os.stat(test.workpath('build/foo'))
380 assert (stat.S_IMODE(st[stat.ST_MODE]) & stat.S_IWRITE), \
381 stat.S_IMODE(st[stat.ST_MODE])
383 # This used to generate a UserError when we forbid the source
384 # directory from being outside the top-level SConstruct dir.
385 fs = SCons.Node.FS.FS()
386 fs.BuildDir('build', '/test/foo')
391 fs = SCons.Node.FS.FS()
392 fs.BuildDir('build', 'build/src')
393 except SCons.Errors.UserError:
395 assert exc_caught, "Should have caught a UserError."
397 test.unlink( "src/foo" )
398 test.unlink( "build/foo" )
400 fs = SCons.Node.FS.FS()
401 fs.BuildDir('build', 'src1')
403 # Calling the same BuildDir twice should work fine.
404 fs.BuildDir('build', 'src1')
406 # Trying to move a build dir to a second source dir
409 fs.BuildDir('build', 'src2')
410 except SCons.Errors.UserError:
413 assert 0, "Should have caught a UserError."
415 # Test against a former bug. Make sure we can get a repository
416 # path for the build directory itself!
417 fs=SCons.Node.FS.FS(test.workpath('work'))
419 fs.BuildDir('build/var3', 'src', duplicate=0)
420 d1 = fs.Dir('build/var3')
422 assert r == d1, "%s != %s" % (r, d1)
424 # verify the link creation attempts in file_link()
425 class LinkSimulator :
426 """A class to intercept os.[sym]link() calls and track them."""
428 def __init__( self, duplicate, link, symlink, copy ) :
429 self.duplicate = duplicate
431 self.have['hard'] = link
432 self.have['soft'] = symlink
433 self.have['copy'] = copy
435 self.links_to_be_called = []
436 for link in string.split(self.duplicate, '-'):
438 self.links_to_be_called.append(link)
440 def link_fail( self , src , dest ) :
441 next_link = self.links_to_be_called.pop(0)
442 assert next_link == "hard", \
443 "Wrong link order: expected %s to be called "\
444 "instead of hard" % next_link
445 raise OSError( "Simulating hard link creation error." )
447 def symlink_fail( self , src , dest ) :
448 next_link = self.links_to_be_called.pop(0)
449 assert next_link == "soft", \
450 "Wrong link order: expected %s to be called "\
451 "instead of soft" % next_link
452 raise OSError( "Simulating symlink creation error." )
454 def copy( self , src , dest ) :
455 next_link = self.links_to_be_called.pop(0)
456 assert next_link == "copy", \
457 "Wrong link order: expected %s to be called "\
458 "instead of copy" % next_link
459 # copy succeeds, but use the real copy
460 self.have['copy'](src, dest)
461 # end class LinkSimulator
464 SCons.Node.FS.set_duplicate("no-link-order")
465 assert 0, "Expected exception when passing an invalid duplicate to set_duplicate"
466 except SCons.Errors.InternalError:
469 for duplicate in SCons.Node.FS.Valid_Duplicates:
470 # save the real functions for later restoration
473 except AttributeError:
476 real_symlink = os.symlink
477 except AttributeError:
479 real_copy = shutil.copy2
481 simulator = LinkSimulator(duplicate, real_link, real_symlink, real_copy)
483 # override the real functions with our simulation
484 os.link = simulator.link_fail
485 os.symlink = simulator.symlink_fail
486 shutil.copy2 = simulator.copy
490 SCons.Node.FS.set_duplicate(duplicate)
492 src_foo = test.workpath('src', 'foo')
493 build_foo = test.workpath('build', 'foo')
495 test.write(src_foo, 'src/foo\n')
496 os.chmod(src_foo, stat.S_IRUSR)
498 SCons.Node.FS.Link(fs.File(build_foo),
502 os.chmod(src_foo, stat.S_IRUSR | stat.S_IWRITE)
504 test.unlink(build_foo)
507 # restore the real functions
513 os.symlink = real_symlink
515 delattr(os, 'symlink')
516 shutil.copy2 = real_copy
518 # Test BuildDir "reflection," where a same-named subdirectory
519 # exists underneath a build_dir.
520 fs = SCons.Node.FS.FS()
521 fs.BuildDir('work/src/b1/b2', 'work/src')
528 'work/src/b1/b2/b1/b2',
532 'work/src/b1/b2' : 'work/src',
533 'work/src/b1/b2/f' : 'work/src/f',
534 'work/src/b1/b2/b1' : 'work/src/b1/',
535 'work/src/b1/b2/b1/f' : 'work/src/b1/f',
536 'work/src/b1/b2/b1/b2' : 'work/src/b1/b2',
537 'work/src/b1/b2/b1/b2/f' : 'work/src/b1/b2/f',
541 'work/src' : 'work/src/b1/b2',
542 'work/src/f' : 'work/src/b1/b2/f',
543 'work/src/b1' : 'work/src/b1/b2/b1',
544 'work/src/b1/f' : 'work/src/b1/b2/b1/f',
552 fnode = fs.File(dir + '/f')
554 dp = dnode.srcnode().path
555 expect = os.path.normpath(srcnode_map.get(dir, dir))
557 print "Dir `%s' srcnode() `%s' != expected `%s'" % (dir, dp, expect)
560 fp = fnode.srcnode().path
561 expect = os.path.normpath(srcnode_map.get(f, f))
563 print "File `%s' srcnode() `%s' != expected `%s'" % (f, fp, expect)
569 fnode = fs.File(dir + '/f')
571 t, m = dnode.alter_targets()
573 expect = os.path.normpath(alter_map.get(dir, dir))
575 print "Dir `%s' alter_targets() `%s' != expected `%s'" % (dir, tp, expect)
578 t, m = fnode.alter_targets()
580 expect = os.path.normpath(alter_map.get(f, f))
582 print "File `%s' alter_targets() `%s' != expected `%s'" % (f, tp, expect)
587 class BaseTestCase(_tempdirTestCase):
589 """Test the Base.stat() method"""
591 test.write("e1", "e1\n")
592 fs = SCons.Node.FS.FS()
596 assert not s is None, s
602 def test_getmtime(self):
603 """Test the Base.getmtime() method"""
605 test.write("file", "file\n")
606 fs = SCons.Node.FS.FS()
608 file = fs.Entry('file')
609 assert file.getmtime()
611 file = fs.Entry('nonexistent')
612 mtime = file.getmtime()
613 assert mtime is None, mtime
615 def test_getsize(self):
616 """Test the Base.getsize() method"""
618 test.write("file", "file\n")
619 fs = SCons.Node.FS.FS()
621 file = fs.Entry('file')
622 size = file.getsize()
623 assert size == 5, size
625 file = fs.Entry('nonexistent')
626 size = file.getsize()
627 assert size is None, size
629 def test_isdir(self):
630 """Test the Base.isdir() method"""
633 test.write("file", "file\n")
634 fs = SCons.Node.FS.FS()
636 dir = fs.Entry('dir')
639 file = fs.Entry('file')
640 assert not file.isdir()
642 nonexistent = fs.Entry('nonexistent')
643 assert not nonexistent.isdir()
645 def test_isfile(self):
646 """Test the Base.isfile() method"""
649 test.write("file", "file\n")
650 fs = SCons.Node.FS.FS()
652 dir = fs.Entry('dir')
653 assert not dir.isfile()
655 file = fs.Entry('file')
658 nonexistent = fs.Entry('nonexistent')
659 assert not nonexistent.isfile()
661 if hasattr(os, 'symlink'):
662 def test_islink(self):
663 """Test the Base.islink() method"""
666 test.write("file", "file\n")
667 test.symlink("symlink", "symlink")
668 fs = SCons.Node.FS.FS()
670 dir = fs.Entry('dir')
671 assert not dir.islink()
673 file = fs.Entry('file')
674 assert not file.islink()
676 symlink = fs.Entry('symlink')
677 assert symlink.islink()
679 nonexistent = fs.Entry('nonexistent')
680 assert not nonexistent.islink()
682 class DirNodeInfoTestCase(_tempdirTestCase):
683 def test___init__(self):
684 """Test DirNodeInfo initialization"""
685 ddd = self.fs.Dir('ddd')
686 ni = SCons.Node.FS.DirNodeInfo(ddd)
688 class DirBuildInfoTestCase(_tempdirTestCase):
689 def test___init__(self):
690 """Test DirBuildInfo initialization"""
691 ddd = self.fs.Dir('ddd')
692 bi = SCons.Node.FS.DirBuildInfo(ddd)
694 class FileNodeInfoTestCase(_tempdirTestCase):
695 def test___init__(self):
696 """Test FileNodeInfo initialization"""
697 fff = self.fs.File('fff')
698 ni = SCons.Node.FS.FileNodeInfo(fff)
699 assert hasattr(ni, 'timestamp')
700 assert hasattr(ni, 'size')
702 def test___cmp__(self):
703 """Test comparing File.NodeInfo objects"""
704 f1 = self.fs.File('f1')
705 f2 = self.fs.File('f2')
707 ni1 = SCons.Node.FS.FileNodeInfo(f1)
708 ni2 = SCons.Node.FS.FileNodeInfo(f2)
710 msg = "cmp(%s, %s) returned %s, not %s"
713 assert c == 1, msg % (ni1, ni2, c, 1)
717 assert c == 1, msg % (ni1.bsig, ni2, c, 1)
721 assert c == 1, msg % (ni1.bsig, ni2.bsig, c, 1)
725 assert c == 0, msg % (ni1.bsig, ni2.bsig, c, 0)
729 assert c == -1, msg % (ni1.bsig, ni2.bsig, c, -1)
731 def test_update(self):
732 """Test updating a File.NodeInfo with on-disk information"""
734 fff = self.fs.File('fff')
736 ni = SCons.Node.FS.FileNodeInfo(fff)
741 test.write('fff', "fff\n")
745 mtime = st[stat.ST_MTIME]
746 assert ni.timestamp != mtime, (ni.timestamp, mtime)
747 size = st[stat.ST_SIZE]
748 assert ni.size != size, (ni.size, size)
755 mtime = st[stat.ST_MTIME]
756 assert ni.timestamp == mtime, (ni.timestamp, mtime)
757 size = st[stat.ST_SIZE]
758 assert ni.size == size, (ni.size, size)
760 class FileBuildInfoTestCase(_tempdirTestCase):
761 def test___init__(self):
762 """Test File.BuildInfo initialization"""
763 fff = self.fs.File('fff')
764 bi = SCons.Node.FS.BuildInfo(fff)
765 assert bi.node is fff, bi.node
767 def test_convert_to_sconsign(self):
768 """Test converting to .sconsign file format"""
769 fff = self.fs.File('fff')
770 bi = SCons.Node.FS.FileBuildInfo(fff)
771 assert hasattr(bi, 'convert_to_sconsign')
773 def test_convert_from_sconsign(self):
774 """Test converting from .sconsign file format"""
775 fff = self.fs.File('fff')
776 bi = SCons.Node.FS.FileBuildInfo(fff)
777 assert hasattr(bi, 'convert_from_sconsign')
779 def test_prepare_dependencies(self):
780 """Test that we have a prepare_dependencies() method"""
781 fff = self.fs.File('fff')
782 bi = SCons.Node.FS.FileBuildInfo(fff)
783 bi.prepare_dependencies()
785 def test_format(self):
786 """Test the format() method"""
787 f1 = self.fs.File('f1')
788 bi1 = SCons.Node.FS.BuildInfo(f1)
790 s1sig = SCons.Node.FS.FileNodeInfo(self.fs.File('n1'))
792 d1sig = SCons.Node.FS.FileNodeInfo(self.fs.File('n2'))
794 i1sig = SCons.Node.FS.FileNodeInfo(self.fs.File('n3'))
797 bi1.bsources = [self.fs.File('s1')]
798 bi1.bdepends = [self.fs.File('d1')]
799 bi1.bimplicit = [self.fs.File('i1')]
800 bi1.bsourcesigs = [s1sig]
801 bi1.bdependsigs = [d1sig]
802 bi1.bimplicitsigs = [i1sig]
811 expect = string.join(expect_lines, '\n')
812 format = bi1.format()
813 assert format == expect, (repr(format), repr(expect))
815 class FSTestCase(_tempdirTestCase):
816 def test_runTest(self):
817 """Test FS (file system) Node operations
819 This test case handles all of the file system node
820 tests in one environment, so we don't have to set up a
821 complicated directory structure for each test individually.
825 test.subdir('sub', ['sub', 'dir'])
827 wp = test.workpath('')
828 sub = test.workpath('sub', '')
829 sub_dir = test.workpath('sub', 'dir', '')
830 sub_dir_foo = test.workpath('sub', 'dir', 'foo', '')
831 sub_dir_foo_bar = test.workpath('sub', 'dir', 'foo', 'bar', '')
832 sub_foo = test.workpath('sub', 'foo', '')
836 fs = SCons.Node.FS.FS()
839 assert isinstance(e1, SCons.Node.FS.Entry)
842 assert isinstance(d1, SCons.Node.FS.Dir)
843 assert d1.cwd is d1, d1
845 f1 = fs.File('f1', directory = d1)
846 assert isinstance(f1, SCons.Node.FS.File)
848 d1_f1 = os.path.join('d1', 'f1')
849 assert f1.path == d1_f1, "f1.path %s != %s" % (f1.path, d1_f1)
850 assert str(f1) == d1_f1, "str(f1) %s != %s" % (str(f1), d1_f1)
853 assert isinstance(x1, SCons.Node.FS.File)
854 assert str(x1) == os.path.join('d1', 'x1')
857 assert isinstance(x2, SCons.Node.FS.Dir)
858 assert str(x2) == os.path.join('d1', 'x2')
861 assert isinstance(x3, SCons.Node.FS.Entry)
862 assert str(x3) == os.path.join('d1', 'x3')
864 assert d1.File(x1) == x1
865 assert d1.Dir(x2) == x2
866 assert d1.Entry(x3) == x3
871 assert str(x4) == os.path.join('d1', 'x4')
874 assert str(x5) == os.path.join('d1', 'x5')
877 assert str(x6) == os.path.join('d1', 'x6')
879 assert str(x7) == os.path.join('d1', 'x7')
881 assert x1.File(x4) == x4
882 assert x1.Dir(x5) == x5
883 assert x1.Entry(x6) == x6
884 assert x1.Entry(x7) == x7
886 assert x1.Entry(x5) == x5
894 assert x1.Entry(x4) == x4
903 assert isinstance(x6, SCons.Node.FS.File)
906 assert isinstance(x7, SCons.Node.FS.Dir)
912 drive, path = os.path.splitdrive(os.getcwd())
916 def Dir_test(lpath, path_, abspath_, up_path_, fileSys=fs, s=sep, drive=drive):
917 dir = fileSys.Dir(string.replace(lpath, '/', s))
920 path_ = string.replace(path_, '/', os.sep)
921 abspath_ = string.replace(abspath_, '/', os.sep)
922 up_path_ = string.replace(up_path_, '/', os.sep)
924 def strip_slash(p, drive=drive):
925 if p[-1] == os.sep and len(p) > 1:
930 path = strip_slash(path_)
931 abspath = strip_slash(abspath_)
932 up_path = strip_slash(up_path_)
933 name = string.split(abspath, os.sep)[-1]
935 assert dir.name == name, \
936 "dir.name %s != expected name %s" % \
938 assert dir.path == path, \
939 "dir.path %s != expected path %s" % \
941 assert str(dir) == path, \
942 "str(dir) %s != expected path %s" % \
944 assert dir.get_abspath() == abspath, \
945 "dir.abspath %s != expected absolute path %s" % \
946 (dir.get_abspath(), abspath)
947 assert dir.up().path == up_path, \
948 "dir.up().path %s != expected parent path %s" % \
949 (dir.up().path, up_path)
951 Dir_test('foo', 'foo/', sub_dir_foo, './')
952 Dir_test('foo/bar', 'foo/bar/', sub_dir_foo_bar, 'foo/')
953 Dir_test('/foo', '/foo/', '/foo/', '/')
954 Dir_test('/foo/bar', '/foo/bar/', '/foo/bar/', '/foo/')
955 Dir_test('..', sub, sub, wp)
956 Dir_test('foo/..', './', sub_dir, sub)
957 Dir_test('../foo', sub_foo, sub_foo, sub)
958 Dir_test('.', './', sub_dir, sub)
959 Dir_test('./.', './', sub_dir, sub)
960 Dir_test('foo/./bar', 'foo/bar/', sub_dir_foo_bar, 'foo/')
961 Dir_test('#../foo', sub_foo, sub_foo, sub)
962 Dir_test('#/../foo', sub_foo, sub_foo, sub)
963 Dir_test('#foo/bar', 'foo/bar/', sub_dir_foo_bar, 'foo/')
964 Dir_test('#/foo/bar', 'foo/bar/', sub_dir_foo_bar, 'foo/')
965 Dir_test('#', './', sub_dir, sub)
968 f2 = fs.File(string.join(['f1', 'f2'], sep), directory = d1)
970 assert str(x) == ("Tried to lookup File '%s' as a Dir." %
976 dir = fs.Dir(string.join(['d1', 'f1'], sep))
978 assert str(x) == ("Tried to lookup File '%s' as a Dir." %
986 assert str(x) == ("Tried to lookup Dir '%s' as a File." %
991 # Test that just specifying the drive works to identify
992 # its root directory.
993 p = os.path.abspath(test.workpath('root_file'))
994 drive, path = os.path.splitdrive(p)
996 # The assert below probably isn't correct for the general
997 # case, but it works for Windows, which covers a lot
1000 assert str(dir) == drive + os.sep, str(dir)
1002 # Test for a bug in 0.04 that did not like looking up
1003 # dirs with a trailing slash on Windows.
1005 assert d.path == '.', d.abspath
1007 assert d.path == 'foo', d.abspath
1009 # Test for sub-classing of node building.
1014 d1.add_source([SCons.Node.Node()]) # XXX FAKE SUBCLASS ATTRIBUTE
1015 d1.builder_set(Builder(fs.File))
1017 d1.env_set(Environment())
1023 f1.add_source([SCons.Node.Node()]) # XXX FAKE SUBCLASS ATTRIBUTE
1024 f1.builder_set(Builder(fs.File))
1026 f1.env_set(Environment())
1030 def match(path, expect):
1031 expect = string.replace(expect, '/', os.sep)
1032 assert path == expect, "path %s != expected %s" % (path, expect)
1035 assert e1.__class__.__name__ == 'Dir'
1036 match(e1.path, "d1")
1037 match(e1.dir.path, ".")
1039 e2 = fs.Entry("d1/f1")
1040 assert e2.__class__.__name__ == 'File'
1041 match(e2.path, "d1/f1")
1042 match(e2.dir.path, "d1")
1045 assert e3.__class__.__name__ == 'Entry'
1046 match(e3.path, "e3")
1047 match(e3.dir.path, ".")
1049 e4 = fs.Entry("d1/e4")
1050 assert e4.__class__.__name__ == 'Entry'
1051 match(e4.path, "d1/e4")
1052 match(e4.dir.path, "d1")
1054 e5 = fs.Entry("e3/e5")
1055 assert e3.__class__.__name__ == 'Dir'
1056 match(e3.path, "e3")
1057 match(e3.dir.path, ".")
1058 assert e5.__class__.__name__ == 'Entry'
1059 match(e5.path, "e3/e5")
1060 match(e5.dir.path, "e3")
1062 e6 = fs.Dir("d1/e4")
1064 assert e4.__class__.__name__ == 'Dir'
1065 match(e4.path, "d1/e4")
1066 match(e4.dir.path, "d1")
1068 e7 = fs.File("e3/e5")
1070 assert e5.__class__.__name__ == 'File'
1071 match(e5.path, "e3/e5")
1072 match(e5.dir.path, "e3")
1074 fs.chdir(fs.Dir('subdir'))
1075 f11 = fs.File("f11")
1076 match(f11.path, "subdir/f11")
1078 e13 = fs.Entry("subdir/e13")
1079 match(e13.path, "subdir/subdir/e13")
1080 fs.chdir(fs.Dir('..'))
1083 f1.builder_set(Builder(fs.File))
1084 f1.env_set(Environment())
1085 xyz = fs.File("xyz")
1086 f1.builder.target_scanner = Scanner(xyz)
1089 assert f1.implicit[0].path == "xyz"
1092 assert f1.implicit == []
1095 assert f1.implicit[0].path == "xyz"
1097 # Test underlying scanning functionality in get_found_includes()
1099 f12 = fs.File("f12")
1102 deps = f12.get_found_includes(env, None, t1)
1103 assert deps == [], deps
1105 class MyScanner(Scanner):
1107 def __call__(self, node, env, path):
1108 self.call_count = self.call_count + 1
1109 return Scanner.__call__(self, node, env, path)
1112 deps = f12.get_found_includes(env, s, t1)
1113 assert deps == [xyz], deps
1114 assert s.call_count == 1, s.call_count
1118 deps = f12.get_found_includes(env, s, t1)
1119 assert deps == [xyz], deps
1120 assert s.call_count == 2, s.call_count
1122 env2 = Environment()
1124 deps = f12.get_found_includes(env2, s, t1)
1125 assert deps == [xyz], deps
1126 assert s.call_count == 3, s.call_count
1130 # Make sure we can scan this file even if the target isn't
1131 # a file that has a scanner (it might be an Alias, e.g.).
1135 deps = f12.get_found_includes(env, s, DummyNode())
1136 assert deps == [xyz], deps
1138 # Test building a file whose directory is not there yet...
1139 f1 = fs.File(test.workpath("foo/bar/baz/ack"))
1140 assert not f1.dir.exists()
1143 assert f1.dir.exists()
1148 fs = SCons.Node.FS.FS()
1149 assert str(fs.getcwd()) == ".", str(fs.getcwd())
1150 fs.chdir(fs.Dir('subdir'))
1151 # The cwd's path is always "."
1152 assert str(fs.getcwd()) == ".", str(fs.getcwd())
1153 assert fs.getcwd().path == 'subdir', fs.getcwd().path
1154 fs.chdir(fs.Dir('../..'))
1155 assert fs.getcwd().path == test.workdir, fs.getcwd().path
1157 f1 = fs.File(test.workpath("do_i_exist"))
1158 assert not f1.exists()
1159 test.write("do_i_exist","\n")
1160 assert not f1.exists(), "exists() call not cached"
1162 assert f1.exists(), "exists() call caching not reset"
1163 test.unlink("do_i_exist")
1166 assert not f1.exists()
1168 # For some reason, in Windows, the \x1a character terminates
1169 # the reading of files in text mode. This tests that
1170 # get_contents() returns the binary contents.
1171 test.write("binary_file", "Foo\x1aBar")
1172 f1 = fs.File(test.workpath("binary_file"))
1173 assert f1.get_contents() == "Foo\x1aBar", f1.get_contents()
1175 def nonexistent(method, s):
1177 x = method(s, create = 0)
1178 except SCons.Errors.UserError:
1181 raise TestFailed, "did not catch expected UserError"
1183 nonexistent(fs.Entry, 'nonexistent')
1184 nonexistent(fs.Entry, 'nonexistent/foo')
1186 nonexistent(fs.File, 'nonexistent')
1187 nonexistent(fs.File, 'nonexistent/foo')
1189 nonexistent(fs.Dir, 'nonexistent')
1190 nonexistent(fs.Dir, 'nonexistent/foo')
1192 test.write("preserve_me", "\n")
1193 assert os.path.exists(test.workpath("preserve_me"))
1194 f1 = fs.File(test.workpath("preserve_me"))
1196 assert os.path.exists(test.workpath("preserve_me"))
1198 test.write("remove_me", "\n")
1199 assert os.path.exists(test.workpath("remove_me"))
1200 f1 = fs.File(test.workpath("remove_me"))
1201 f1.builder = Builder(fs.File)
1202 f1.env_set(Environment())
1204 assert not os.path.exists(test.workpath("remove_me"))
1206 e = fs.Entry('e_local')
1207 assert not hasattr(e, '_local')
1209 assert e._local == 1
1210 f = fs.File('e_local')
1211 assert f._local == 1
1212 f = fs.File('f_local')
1213 assert f._local == 0
1215 #XXX test current() for directories
1217 #XXX test sconsign() for directories
1219 #XXX test set_signature() for directories
1221 #XXX test build() for directories
1225 # test Entry.get_contents()
1226 e = fs.Entry('does_not_exist')
1227 c = e.get_contents()
1229 assert e.__class__ == SCons.Node.FS.Entry
1231 test.write("file", "file\n")
1233 e = fs.Entry('file')
1234 c = e.get_contents()
1235 assert c == "file\n", c
1236 assert e.__class__ == SCons.Node.FS.File
1242 c = e.get_contents()
1244 assert e.__class__ == SCons.Node.FS.Dir
1246 if hasattr(os, 'symlink'):
1247 os.symlink('nonexistent', test.workpath('dangling_symlink'))
1248 e = fs.Entry('dangling_symlink')
1249 c = e.get_contents()
1250 assert e.__class__ == SCons.Node.FS.Entry, e.__class__
1253 test.write("tstamp", "tstamp\n")
1255 # Okay, *this* manipulation accomodates Windows FAT file systems
1256 # that only have two-second granularity on their timestamps.
1257 # We round down the current time to the nearest even integer
1258 # value, subtract two to make sure the timestamp is not "now,"
1259 # and then convert it back to a float.
1260 tstamp = float(int(time.time() / 2) * 2) - 2
1261 os.utime(test.workpath("tstamp"), (tstamp - 2.0, tstamp))
1262 f = fs.File("tstamp")
1263 t = f.get_timestamp()
1264 assert t == tstamp, "expected %f, got %f" % (tstamp, t)
1266 test.unlink("tstamp")
1268 test.subdir('tdir1')
1270 t = d.get_timestamp()
1271 assert t == 0, "expected 0, got %s" % str(t)
1273 test.subdir('tdir2')
1274 f1 = test.workpath('tdir2', 'file1')
1275 f2 = test.workpath('tdir2', 'file2')
1276 test.write(f1, 'file1\n')
1277 test.write(f2, 'file2\n')
1278 current_time = float(int(time.time() / 2) * 2)
1279 t1 = current_time - 4.0
1280 t2 = current_time - 2.0
1281 os.utime(f1, (t1 - 2.0, t1))
1282 os.utime(f2, (t2 - 2.0, t2))
1286 t = d.get_timestamp()
1287 assert t == t2, "expected %f, got %f" % (t2, t)
1289 skey = fs.Entry('eee.x').scanner_key()
1290 assert skey == '.x', skey
1291 skey = fs.Entry('eee.xyz').scanner_key()
1292 assert skey == '.xyz', skey
1294 skey = fs.File('fff.x').scanner_key()
1295 assert skey == '.x', skey
1296 skey = fs.File('fff.xyz').scanner_key()
1297 assert skey == '.xyz', skey
1299 skey = fs.Dir('ddd.x').scanner_key()
1300 assert skey is None, skey
1302 test.write("i_am_not_a_directory", "\n")
1306 fs.Dir(test.workpath("i_am_not_a_directory"))
1309 assert exc_caught, "Should have caught a TypeError"
1311 test.unlink("i_am_not_a_directory")
1318 assert exc_caught, "Should have caught a TypeError"
1320 # XXX test calc_signature()
1322 # XXX test current()
1328 f = fs.File('does_not_exist')
1332 test.write('exists', "exists\n")
1333 f = fs.File('exists')
1336 assert not os.path.exists(test.workpath('exists')), "exists was not removed"
1338 symlink = test.workpath('symlink')
1340 os.symlink(test.workpath('does_not_exist'), symlink)
1341 assert os.path.islink(symlink)
1342 f = fs.File('symlink')
1345 assert not os.path.islink(symlink), "symlink was not removed"
1346 except AttributeError:
1349 test.write('can_not_remove', "can_not_remove\n")
1350 test.writable(test.workpath('.'), 0)
1351 fp = open(test.workpath('can_not_remove'))
1353 f = fs.File('can_not_remove')
1362 assert exc_caught, "Should have caught an OSError, r = " + str(r)
1364 f = fs.Entry('foo/bar/baz')
1365 assert f.for_signature() == 'baz', f.for_signature()
1366 assert f.get_string(0) == os.path.normpath('foo/bar/baz'), \
1368 assert f.get_string(1) == 'baz', f.get_string(1)
1370 def test_target_from_source(self):
1371 """Test the method for generating target nodes from sources"""
1375 t = x.target_from_source('pre-', '-suf')
1376 assert str(t) == 'pre-x-suf', str(t)
1377 assert t.__class__ == SCons.Node.FS.Entry
1379 y = fs.File('dir/y')
1380 t = y.target_from_source('pre-', '-suf')
1381 assert str(t) == os.path.join('dir', 'pre-y-suf'), str(t)
1382 assert t.__class__ == SCons.Node.FS.Entry
1385 t = z.target_from_source('pre-', '-suf', lambda x: x[:-1])
1386 assert str(t) == 'pre-z-suf', str(t)
1387 assert t.__class__ == SCons.Node.FS.Entry
1390 t = d.target_from_source('pre-', '-suf')
1391 assert str(t) == 'pre-ddd-suf', str(t)
1392 assert t.__class__ == SCons.Node.FS.Entry
1395 t = e.target_from_source('pre-', '-suf')
1396 assert str(t) == 'pre-eee-suf', str(t)
1397 assert t.__class__ == SCons.Node.FS.Entry
1399 def test_same_name(self):
1400 """Test that a local same-named file isn't found for a Dir lookup"""
1404 test.subdir('subdir')
1405 test.write(['subdir', 'build'], "subdir/build\n")
1407 subdir = fs.Dir('subdir')
1408 fs.chdir(subdir, change_os_dir=1)
1409 path, dir = fs._transformPath('#build/file', subdir)
1410 self.fs._doLookup(SCons.Node.FS.File, path, dir)
1412 def test_above_root(self):
1413 """Testing looking up a path above the root directory"""
1419 dirs = string.split(os.path.normpath(d2.abspath), os.sep)
1420 above_path = apply(os.path.join, ['..']*len(dirs) + ['above'])
1421 above = d2.Dir(above_path)
1423 def test_rel_path(self):
1424 """Test the rel_path() method"""
1430 d1_d2 = d1.Dir('d2')
1431 d1_d2_f = d1_d2.File('f')
1435 d3_d4 = d3.Dir('d4')
1436 d3_d4_f = d3_d4.File('f')
1442 d1, d1_d2_f, 'd2/f',
1444 d1, d3_f, '../d3/f',
1445 d1, d3_d4, '../d3/d4',
1446 d1, d3_d4_f, '../d3/d4/f',
1451 d1_f, d1_d2_f, 'd2/f',
1453 d1_f, d3_f, '../d3/f',
1454 d1_f, d3_d4, '../d3/d4',
1455 d1_f, d3_d4_f, '../d3/d4/f',
1458 d1_d2, d1_f, '../f',
1460 d1_d2, d1_d2_f, 'f',
1461 d1_d2, d3, '../../d3',
1462 d1_d2, d3_f, '../../d3/f',
1463 d1_d2, d3_d4, '../../d3/d4',
1464 d1_d2, d3_d4_f, '../../d3/d4/f',
1467 d1_d2_f, d1_f, '../f',
1468 d1_d2_f, d1_d2, '.',
1469 d1_d2_f, d1_d2_f, 'f',
1470 d1_d2_f, d3, '../../d3',
1471 d1_d2_f, d3_f, '../../d3/f',
1472 d1_d2_f, d3_d4, '../../d3/d4',
1473 d1_d2_f, d3_d4_f, '../../d3/d4/f',
1476 if sys.platform in ('win32',):
1477 x_d1 = fs.Dir(r'X:\d1')
1478 x_d1_d2 = x_d1.Dir('d2')
1479 y_d1 = fs.Dir(r'Y:\d1')
1480 y_d1_d2 = y_d1.Dir('d2')
1481 y_d2 = fs.Dir(r'Y:\d2')
1485 x_d1, x_d1_d2, 'd2',
1486 x_d1, y_d1, r'Y:\d1',
1487 x_d1, y_d1_d2, r'Y:\d1\d2',
1488 x_d1, y_d2, r'Y:\d2',
1491 cases.extend(win32_cases)
1495 dir, other, expect = cases[:3]
1496 expect = os.path.normpath(expect)
1498 result = dir.rel_path(other)
1499 if result != expect:
1500 if failed == 0: print
1501 fmt = " dir_path(%(dir)s, %(other)s) => '%(result)s' did not match '%(expect)s'"
1502 print fmt % locals()
1504 assert failed == 0, "%d rel_path() cases failed" % failed
1506 def test_proxy(self):
1507 """Test a Node.FS object wrapped in a proxy instance"""
1508 f1 = self.fs.File('fff')
1510 # Simplest possibly Proxy class that works for our test,
1511 # this is stripped down from SCons.Util.Proxy.
1512 def __init__(self, subject):
1513 self.__subject = subject
1514 def __getattr__(self, name):
1515 return getattr(self.__subject, name)
1517 f2 = self.fs.Entry(p)
1518 assert f1 is f2, (f1, f2)
1522 class DirTestCase(_tempdirTestCase):
1524 def test__morph(self):
1525 """Test handling of actions when morphing an Entry into a Dir"""
1527 e = self.fs.Entry('eee')
1528 x = e.get_executor()
1529 x.add_pre_action('pre')
1530 x.add_post_action('post')
1531 e.must_be_same(SCons.Node.FS.Dir)
1532 a = x.get_action_list()
1533 assert a[0] == 'pre', a
1534 assert a[2] == 'post', a
1536 def test_get_env_scanner(self):
1537 """Test the Dir.get_env_scanner() method
1539 import SCons.Defaults
1540 d = self.fs.Dir('ddd')
1541 s = d.get_env_scanner(Environment())
1542 assert s is SCons.Defaults.DirEntryScanner, s
1544 def test_get_target_scanner(self):
1545 """Test the Dir.get_target_scanner() method
1547 import SCons.Defaults
1548 d = self.fs.Dir('ddd')
1549 s = d.get_target_scanner()
1550 assert s is SCons.Defaults.DirEntryScanner, s
1552 def test_scan(self):
1553 """Test scanning a directory for in-memory entries
1558 fs.File(os.path.join('ddd', 'f1'))
1559 fs.File(os.path.join('ddd', 'f2'))
1560 fs.File(os.path.join('ddd', 'f3'))
1561 fs.Dir(os.path.join('ddd', 'd1'))
1562 fs.Dir(os.path.join('ddd', 'd1', 'f4'))
1563 fs.Dir(os.path.join('ddd', 'd1', 'f5'))
1565 kids = map(lambda x: x.path, dir.children(None))
1567 assert kids == [os.path.join('ddd', 'd1'),
1568 os.path.join('ddd', 'f1'),
1569 os.path.join('ddd', 'f2'),
1570 os.path.join('ddd', 'f3')], kids
1572 def test_entry_exists_on_disk(self):
1573 """Test the Dir.entry_exists_on_disk() method
1577 does_not_exist = self.fs.Dir('does_not_exist')
1578 assert not does_not_exist.entry_exists_on_disk('foo')
1581 test.write(['d', 'exists'], "d/exists\n")
1582 test.write(['d', 'Case-Insensitive'], "d/Case-Insensitive\n")
1584 d = self.fs.Dir('d')
1585 assert d.entry_exists_on_disk('exists')
1586 assert not d.entry_exists_on_disk('does_not_exist')
1588 if os.path.normcase("TeSt") != os.path.normpath("TeSt") or sys.platform == "cygwin":
1589 assert d.entry_exists_on_disk('case-insensitive')
1591 def test_srcdir_list(self):
1592 """Test the Dir.srcdir_list() method
1594 src = self.fs.Dir('src')
1595 bld = self.fs.Dir('bld')
1596 sub1 = bld.Dir('sub')
1597 sub2 = sub1.Dir('sub')
1598 sub3 = sub2.Dir('sub')
1599 self.fs.BuildDir(bld, src, duplicate=0)
1600 self.fs.BuildDir(sub2, src, duplicate=0)
1602 def check(result, expect):
1603 result = map(str, result)
1604 expect = map(os.path.normpath, expect)
1605 assert result == expect, result
1607 s = src.srcdir_list()
1610 s = bld.srcdir_list()
1613 s = sub1.srcdir_list()
1614 check(s, ['src/sub'])
1616 s = sub2.srcdir_list()
1617 check(s, ['src', 'src/sub/sub'])
1619 s = sub3.srcdir_list()
1620 check(s, ['src/sub', 'src/sub/sub/sub'])
1622 self.fs.BuildDir('src/b1/b2', 'src')
1624 b1_b2 = b1.Dir('b2')
1625 b1_b2_b1 = b1_b2.Dir('b1')
1626 b1_b2_b1_b2 = b1_b2_b1.Dir('b2')
1627 b1_b2_b1_b2_sub = b1_b2_b1_b2.Dir('sub')
1629 s = b1.srcdir_list()
1632 s = b1_b2.srcdir_list()
1635 s = b1_b2_b1.srcdir_list()
1636 check(s, ['src/b1'])
1638 s = b1_b2_b1_b2.srcdir_list()
1641 s = b1_b2_b1_b2_sub.srcdir_list()
1644 def test_srcdir_duplicate(self):
1645 """Test the Dir.srcdir_duplicate() method
1650 test.write(['src0', 'exists'], "src0/exists\n")
1652 bld0 = self.fs.Dir('bld0')
1653 src0 = self.fs.Dir('src0')
1654 self.fs.BuildDir(bld0, src0, duplicate=0)
1656 n = bld0.srcdir_duplicate('does_not_exist')
1658 assert not os.path.exists(test.workpath('bld0', 'does_not_exist'))
1660 n = bld0.srcdir_duplicate('exists')
1661 assert str(n) == os.path.normpath('src0/exists'), str(n)
1662 assert not os.path.exists(test.workpath('bld0', 'exists'))
1665 test.write(['src1', 'exists'], "src0/exists\n")
1667 bld1 = self.fs.Dir('bld1')
1668 src1 = self.fs.Dir('src1')
1669 self.fs.BuildDir(bld1, src1, duplicate=1)
1671 n = bld1.srcdir_duplicate('does_not_exist')
1673 assert not os.path.exists(test.workpath('bld1', 'does_not_exist'))
1675 n = bld1.srcdir_duplicate('exists')
1676 assert str(n) == os.path.normpath('bld1/exists'), str(n)
1677 assert os.path.exists(test.workpath('bld1', 'exists'))
1679 def test_srcdir_find_file(self):
1680 """Test the Dir.srcdir_find_file() method
1684 return_true = lambda: 1
1687 test.write(['src0', 'on-disk-f1'], "src0/on-disk-f1\n")
1688 test.write(['src0', 'on-disk-f2'], "src0/on-disk-f2\n")
1689 test.write(['src0', 'on-disk-e1'], "src0/on-disk-e1\n")
1690 test.write(['src0', 'on-disk-e2'], "src0/on-disk-e2\n")
1692 bld0 = self.fs.Dir('bld0')
1693 src0 = self.fs.Dir('src0')
1694 self.fs.BuildDir(bld0, src0, duplicate=0)
1696 derived_f = src0.File('derived-f')
1697 derived_f.is_derived = return_true
1698 pseudo_f = src0.File('pseudo-f')
1699 pseudo_f.is_pseudo_derived = return_true
1700 exists_f = src0.File('exists-f')
1701 exists_f.exists = return_true
1703 derived_e = src0.Entry('derived-e')
1704 derived_e.is_derived = return_true
1705 pseudo_e = src0.Entry('pseudo-e')
1706 pseudo_e.is_pseudo_derived = return_true
1707 exists_e = src0.Entry('exists-e')
1708 exists_e.exists = return_true
1710 def check(result, expect):
1711 result = map(str, result)
1712 expect = map(os.path.normpath, expect)
1713 assert result == expect, result
1715 # First check from the source directory.
1716 n = src0.srcdir_find_file('does_not_exist')
1717 assert n == (None, None), n
1719 n = src0.srcdir_find_file('derived-f')
1720 check(n, ['src0/derived-f', 'src0'])
1721 n = src0.srcdir_find_file('pseudo-f')
1722 check(n, ['src0/pseudo-f', 'src0'])
1723 n = src0.srcdir_find_file('exists-f')
1724 check(n, ['src0/exists-f', 'src0'])
1725 n = src0.srcdir_find_file('on-disk-f1')
1726 check(n, ['src0/on-disk-f1', 'src0'])
1728 n = src0.srcdir_find_file('derived-e')
1729 check(n, ['src0/derived-e', 'src0'])
1730 n = src0.srcdir_find_file('pseudo-e')
1731 check(n, ['src0/pseudo-e', 'src0'])
1732 n = src0.srcdir_find_file('exists-e')
1733 check(n, ['src0/exists-e', 'src0'])
1734 n = src0.srcdir_find_file('on-disk-e1')
1735 check(n, ['src0/on-disk-e1', 'src0'])
1737 # Now check from the build directory.
1738 n = bld0.srcdir_find_file('does_not_exist')
1739 assert n == (None, None), n
1741 n = bld0.srcdir_find_file('derived-f')
1742 check(n, ['src0/derived-f', 'bld0'])
1743 n = bld0.srcdir_find_file('pseudo-f')
1744 check(n, ['src0/pseudo-f', 'bld0'])
1745 n = bld0.srcdir_find_file('exists-f')
1746 check(n, ['src0/exists-f', 'bld0'])
1747 n = bld0.srcdir_find_file('on-disk-f2')
1748 check(n, ['src0/on-disk-f2', 'bld0'])
1750 n = bld0.srcdir_find_file('derived-e')
1751 check(n, ['src0/derived-e', 'bld0'])
1752 n = bld0.srcdir_find_file('pseudo-e')
1753 check(n, ['src0/pseudo-e', 'bld0'])
1754 n = bld0.srcdir_find_file('exists-e')
1755 check(n, ['src0/exists-e', 'bld0'])
1756 n = bld0.srcdir_find_file('on-disk-e2')
1757 check(n, ['src0/on-disk-e2', 'bld0'])
1760 test.write(['src1', 'on-disk-f1'], "src1/on-disk-f1\n")
1761 test.write(['src1', 'on-disk-f2'], "src1/on-disk-f2\n")
1762 test.write(['src1', 'on-disk-e1'], "src1/on-disk-e1\n")
1763 test.write(['src1', 'on-disk-e2'], "src1/on-disk-e2\n")
1765 bld1 = self.fs.Dir('bld1')
1766 src1 = self.fs.Dir('src1')
1767 self.fs.BuildDir(bld1, src1, duplicate=1)
1769 derived_f = src1.File('derived-f')
1770 derived_f.is_derived = return_true
1771 pseudo_f = src1.File('pseudo-f')
1772 pseudo_f.is_pseudo_derived = return_true
1773 exists_f = src1.File('exists-f')
1774 exists_f.exists = return_true
1776 derived_e = src1.Entry('derived-e')
1777 derived_e.is_derived = return_true
1778 pseudo_e = src1.Entry('pseudo-e')
1779 pseudo_e.is_pseudo_derived = return_true
1780 exists_e = src1.Entry('exists-e')
1781 exists_e.exists = return_true
1783 # First check from the source directory.
1784 n = src1.srcdir_find_file('does_not_exist')
1785 assert n == (None, None), n
1787 n = src1.srcdir_find_file('derived-f')
1788 check(n, ['src1/derived-f', 'src1'])
1789 n = src1.srcdir_find_file('pseudo-f')
1790 check(n, ['src1/pseudo-f', 'src1'])
1791 n = src1.srcdir_find_file('exists-f')
1792 check(n, ['src1/exists-f', 'src1'])
1793 n = src1.srcdir_find_file('on-disk-f1')
1794 check(n, ['src1/on-disk-f1', 'src1'])
1796 n = src1.srcdir_find_file('derived-e')
1797 check(n, ['src1/derived-e', 'src1'])
1798 n = src1.srcdir_find_file('pseudo-e')
1799 check(n, ['src1/pseudo-e', 'src1'])
1800 n = src1.srcdir_find_file('exists-e')
1801 check(n, ['src1/exists-e', 'src1'])
1802 n = src1.srcdir_find_file('on-disk-e1')
1803 check(n, ['src1/on-disk-e1', 'src1'])
1805 # Now check from the build directory.
1806 n = bld1.srcdir_find_file('does_not_exist')
1807 assert n == (None, None), n
1809 n = bld1.srcdir_find_file('derived-f')
1810 check(n, ['bld1/derived-f', 'src1'])
1811 n = bld1.srcdir_find_file('pseudo-f')
1812 check(n, ['bld1/pseudo-f', 'src1'])
1813 n = bld1.srcdir_find_file('exists-f')
1814 check(n, ['bld1/exists-f', 'src1'])
1815 n = bld1.srcdir_find_file('on-disk-f2')
1816 check(n, ['bld1/on-disk-f2', 'bld1'])
1818 n = bld1.srcdir_find_file('derived-e')
1819 check(n, ['bld1/derived-e', 'src1'])
1820 n = bld1.srcdir_find_file('pseudo-e')
1821 check(n, ['bld1/pseudo-e', 'src1'])
1822 n = bld1.srcdir_find_file('exists-e')
1823 check(n, ['bld1/exists-e', 'src1'])
1824 n = bld1.srcdir_find_file('on-disk-e2')
1825 check(n, ['bld1/on-disk-e2', 'bld1'])
1827 def test_dir_on_disk(self):
1828 """Test the Dir.dir_on_disk() method"""
1829 self.test.subdir('sub', ['sub', 'exists'])
1830 self.test.write(['sub', 'file'], "self/file\n")
1831 sub = self.fs.Dir('sub')
1833 r = sub.dir_on_disk('does_not_exist')
1836 r = sub.dir_on_disk('exists')
1839 r = sub.dir_on_disk('file')
1842 def test_file_on_disk(self):
1843 """Test the Dir.file_on_disk() method"""
1844 self.test.subdir('sub', ['sub', 'dir'])
1845 self.test.write(['sub', 'exists'], "self/exists\n")
1846 sub = self.fs.Dir('sub')
1848 r = sub.file_on_disk('does_not_exist')
1851 r = sub.file_on_disk('exists')
1854 r = sub.file_on_disk('dir')
1857 class EntryTestCase(_tempdirTestCase):
1858 def test_runTest(self):
1859 """Test methods specific to the Entry sub-class.
1861 test = TestCmd(workdir='')
1862 # FS doesn't like the cwd to be something other than its root.
1863 os.chdir(test.workpath(""))
1865 fs = SCons.Node.FS.FS()
1869 assert e1.__class__ is SCons.Node.FS.File, e1.__class__
1872 test.write('e3f', "e3f\n")
1874 e3d = fs.Entry('e3d')
1876 assert e3d.__class__ is SCons.Node.FS.Dir, e3d.__class__
1878 e3f = fs.Entry('e3f')
1880 assert e3f.__class__ is SCons.Node.FS.File, e3f.__class__
1882 e3n = fs.Entry('e3n')
1884 assert e3n.__class__ is SCons.Node.FS.Entry, e3n.__class__
1887 test.write('e4f', "e4f\n")
1889 e4d = fs.Entry('e4d')
1890 exists = e4d.exists()
1891 assert e4d.__class__ is SCons.Node.FS.Dir, e4d.__class__
1892 assert exists, "e4d does not exist?"
1894 e4f = fs.Entry('e4f')
1895 exists = e4f.exists()
1896 assert e4f.__class__ is SCons.Node.FS.File, e4f.__class__
1897 assert exists, "e4f does not exist?"
1899 e4n = fs.Entry('e4n')
1900 exists = e4n.exists()
1901 assert e4n.__class__ is SCons.Node.FS.File, e4n.__class__
1902 assert not exists, "e4n exists?"
1905 def __init__(self, val):
1908 def __init__(self, val):
1910 def collect(self, args):
1911 return reduce(lambda x, y: x+y, args)
1912 def signature(self, executor):
1913 return self.val + 222
1914 self.module = M(val)
1917 test.write('e5f', "e5f\n")
1919 e5f = fs.Entry('e5f')
1920 sig = e5f.calc_signature(MyCalc(666))
1921 assert e5f.__class__ is SCons.Node.FS.File, e5f.__class__
1922 # This node has no builder, so it just calculates the
1923 # signature once: the source content signature.
1924 assert sig == 888, sig
1926 e5n = fs.Entry('e5n')
1927 sig = e5n.calc_signature(MyCalc(777))
1928 assert e5n.__class__ is SCons.Node.FS.File, e5n.__class__
1929 # Doesn't exist, no sources, and no builder: no sig
1930 assert sig is None, sig
1932 def test_Entry_Entry_lookup(self):
1933 """Test looking up an Entry within another Entry"""
1934 self.fs.Entry('#topdir')
1935 self.fs.Entry('#topdir/a/b/c')
1939 class FileTestCase(_tempdirTestCase):
1941 def test_Dirs(self):
1942 """Test the File.Dirs() method"""
1943 fff = self.fs.File('subdir/fff')
1944 # This simulates that the SConscript file that defined
1945 # fff is in subdir/.
1946 fff.cwd = self.fs.Dir('subdir')
1947 d1 = self.fs.Dir('subdir/d1')
1948 d2 = self.fs.Dir('subdir/d2')
1949 dirs = fff.Dirs(['d1', 'd2'])
1950 assert dirs == [d1, d2], map(str, dirs)
1952 def test_exists(self):
1953 """Test the File.exists() method"""
1957 src_f1 = fs.File('src/f1')
1958 assert not src_f1.exists(), "%s apparently exists?" % src_f1
1961 test.write(['src', 'f1'], "src/f1\n")
1963 assert not src_f1.exists(), "%s did not cache previous exists() value" % src_f1
1965 assert src_f1.exists(), "%s apparently does not exist?" % src_f1
1967 test.subdir('build')
1968 fs.BuildDir('build', 'src')
1969 build_f1 = fs.File('build/f1')
1971 assert build_f1.exists(), "%s did not realize that %s exists" % (build_f1, src_f1)
1972 assert os.path.exists(build_f1.abspath), "%s did not get duplicated on disk" % build_f1.abspath
1974 test.unlink(['src', 'f1'])
1975 src_f1.clear() # so the next exists() call will look on disk again
1977 assert build_f1.exists(), "%s did not cache previous exists() value" % build_f1
1979 build_f1.linked = None
1980 assert not build_f1.exists(), "%s did not realize that %s disappeared" % (build_f1, src_f1)
1981 assert not os.path.exists(build_f1.abspath), "%s did not get removed after %s was removed" % (build_f1, src_f1)
1985 class RepositoryTestCase(_tempdirTestCase):
1988 _tempdirTestCase.setUp(self)
1990 self.test.subdir('rep1', 'rep2', 'rep3', 'work')
1992 self.rep1 = self.test.workpath('rep1')
1993 self.rep2 = self.test.workpath('rep2')
1994 self.rep3 = self.test.workpath('rep3')
1996 os.chdir(self.test.workpath('work'))
1998 self.fs = SCons.Node.FS.FS()
1999 self.fs.Repository(self.rep1, self.rep2, self.rep3)
2001 def test_getRepositories(self):
2002 """Test the Dir.getRepositories() method"""
2003 self.fs.Repository('foo')
2004 self.fs.Repository(os.path.join('foo', 'bar'))
2005 self.fs.Repository('bar/foo')
2006 self.fs.Repository('bar')
2013 os.path.join('foo', 'bar'),
2014 os.path.join('bar', 'foo'),
2018 rep = self.fs.Dir('#').getRepositories()
2019 r = map(lambda x, np=os.path.normpath: np(str(x)), rep)
2020 assert r == expect, r
2022 def test_get_all_rdirs(self):
2023 """Test the Dir.get_all_rdirs() method"""
2024 self.fs.Repository('foo')
2025 self.fs.Repository(os.path.join('foo', 'bar'))
2026 self.fs.Repository('bar/foo')
2027 self.fs.Repository('bar')
2035 os.path.join('foo', 'bar'),
2036 os.path.join('bar', 'foo'),
2040 rep = self.fs.Dir('#').get_all_rdirs()
2041 r = map(lambda x, np=os.path.normpath: np(str(x)), rep)
2042 assert r == expect, r
2044 def test_rdir(self):
2045 """Test the Dir.rdir() method"""
2046 return_true = lambda: 1
2047 return_false = lambda: 0
2049 d1 = self.fs.Dir('d1')
2050 d2 = self.fs.Dir('d2')
2051 d3 = self.fs.Dir('d3')
2053 self.test.subdir([self.rep1, 'd2'])
2054 self.test.write([self.rep2, 'd3'], "")
2055 self.test.subdir([self.rep3, 'd3'])
2061 assert not r is d2, r
2063 assert r == os.path.join(self.rep1, 'd2'), r
2066 assert not r is d3, r
2068 assert r == os.path.join(self.rep3, 'd3'), r
2070 e1 = self.fs.Dir('e1')
2071 e1.exists = return_false
2072 e2 = self.fs.Dir('e2')
2073 e2.exists = return_false
2075 # Make sure we match entries in repositories,
2076 # regardless of whether they're derived or not.
2078 re1 = self.fs.Entry(os.path.join(self.rep1, 'e1'))
2079 re1.exists = return_true
2080 re1.is_derived = return_true
2081 re2 = self.fs.Entry(os.path.join(self.rep2, 'e2'))
2082 re2.exists = return_true
2083 re2.is_derived = return_false
2091 def test_rfile(self):
2092 """Test the File.rfile() method"""
2093 return_true = lambda: 1
2094 return_false = lambda: 0
2096 f1 = self.fs.File('f1')
2097 f2 = self.fs.File('f2')
2098 f3 = self.fs.File('f3')
2100 self.test.write([self.rep1, 'f2'], "")
2101 self.test.subdir([self.rep2, 'f3'])
2102 self.test.write([self.rep3, 'f3'], "")
2108 assert not r is f2, r
2110 assert r == os.path.join(self.rep1, 'f2'), r
2113 assert not r is f3, r
2115 assert r == os.path.join(self.rep3, 'f3'), r
2117 e1 = self.fs.File('e1')
2118 e1.exists = return_false
2119 e2 = self.fs.File('e2')
2120 e2.exists = return_false
2122 # Make sure we match entries in repositories,
2123 # regardless of whether they're derived or not.
2125 re1 = self.fs.Entry(os.path.join(self.rep1, 'e1'))
2126 re1.exists = return_true
2127 re1.is_derived = return_true
2128 re2 = self.fs.Entry(os.path.join(self.rep2, 'e2'))
2129 re2.exists = return_true
2130 re2.is_derived = return_false
2138 def test_Rfindalldirs(self):
2139 """Test the Rfindalldirs() methods"""
2145 rep1_d1 = fs.Dir(test.workpath('rep1', 'd1'))
2146 rep2_d1 = fs.Dir(test.workpath('rep2', 'd1'))
2147 rep3_d1 = fs.Dir(test.workpath('rep3', 'd1'))
2149 sub_d1 = sub.Dir('d1')
2150 rep1_sub_d1 = fs.Dir(test.workpath('rep1', 'sub', 'd1'))
2151 rep2_sub_d1 = fs.Dir(test.workpath('rep2', 'sub', 'd1'))
2152 rep3_sub_d1 = fs.Dir(test.workpath('rep3', 'sub', 'd1'))
2154 r = fs.Top.Rfindalldirs((d1,))
2155 assert r == [d1], map(str, r)
2157 r = fs.Top.Rfindalldirs((d1, d2))
2158 assert r == [d1, d2], map(str, r)
2160 r = fs.Top.Rfindalldirs(('d1',))
2161 assert r == [d1, rep1_d1, rep2_d1, rep3_d1], map(str, r)
2163 r = fs.Top.Rfindalldirs(('#d1',))
2164 assert r == [d1, rep1_d1, rep2_d1, rep3_d1], map(str, r)
2166 r = sub.Rfindalldirs(('d1',))
2167 assert r == [sub_d1, rep1_sub_d1, rep2_sub_d1, rep3_sub_d1], map(str, r)
2169 r = sub.Rfindalldirs(('#d1',))
2170 assert r == [d1, rep1_d1, rep2_d1, rep3_d1], map(str, r)
2172 r = fs.Top.Rfindalldirs(('d1', d2))
2173 assert r == [d1, rep1_d1, rep2_d1, rep3_d1, d2], map(str, r)
2175 def test_rexists(self):
2176 """Test the Entry.rexists() method"""
2180 test.write([self.rep1, 'f2'], "")
2181 test.write([self.rep2, "i_exist"], "\n")
2182 test.write(["work", "i_exist_too"], "\n")
2184 fs.BuildDir('build', '.')
2186 f = fs.File(test.workpath("work", "i_do_not_exist"))
2187 assert not f.rexists()
2189 f = fs.File(test.workpath("work", "i_exist"))
2192 f = fs.File(test.workpath("work", "i_exist_too"))
2195 f1 = fs.File(os.path.join('build', 'f1'))
2196 assert not f1.rexists()
2198 f2 = fs.File(os.path.join('build', 'f2'))
2201 def test_FAT_timestamps(self):
2202 """Test repository timestamps on FAT file systems"""
2206 test.write(["rep2", "tstamp"], "tstamp\n")
2208 # Okay, *this* manipulation accomodates Windows FAT file systems
2209 # that only have two-second granularity on their timestamps.
2210 # We round down the current time to the nearest even integer
2211 # value, subtract two to make sure the timestamp is not "now,"
2212 # and then convert it back to a float.
2213 tstamp = float(int(time.time() / 2) * 2) - 2
2214 os.utime(test.workpath("rep2", "tstamp"), (tstamp - 2.0, tstamp))
2215 f = fs.File("tstamp")
2216 t = f.get_timestamp()
2217 assert t == tstamp, "expected %f, got %f" % (tstamp, t)
2219 test.unlink(["rep2", "tstamp"])
2221 def test_get_contents(self):
2222 """Ensure get_contents() returns binary contents from Repositories"""
2226 test.write(["rep3", "contents"], "Con\x1aTents\n")
2228 c = fs.File("contents").get_contents()
2229 assert c == "Con\x1aTents\n", "got '%s'" % c
2231 test.unlink(["rep3", "contents"])
2233 #def test calc_signature(self):
2235 #def test current(self):
2239 class find_fileTestCase(unittest.TestCase):
2241 """Testing find_file function"""
2242 test = TestCmd(workdir = '')
2243 test.write('./foo', 'Some file\n')
2244 test.write('./foo2', 'Another file\n')
2247 test.write(['bar', 'on_disk'], 'Another file\n')
2248 test.write(['bar', 'same'], 'bar/same\n')
2250 fs = SCons.Node.FS.FS(test.workpath(""))
2251 # FS doesn't like the cwd to be something other than its root.
2252 os.chdir(test.workpath(""))
2254 node_derived = fs.File(test.workpath('bar/baz'))
2255 node_derived.builder_set(1) # Any non-zero value.
2256 node_pseudo = fs.File(test.workpath('pseudo'))
2257 node_pseudo.set_src_builder(1) # Any non-zero value.
2259 paths = tuple(map(fs.Dir, ['.', 'same', './bar']))
2260 nodes = [SCons.Node.FS.find_file('foo', paths)]
2261 nodes.append(SCons.Node.FS.find_file('baz', paths))
2262 nodes.append(SCons.Node.FS.find_file('pseudo', paths))
2263 nodes.append(SCons.Node.FS.find_file('same', paths))
2265 file_names = map(str, nodes)
2266 file_names = map(os.path.normpath, file_names)
2267 expect = ['./foo', './bar/baz', './pseudo', './bar/same']
2268 expect = map(os.path.normpath, expect)
2269 assert file_names == expect, file_names
2271 # Make sure we don't blow up if there's already a File in place
2272 # of a directory that we'd otherwise try to search. If this
2273 # is broken, we'll see an exception like "Tried to lookup File
2274 # 'bar/baz' as a Dir.
2275 SCons.Node.FS.find_file('baz/no_file_here', paths)
2278 save_sys_stdout = sys.stdout
2281 sio = StringIO.StringIO()
2283 SCons.Node.FS.find_file('foo2', paths, verbose="xyz")
2284 expect = " xyz: looking for 'foo2' in '.' ...\n" + \
2285 " xyz: ... FOUND 'foo2' in '.'\n"
2287 assert c == expect, c
2289 sio = StringIO.StringIO()
2291 SCons.Node.FS.find_file('baz2', paths, verbose=1)
2292 expect = " find_file: looking for 'baz2' in '.' ...\n" + \
2293 " find_file: looking for 'baz2' in 'same' ...\n" + \
2294 " find_file: looking for 'baz2' in 'bar' ...\n"
2296 assert c == expect, c
2298 sio = StringIO.StringIO()
2300 SCons.Node.FS.find_file('on_disk', paths, verbose=1)
2301 expect = " find_file: looking for 'on_disk' in '.' ...\n" + \
2302 " find_file: looking for 'on_disk' in 'same' ...\n" + \
2303 " find_file: looking for 'on_disk' in 'bar' ...\n" + \
2304 " find_file: ... FOUND 'on_disk' in 'bar'\n"
2306 assert c == expect, c
2308 sys.stdout = save_sys_stdout
2310 class StringDirTestCase(unittest.TestCase):
2312 """Test using a string as the second argument of
2315 test = TestCmd(workdir = '')
2317 fs = SCons.Node.FS.FS(test.workpath(''))
2319 d = fs.Dir('sub', '.')
2320 assert str(d) == 'sub'
2322 f = fs.File('file', 'sub')
2323 assert str(f) == os.path.join('sub', 'file')
2324 assert not f.exists()
2326 class stored_infoTestCase(unittest.TestCase):
2328 """Test how we store build information"""
2329 test = TestCmd(workdir = '')
2331 fs = SCons.Node.FS.FS(test.workpath(''))
2334 f = fs.File('file1', d)
2335 bi = f.get_stored_info()
2336 assert bi.ninfo.timestamp == 0, bi.ninfo.timestamp
2337 assert bi.ninfo.size == None, bi.ninfo.size
2343 def get_entry(self, name):
2346 f = fs.File('file2', d)
2347 f.dir.sconsign = MySConsign
2348 bi = f.get_stored_info()
2349 assert bi.xyzzy == 7, bi
2351 class has_src_builderTestCase(unittest.TestCase):
2353 """Test the has_src_builder() method"""
2354 test = TestCmd(workdir = '')
2355 fs = SCons.Node.FS.FS(test.workpath(''))
2356 os.chdir(test.workpath(''))
2358 test.subdir('sub2', ['sub2', 'SCCS'], ['sub2', 'RCS'])
2360 sub1 = fs.Dir('sub1', '.')
2361 f1 = fs.File('f1', sub1)
2362 f2 = fs.File('f2', sub1)
2363 f3 = fs.File('f3', sub1)
2364 sub2 = fs.Dir('sub2', '.')
2365 f4 = fs.File('f4', sub2)
2366 f5 = fs.File('f5', sub2)
2367 f6 = fs.File('f6', sub2)
2368 f7 = fs.File('f7', sub2)
2369 f8 = fs.File('f8', sub2)
2371 h = f1.has_src_builder()
2373 h = f1.has_builder()
2376 b1 = Builder(fs.File)
2377 sub1.set_src_builder(b1)
2379 test.write(['sub1', 'f2'], "sub1/f2\n")
2380 h = f1.has_src_builder() # cached from previous call
2382 h = f1.has_builder() # cached from previous call
2384 h = f2.has_src_builder()
2386 h = f2.has_builder()
2388 h = f3.has_src_builder()
2390 h = f3.has_builder()
2392 assert f3.builder is b1, f3.builder
2394 f7.set_src_builder(b1)
2397 test.write(['sub2', 'SCCS', 's.f5'], "sub2/SCCS/s.f5\n")
2398 test.write(['sub2', 'RCS', 'f6,v'], "sub2/RCS/f6,v\n")
2399 h = f4.has_src_builder()
2401 h = f4.has_builder()
2403 h = f5.has_src_builder()
2405 h = f5.has_builder()
2407 h = f6.has_src_builder()
2409 h = f6.has_builder()
2411 h = f7.has_src_builder()
2413 h = f7.has_builder()
2415 h = f8.has_src_builder()
2417 h = f8.has_builder()
2420 class prepareTestCase(unittest.TestCase):
2422 """Test the prepare() method"""
2424 class MyFile(SCons.Node.FS.File):
2425 def _createDir(self, update=None):
2426 raise SCons.Errors.StopError
2430 fs = SCons.Node.FS.FS()
2431 file = MyFile('foo', fs.Dir('.'), fs)
2436 except SCons.Errors.StopError:
2438 assert exc_caught, "Should have caught a StopError."
2440 class MkdirAction(Action):
2441 def __init__(self, dir_made):
2442 self.dir_made = dir_made
2443 def __call__(self, target, source, env, errfunc):
2444 self.dir_made.extend(target)
2447 new_dir = fs.Dir("new_dir")
2448 new_dir.builder = Builder(fs.Dir, action=MkdirAction(dir_made))
2449 new_dir.reset_executor()
2450 xyz = fs.File(os.path.join("new_dir", "xyz"))
2452 xyz.set_state(SCons.Node.up_to_date)
2454 assert dir_made == [], dir_made
2458 assert dir_made[0].path == "new_dir", dir_made[0]
2463 class SConstruct_dirTestCase(unittest.TestCase):
2465 """Test setting the SConstruct directory"""
2467 fs = SCons.Node.FS.FS()
2468 fs.set_SConstruct_dir(fs.Dir('xxx'))
2469 assert fs.SConstruct_dir.path == 'xxx'
2471 class CacheDirTestCase(unittest.TestCase):
2473 """Test CacheDir functionality"""
2474 test = TestCmd(workdir='')
2478 fs = SCons.Node.FS.FS()
2479 assert fs.CachePath is None, fs.CachePath
2480 assert fs.cache_force is None, fs.cache_force
2481 assert fs.cache_show is None, fs.cache_show
2483 fs.CacheDir('cache')
2484 assert fs.CachePath == 'cache', fs.CachePath
2486 save_CacheRetrieve = SCons.Node.FS.CacheRetrieve
2488 def retrieve_succeed(target, source, env, self=self, execute=1):
2489 self.retrieved.append(target)
2491 def retrieve_fail(target, source, env, self=self, execute=1):
2492 self.retrieved.append(target)
2495 f1 = fs.File("cd.f1")
2496 f1.builder_set(Builder(fs.File))
2497 f1.env_set(Environment())
2499 SCons.Node.FS.CacheRetrieve = retrieve_succeed
2503 r = f1.retrieve_from_cache()
2505 assert self.retrieved == [f1], self.retrieved
2506 assert built_it is None, built_it
2508 SCons.Node.FS.CacheRetrieve = retrieve_fail
2512 r = f1.retrieve_from_cache()
2514 assert self.retrieved == [f1], self.retrieved
2515 assert built_it is None, built_it
2517 SCons.Node.FS.CacheRetrieve = save_CacheRetrieve
2519 save_CacheRetrieveSilent = SCons.Node.FS.CacheRetrieveSilent
2523 f2 = fs.File("cd.f2")
2524 f2.builder_set(Builder(fs.File))
2525 f2.env_set(Environment())
2527 SCons.Node.FS.CacheRetrieveSilent = retrieve_succeed
2531 r = f2.retrieve_from_cache()
2533 assert self.retrieved == [f2], self.retrieved
2534 assert built_it is None, built_it
2536 SCons.Node.FS.CacheRetrieveSilent = retrieve_fail
2540 r = f2.retrieve_from_cache()
2542 assert self.retrieved == [f2], self.retrieved
2543 assert built_it is None, built_it
2545 SCons.Node.FS.CacheRetrieveSilent = save_CacheRetrieveSilent
2547 save_CachePush = SCons.Node.FS.CachePush
2548 def push(target, source, env, self=self):
2549 self.pushed.append(target)
2551 SCons.Node.FS.CachePush = push
2556 cd_f3 = test.workpath("cd.f3")
2559 assert self.pushed == [], self.pushed
2560 test.write(cd_f3, "cd.f3\n")
2562 assert self.pushed == [f3], self.pushed
2566 cd_f4 = test.workpath("cd.f4")
2569 assert self.pushed == [], self.pushed
2570 test.write(cd_f4, "cd.f4\n")
2572 assert self.pushed == [], self.pushed
2575 assert self.pushed == [f4], self.pushed
2577 SCons.Node.FS.CachePush = save_CachePush
2579 # Verify how the cachepath() method determines the name
2580 # of the file in cache.
2581 def my_collect(list):
2583 save_collect = SCons.Sig.MD5.collect
2584 SCons.Sig.MD5.collect = my_collect
2586 f5 = fs.File("cd.f5")
2587 f5.binfo = f5.BuildInfo(f5)
2588 f5.binfo.ninfo.bsig = 'a_fake_bsig'
2590 dirname = os.path.join('cache', 'A')
2591 filename = os.path.join(dirname, 'a_fake_bsig')
2592 assert cp == (dirname, filename), cp
2594 SCons.Sig.MD5.collect = save_collect
2596 # Verify that no bsig raises an InternalERror
2597 f6 = fs.File("cd.f6")
2598 f6.binfo = f6.BuildInfo(f6)
2602 except SCons.Errors.InternalError:
2606 # Verify that we raise a warning if we can't copy a file to cache.
2607 save_copy2 = shutil.copy2
2608 def copy2(src, dst):
2610 shutil.copy2 = copy2
2611 save_mkdir = os.mkdir
2612 def mkdir(dir, mode=0):
2615 old_warn_exceptions = SCons.Warnings.warningAsException(1)
2616 SCons.Warnings.enableWarningClass(SCons.Warnings.CacheWriteErrorWarning)
2619 cd_f7 = test.workpath("cd.f7")
2620 test.write(cd_f7, "cd.f7\n")
2622 f7.binfo = f7.BuildInfo(f7)
2623 f7.binfo.ninfo.bsig = 'f7_bsig'
2628 except SCons.Warnings.CacheWriteErrorWarning:
2632 shutil.copy2 = save_copy2
2633 os.mkdir = save_mkdir
2634 SCons.Warnings.warningAsException(old_warn_exceptions)
2635 SCons.Warnings.suppressWarningClass(SCons.Warnings.CacheWriteErrorWarning)
2637 # Verify that we don't blow up if there's no strfunction()
2640 act.strfunction = None
2641 f8 = fs.File("cd.f8")
2642 f8.builder_set(Builder(fs.File, action=act))
2643 f8.env_set(Environment())
2645 SCons.Node.FS.CacheRetrieveSilent = retrieve_succeed
2649 r = f8.retrieve_from_cache()
2651 assert self.retrieved == [f8], self.retrieved
2652 assert built_it is None, built_it
2654 SCons.Node.FS.CacheRetrieveSilent = retrieve_fail
2658 r = f8.retrieve_from_cache()
2660 assert self.retrieved == [f8], self.retrieved
2661 assert built_it is None, built_it
2663 SCons.Node.FS.CacheRetrieveSilent = save_CacheRetrieveSilent
2665 class clearTestCase(unittest.TestCase):
2667 """Test clearing FS nodes of cached data."""
2668 fs = SCons.Node.FS.FS()
2669 test = TestCmd(workdir='')
2672 assert not e.exists()
2673 assert not e.rexists()
2674 assert str(e) == 'e', str(d)
2676 assert not e.exists()
2677 assert not e.rexists()
2678 assert str(e) == 'e', str(d)
2680 d = fs.Dir(test.workpath('d'))
2684 assert str(d) == test.workpath('d'), str(d)
2685 fs.rename(test.workpath('d'), test.workpath('gone'))
2686 # Verify caching is active
2687 assert d.exists(), 'caching not active'
2689 assert str(d) == test.workpath('d'), str(d)
2690 # Now verify clear() resets the cache
2692 assert not d.exists()
2693 assert not d.rexists()
2694 assert str(d) == test.workpath('d'), str(d)
2696 f = fs.File(test.workpath('f'))
2697 test.write(test.workpath('f'), 'file f')
2700 assert str(f) == test.workpath('f'), str(f)
2701 # Verify caching is active
2702 test.unlink(test.workpath('f'))
2705 assert str(f) == test.workpath('f'), str(f)
2706 # Now verify clear() resets the cache
2708 assert not f.exists()
2709 assert not f.rexists()
2710 assert str(f) == test.workpath('f'), str(f)
2712 class disambiguateTestCase(unittest.TestCase):
2714 """Test calling the disambiguate() method."""
2715 test = TestCmd(workdir='')
2717 fs = SCons.Node.FS.FS()
2720 d = ddd.disambiguate()
2723 fff = fs.File('fff')
2724 f = fff.disambiguate()
2728 test.write('efile', "efile\n")
2730 edir = fs.Entry(test.workpath('edir'))
2731 d = edir.disambiguate()
2732 assert d.__class__ is ddd.__class__, d.__class__
2734 efile = fs.Entry(test.workpath('efile'))
2735 f = efile.disambiguate()
2736 assert f.__class__ is fff.__class__, f.__class__
2738 test.subdir('build')
2739 test.subdir(['build', 'bdir'])
2740 test.write(['build', 'bfile'], "build/bfile\n")
2743 test.write(['src', 'bdir'], "src/bdir\n")
2744 test.subdir(['src', 'bfile'])
2746 test.subdir(['src', 'edir'])
2747 test.write(['src', 'efile'], "src/efile\n")
2749 fs.BuildDir(test.workpath('build'), test.workpath('src'))
2751 build_bdir = fs.Entry(test.workpath('build/bdir'))
2752 d = build_bdir.disambiguate()
2753 assert d is build_bdir, d
2754 assert d.__class__ is ddd.__class__, d.__class__
2756 build_bfile = fs.Entry(test.workpath('build/bfile'))
2757 f = build_bfile.disambiguate()
2758 assert f is build_bfile, f
2759 assert f.__class__ is fff.__class__, f.__class__
2761 build_edir = fs.Entry(test.workpath('build/edir'))
2762 d = build_edir.disambiguate()
2763 assert d.__class__ is ddd.__class__, d.__class__
2765 build_efile = fs.Entry(test.workpath('build/efile'))
2766 f = build_efile.disambiguate()
2767 assert f.__class__ is fff.__class__, f.__class__
2769 build_nonexistant = fs.Entry(test.workpath('build/nonexistant'))
2770 f = build_nonexistant.disambiguate()
2771 assert f.__class__ is fff.__class__, f.__class__
2773 class postprocessTestCase(unittest.TestCase):
2775 """Test calling the postprocess() method."""
2776 fs = SCons.Node.FS.FS()
2787 class SpecialAttrTestCase(unittest.TestCase):
2789 """Test special attributes of file nodes."""
2790 test=TestCmd(workdir='')
2791 fs = SCons.Node.FS.FS(test.workpath('work'))
2793 f = fs.Entry('foo/bar/baz.blat').get_subst_proxy()
2796 assert s == os.path.normpath('foo/bar'), s
2797 assert f.dir.is_literal(), f.dir
2798 for_sig = f.dir.for_signature()
2799 assert for_sig == 'bar', for_sig
2802 assert s == 'baz.blat', s
2803 assert f.file.is_literal(), f.file
2804 for_sig = f.file.for_signature()
2805 assert for_sig == 'baz.blat_file', for_sig
2808 assert s == os.path.normpath('foo/bar/baz'), s
2809 assert f.base.is_literal(), f.base
2810 for_sig = f.base.for_signature()
2811 assert for_sig == 'baz.blat_base', for_sig
2814 assert s == 'baz', s
2815 assert f.filebase.is_literal(), f.filebase
2816 for_sig = f.filebase.for_signature()
2817 assert for_sig == 'baz.blat_filebase', for_sig
2820 assert s == '.blat', s
2821 assert f.suffix.is_literal(), f.suffix
2822 for_sig = f.suffix.for_signature()
2823 assert for_sig == 'baz.blat_suffix', for_sig
2826 assert s == test.workpath('work', 'foo', 'bar', 'baz.blat'), s
2827 assert f.abspath.is_literal(), f.abspath
2828 for_sig = f.abspath.for_signature()
2829 assert for_sig == 'baz.blat_abspath', for_sig
2832 assert s == 'foo/bar/baz.blat', s
2833 assert f.posix.is_literal(), f.posix
2835 for_sig = f.posix.for_signature()
2836 assert for_sig == 'baz.blat_posix', for_sig
2839 assert s == 'foo\\bar\\baz.blat', repr(s)
2840 assert f.windows.is_literal(), f.windows
2842 for_sig = f.windows.for_signature()
2843 assert for_sig == 'baz.blat_windows', for_sig
2845 # Deprecated synonym for the .windows suffix.
2847 assert s == 'foo\\bar\\baz.blat', repr(s)
2848 assert f.win32.is_literal(), f.win32
2850 for_sig = f.win32.for_signature()
2851 assert for_sig == 'baz.blat_windows', for_sig
2853 # And now, combinations!!!
2854 s = str(f.srcpath.base)
2855 assert s == os.path.normpath('foo/bar/baz'), s
2856 s = str(f.srcpath.dir)
2857 assert s == str(f.srcdir), s
2858 s = str(f.srcpath.posix)
2859 assert s == 'foo/bar/baz.blat', s
2860 s = str(f.srcpath.windows)
2861 assert s == 'foo\\bar\\baz.blat', s
2862 s = str(f.srcpath.win32)
2863 assert s == 'foo\\bar\\baz.blat', s
2865 # Test what happens with BuildDir()
2866 fs.BuildDir('foo', 'baz')
2869 assert s == os.path.normpath('baz/bar/baz.blat'), s
2870 assert f.srcpath.is_literal(), f.srcpath
2872 assert isinstance(g, SCons.Node.FS.Entry), g.__class__
2875 assert s == os.path.normpath('baz/bar'), s
2876 assert f.srcdir.is_literal(), f.srcdir
2878 assert isinstance(g, SCons.Node.FS.Dir), g.__class__
2880 # And now what happens with BuildDir() + Repository()
2881 fs.Repository(test.workpath('repository'))
2883 f = fs.Entry('foo/sub/file.suffix').get_subst_proxy()
2884 test.subdir('repository',
2885 ['repository', 'baz'],
2886 ['repository', 'baz', 'sub'])
2888 rd = test.workpath('repository', 'baz', 'sub')
2889 rf = test.workpath('repository', 'baz', 'sub', 'file.suffix')
2890 test.write(rf, "\n")
2893 assert s == os.path.normpath('baz/sub/file.suffix'), s
2894 assert f.srcpath.is_literal(), f.srcpath
2896 assert isinstance(g, SCons.Node.FS.Entry), g.__class__
2899 assert s == os.path.normpath('baz/sub'), s
2900 assert f.srcdir.is_literal(), f.srcdir
2902 assert isinstance(g, SCons.Node.FS.Dir), g.__class__
2906 assert f.rsrcpath.is_literal(), f.rsrcpath
2907 g = f.rsrcpath.get()
2908 assert isinstance(g, SCons.Node.FS.File), g.__class__
2912 assert f.rsrcdir.is_literal(), f.rsrcdir
2914 assert isinstance(g, SCons.Node.FS.Dir), g.__class__
2916 # Check that attempts to access non-existent attributes of the
2917 # subst proxy generate the right exceptions and messages.
2920 fs.Dir('ddd').get_subst_proxy().no_such_attr
2921 except AttributeError, e:
2922 assert str(e) == "Dir instance 'ddd' has no attribute 'no_such_attr'", e
2924 assert caught, "did not catch expected AttributeError"
2928 fs.Entry('eee').get_subst_proxy().no_such_attr
2929 except AttributeError, e:
2930 assert str(e) == "Entry instance 'eee' has no attribute 'no_such_attr'", e
2932 assert caught, "did not catch expected AttributeError"
2936 fs.File('fff').get_subst_proxy().no_such_attr
2937 except AttributeError, e:
2938 assert str(e) == "File instance 'fff' has no attribute 'no_such_attr'", e
2940 assert caught, "did not catch expected AttributeError"
2942 class SaveStringsTestCase(unittest.TestCase):
2944 """Test caching string values of nodes."""
2945 test=TestCmd(workdir='')
2952 d0_f = fs.File('d0/f')
2953 d1_f = fs.File('d1/f')
2954 d0_b = fs.File('d0/b')
2955 d1_b = fs.File('d1/b')
2961 return [d0_f, d1_f, d0_b, d1_b]
2964 d0_f, d1_f, d0_b, d1_b = nodes
2970 fs1 = SCons.Node.FS.FS(test.workpath('fs1'))
2972 fs1.BuildDir('d0', 'src', duplicate=0)
2973 fs1.BuildDir('d1', 'src', duplicate=1)
2976 expect = map(os.path.normpath, ['src/f', 'd1/f', 'd0/b', 'd1/b'])
2977 assert s == expect, s
2982 expect = map(os.path.normpath, ['src/f', 'src/f', 'd0/b', 'd1/b'])
2983 assert s == expect, s
2985 SCons.Node.FS.save_strings(1)
2986 fs2 = SCons.Node.FS.FS(test.workpath('fs2'))
2988 fs2.BuildDir('d0', 'src', duplicate=0)
2989 fs2.BuildDir('d1', 'src', duplicate=1)
2992 expect = map(os.path.normpath, ['src/f', 'd1/f', 'd0/b', 'd1/b'])
2993 assert s == expect, s
2998 expect = map(os.path.normpath, ['src/f', 'd1/f', 'd0/b', 'd1/b'])
2999 assert s == expect, 'node str() not cached: %s'%s
3001 if __name__ == "__main__":
3002 suite = unittest.TestSuite()
3003 suite.addTest(BuildDirTestCase())
3004 suite.addTest(find_fileTestCase())
3005 suite.addTest(StringDirTestCase())
3006 suite.addTest(stored_infoTestCase())
3007 suite.addTest(has_src_builderTestCase())
3008 suite.addTest(prepareTestCase())
3009 suite.addTest(SConstruct_dirTestCase())
3010 suite.addTest(CacheDirTestCase())
3011 suite.addTest(clearTestCase())
3012 suite.addTest(disambiguateTestCase())
3013 suite.addTest(postprocessTestCase())
3014 suite.addTest(SpecialAttrTestCase())
3015 suite.addTest(SaveStringsTestCase())
3019 DirBuildInfoTestCase,
3020 DirNodeInfoTestCase,
3023 FileBuildInfoTestCase,
3024 FileNodeInfoTestCase,
3028 for tclass in tclasses:
3029 names = unittest.getTestCaseNames(tclass, 'test_')
3030 suite.addTests(map(tclass, names))
3031 if not unittest.TextTestRunner().run(suite).wasSuccessful():