1
# Copyright (c) 2001-2009 Twisted Matrix Laboratories.
2
# See LICENSE for details.
5
Test cases covering L{twisted.python.filepath} and L{twisted.python.zippath}.
8
import os, time, pickle, errno, zipfile, stat
10
from twisted.python.compat import set
11
from twisted.python.win32 import WindowsError, ERROR_DIRECTORY
12
from twisted.python import filepath
13
from twisted.python.zippath import ZipArchive
14
from twisted.python.runtime import platform
16
from twisted.trial import unittest
19
class AbstractFilePathTestCase(unittest.TestCase):
24
def _mkpath(self, *p):
25
x = os.path.abspath(os.path.join(self.cmn, *p))
30
def subdir(self, *dirname):
31
os.mkdir(self._mkpath(*dirname))
34
def subfile(self, *dirname):
35
return open(self._mkpath(*dirname), "wb")
39
self.now = time.time()
40
cmn = self.cmn = os.path.abspath(self.mktemp())
44
f = self.subfile("file1")
45
f.write(self.f1content)
47
f = self.subfile("sub1", "file2")
48
f.write(self.f2content)
51
f = self.subfile("sub3", "file3.ext1")
53
f = self.subfile("sub3", "file3.ext2")
55
f = self.subfile("sub3", "file3.ext3")
57
self.path = filepath.FilePath(cmn)
58
self.root = filepath.FilePath("/")
61
def test_segmentsFromPositive(self):
63
Verify that the segments between two paths are correctly identified.
66
self.path.child("a").child("b").child("c").segmentsFrom(self.path),
69
def test_segmentsFromNegative(self):
70
"""Verify that segmentsFrom notices when the ancestor isn't an ancestor.
74
self.path.child("a").child("b").child("c").segmentsFrom,
75
self.path.child("d").child("c").child("e"))
80
Verify that walking the path gives the same result as the known file
83
x = [foo.path for foo in self.path.walk()]
84
self.assertEquals(set(x), set(self.all))
87
def test_parents(self):
89
L{FilePath.parents()} should return an iterator of every ancestor of
90
the L{FilePath} in question.
93
pathobj = self.path.child("a").child("b").child("c")
94
fullpath = pathobj.path
96
thispath = os.path.dirname(fullpath)
97
while lastpath != self.root.path:
100
thispath = os.path.dirname(thispath)
101
self.assertEquals([x.path for x in pathobj.parents()], L)
104
def test_validSubdir(self):
105
"""Verify that a valid subdirectory will show up as a directory, but not as a
106
file, not as a symlink, and be listable.
108
sub1 = self.path.child('sub1')
109
self.failUnless(sub1.exists(),
110
"This directory does exist.")
111
self.failUnless(sub1.isdir(),
113
self.failUnless(not sub1.isfile(),
115
self.failUnless(not sub1.islink(),
117
self.failUnlessEqual(sub1.listdir(),
121
def test_invalidSubdir(self):
123
Verify that a subdirectory that doesn't exist is reported as such.
125
sub2 = self.path.child('sub2')
126
self.failIf(sub2.exists(),
127
"This directory does not exist.")
129
def test_validFiles(self):
131
Make sure that we can read existent non-empty files.
133
f1 = self.path.child('file1')
134
self.failUnlessEqual(f1.open().read(), self.f1content)
135
f2 = self.path.child('sub1').child('file2')
136
self.failUnlessEqual(f2.open().read(), self.f2content)
139
def test_dictionaryKeys(self):
141
Verify that path instances are usable as dictionary keys.
143
f1 = self.path.child('file1')
144
f1prime = self.path.child('file1')
145
f2 = self.path.child('file2')
149
self.assertEquals(dictoid[f1], 4)
150
self.assertEquals(dictoid.keys(), [f1])
151
self.assertIdentical(dictoid.keys()[0], f1)
152
self.assertNotIdentical(dictoid.keys()[0], f1prime) # sanity check
154
self.assertEquals(dictoid[f2], 5)
155
self.assertEquals(len(dictoid), 2)
158
def test_dictionaryKeyWithString(self):
160
Verify that path instances are usable as dictionary keys which do not clash
161
with their string counterparts.
163
f1 = self.path.child('file1')
164
dictoid = {f1: 'hello'}
165
dictoid[f1.path] = 'goodbye'
166
self.assertEquals(len(dictoid), 2)
169
def test_childrenNonexistentError(self):
171
Verify that children raises the appropriate exception for non-existent
174
self.assertRaises(filepath.UnlistableError,
175
self.path.child('not real').children)
177
def test_childrenNotDirectoryError(self):
179
Verify that listdir raises the appropriate exception for attempting to list
180
a file rather than a directory.
182
self.assertRaises(filepath.UnlistableError,
183
self.path.child('file1').children)
186
def test_newTimesAreFloats(self):
188
Verify that all times returned from the various new time functions are ints
189
(and hopefully therefore 'high precision').
191
for p in self.path, self.path.child('file1'):
192
self.failUnlessEqual(type(p.getAccessTime()), float)
193
self.failUnlessEqual(type(p.getModificationTime()), float)
194
self.failUnlessEqual(type(p.getStatusChangeTime()), float)
197
def test_oldTimesAreInts(self):
199
Verify that all times returned from the various time functions are
200
integers, for compatibility.
202
for p in self.path, self.path.child('file1'):
203
self.failUnlessEqual(type(p.getatime()), int)
204
self.failUnlessEqual(type(p.getmtime()), int)
205
self.failUnlessEqual(type(p.getctime()), int)
209
class FakeWindowsPath(filepath.FilePath):
211
A test version of FilePath which overrides listdir to raise L{WindowsError}.
216
@raise WindowsError: always.
220
"A directory's validness was called into question")
223
class ListingCompatibilityTests(unittest.TestCase):
225
These tests verify compatibility with legacy behavior of directory listing.
228
def test_windowsErrorExcept(self):
230
Verify that when a WindowsError is raised from listdir, catching
233
fwp = FakeWindowsPath(self.mktemp())
234
self.assertRaises(filepath.UnlistableError, fwp.children)
235
self.assertRaises(WindowsError, fwp.children)
238
def test_alwaysCatchOSError(self):
240
Verify that in the normal case where a directory does not exist, we will
243
fp = filepath.FilePath(self.mktemp())
244
self.assertRaises(OSError, fp.children)
247
def test_keepOriginalAttributes(self):
249
Verify that the Unlistable exception raised will preserve the attributes of
250
the previously-raised exception.
252
fp = filepath.FilePath(self.mktemp())
253
ose = self.assertRaises(OSError, fp.children)
254
d1 = ose.__dict__.keys()
255
d1.remove('originalException')
256
d2 = ose.originalException.__dict__.keys()
259
self.assertEquals(d1, d2)
263
def zipit(dirname, zfname):
265
create a zipfile on zfname, containing the contents of dirname'
267
zf = zipfile.ZipFile(zfname, "w")
268
basedir = os.path.basename(dirname)
269
for root, dirs, files, in os.walk(dirname):
271
fspath = os.path.join(root, fname)
272
arcpath = os.path.join(root, fname)[len(dirname)+1:]
273
# print fspath, '=>', arcpath
274
zf.write(fspath, arcpath)
279
class ZipFilePathTestCase(AbstractFilePathTestCase):
281
Test various L{ZipPath} path manipulations as well as reprs for L{ZipPath}
285
AbstractFilePathTestCase.setUp(self)
286
zipit(self.cmn, self.cmn + '.zip')
287
self.path = ZipArchive(self.cmn + '.zip')
288
self.root = self.path
289
self.all = [x.replace(self.cmn, self.cmn + '.zip') for x in self.all]
292
def test_zipPathRepr(self):
294
Make sure that invoking ZipPath's repr prints the correct class name
295
and an absolute path to the zip file.
297
child = self.path.child("foo")
298
pathRepr = "ZipPath(%r)" % (
299
os.path.abspath(self.cmn + ".zip" + os.sep + 'foo'),)
301
# Check for an absolute path
302
self.assertEquals(repr(child), pathRepr)
304
# Create a path to the file rooted in the current working directory
305
relativeCommon = self.cmn.replace(os.getcwd() + os.sep, "", 1) + ".zip"
306
relpath = ZipArchive(relativeCommon)
307
child = relpath.child("foo")
309
# Check using a path without the cwd prepended
310
self.assertEquals(repr(child), pathRepr)
313
def test_zipArchiveRepr(self):
315
Make sure that invoking ZipArchive's repr prints the correct class
316
name and an absolute path to the zip file.
318
pathRepr = 'ZipArchive(%r)' % (os.path.abspath(self.cmn + '.zip'),)
320
# Check for an absolute path
321
self.assertEquals(repr(self.path), pathRepr)
323
# Create a path to the file rooted in the current working directory
324
relativeCommon = self.cmn.replace(os.getcwd() + os.sep, "", 1) + ".zip"
325
relpath = ZipArchive(relativeCommon)
327
# Check using a path without the cwd prepended
328
self.assertEquals(repr(relpath), pathRepr)
332
class FilePathTestCase(AbstractFilePathTestCase):
334
def test_chmod(self):
336
Make sure that calling L{FilePath.chmod} modifies the permissions of
337
the passed file as expected (using C{os.stat} to check). We use some
338
basic modes that should work everywhere (even on Windows).
340
for mode in (0555, 0777):
341
self.path.child("sub1").chmod(mode)
343
stat.S_IMODE(os.stat(self.path.child("sub1").path).st_mode),
347
def symlink(self, target, name):
349
Create a symbolic link named C{name} pointing at C{target}.
353
@raise SkipTest: raised if symbolic links are not supported on the
356
if getattr(os, 'symlink', None) is None:
357
raise unittest.SkipTest(
358
"Platform does not support symbolic links.")
359
os.symlink(target, name)
362
def createLinks(self):
364
Create several symbolic links to files and directories.
366
subdir = self.path.child("sub1")
367
self.symlink(subdir.path, self._mkpath("sub1.link"))
368
self.symlink(subdir.child("file2").path, self._mkpath("file2.link"))
369
self.symlink(subdir.child("file2").path,
370
self._mkpath("sub1", "sub1.file2.link"))
373
def test_realpathSymlink(self):
375
L{FilePath.realpath} returns the path of the ultimate target of a
379
self.symlink(self.path.child("file2.link").path,
380
self.path.child("link.link").path)
381
self.assertEquals(self.path.child("link.link").realpath(),
382
self.path.child("sub1").child("file2"))
385
def test_realpathCyclicalSymlink(self):
387
L{FilePath.realpath} raises L{filepath.LinkError} if the path is a
388
symbolic link which is part of a cycle.
390
self.symlink(self.path.child("link1").path, self.path.child("link2").path)
391
self.symlink(self.path.child("link2").path, self.path.child("link1").path)
392
self.assertRaises(filepath.LinkError,
393
self.path.child("link2").realpath)
396
def test_realpathNoSymlink(self):
398
L{FilePath.realpath} returns the path itself if the path is not a
401
self.assertEquals(self.path.child("sub1").realpath(),
402
self.path.child("sub1"))
405
def test_walkCyclicalSymlink(self):
407
Verify that walking a path with a cyclical symlink raises an error
410
self.symlink(self.path.child("sub1").path,
411
self.path.child("sub1").child("sub1.loopylink").path)
412
def iterateOverPath():
413
return [foo.path for foo in self.path.walk()]
414
self.assertRaises(filepath.LinkError, iterateOverPath)
417
def test_walkObeysDescendWithCyclicalSymlinks(self):
419
Verify that, after making a path with cyclical symlinks, when the
420
supplied C{descend} predicate returns C{False}, the target is not
421
traversed, as if it was a simple symlink.
424
# we create cyclical symlinks
425
self.symlink(self.path.child("sub1").path,
426
self.path.child("sub1").child("sub1.loopylink").path)
427
def noSymLinks(path):
428
return not path.islink()
429
def iterateOverPath():
430
return [foo.path for foo in self.path.walk(descend=noSymLinks)]
431
self.assertTrue(iterateOverPath())
434
def test_walkObeysDescend(self):
436
Verify that when the supplied C{descend} predicate returns C{False},
437
the target is not traversed.
440
def noSymLinks(path):
441
return not path.islink()
442
x = [foo.path for foo in self.path.walk(descend=noSymLinks)]
443
self.assertEquals(set(x), set(self.all))
446
def test_getAndSet(self):
447
content = 'newcontent'
448
self.path.child('new').setContent(content)
449
newcontent = self.path.child('new').getContent()
450
self.failUnlessEqual(content, newcontent)
452
self.path.child('new').setContent(content, '.tmp')
453
newcontent = self.path.child('new').getContent()
454
self.failUnlessEqual(content, newcontent)
457
def test_symbolicLink(self):
459
Verify the behavior of the C{isLink} method against links and
460
non-links. Also check that the symbolic link shares the directory
461
property with its target.
463
s4 = self.path.child("sub4")
464
s3 = self.path.child("sub3")
465
self.symlink(s3.path, s4.path)
466
self.assertTrue(s4.islink())
467
self.assertFalse(s3.islink())
468
self.assertTrue(s4.isdir())
469
self.assertTrue(s3.isdir())
472
def test_linkTo(self):
474
Verify that symlink creates a valid symlink that is both a link and a
475
file if its target is a file, or a directory if its target is a
479
(self.path.child("sub2"), self.path.child("sub2.link")),
480
(self.path.child("sub2").child("file3.ext1"),
481
self.path.child("file3.ext1.link"))
483
for target, link in targetLinks:
485
self.assertTrue(link.islink(), "This is a link")
486
self.assertEquals(target.isdir(), link.isdir())
487
self.assertEquals(target.isfile(), link.isfile())
490
def test_linkToErrors(self):
492
Verify C{linkTo} fails in the following case:
493
- the target is in a directory that doesn't exist
494
- the target already exists
496
self.assertRaises(OSError, self.path.child("file1").linkTo,
497
self.path.child('nosub').child('file1'))
498
self.assertRaises(OSError, self.path.child("file1").linkTo,
499
self.path.child('sub1').child('file2'))
502
if not getattr(os, "symlink", None):
503
skipMsg = "Your platform does not support symbolic links."
504
test_symbolicLink.skip = skipMsg
505
test_linkTo.skip = skipMsg
506
test_linkToErrors.skip = skipMsg
509
def testMultiExt(self):
510
f3 = self.path.child('sub3').child('file3')
511
exts = '.foo','.bar', 'ext1','ext2','ext3'
512
self.failIf(f3.siblingExtensionSearch(*exts))
513
f3e = f3.siblingExtension(".foo")
515
self.failIf(not f3.siblingExtensionSearch(*exts).exists())
516
self.failIf(not f3.siblingExtensionSearch('*').exists())
518
self.failIf(f3.siblingExtensionSearch(*exts))
520
def testPreauthChild(self):
521
fp = filepath.FilePath('.')
522
fp.preauthChild('foo/bar')
523
self.assertRaises(filepath.InsecurePath, fp.child, '/foo')
525
def testStatCache(self):
526
p = self.path.child('stattest')
528
self.failUnlessEqual(p.getsize(), 0)
529
self.failUnlessEqual(abs(p.getmtime() - time.time()) // 20, 0)
530
self.failUnlessEqual(abs(p.getctime() - time.time()) // 20, 0)
531
self.failUnlessEqual(abs(p.getatime() - time.time()) // 20, 0)
532
self.failUnlessEqual(p.exists(), True)
533
self.failUnlessEqual(p.exists(), True)
534
# OOB removal: FilePath.remove() will automatically restat
537
self.failUnlessEqual(p.exists(), True)
538
p.restat(reraise=False)
539
self.failUnlessEqual(p.exists(), False)
540
self.failUnlessEqual(p.islink(), False)
541
self.failUnlessEqual(p.isdir(), False)
542
self.failUnlessEqual(p.isfile(), False)
544
def testPersist(self):
545
newpath = pickle.loads(pickle.dumps(self.path))
546
self.failUnlessEqual(self.path.__class__, newpath.__class__)
547
self.failUnlessEqual(self.path.path, newpath.path)
549
def testInsecureUNIX(self):
550
self.assertRaises(filepath.InsecurePath, self.path.child, "..")
551
self.assertRaises(filepath.InsecurePath, self.path.child, "/etc")
552
self.assertRaises(filepath.InsecurePath, self.path.child, "../..")
554
def testInsecureWin32(self):
555
self.assertRaises(filepath.InsecurePath, self.path.child, r"..\..")
556
self.assertRaises(filepath.InsecurePath, self.path.child, r"C:randomfile")
558
if platform.getType() != 'win32':
559
testInsecureWin32.skip = "Consider yourself lucky."
561
def testInsecureWin32Whacky(self):
562
"""Windows has 'special' filenames like NUL and CON and COM1 and LPR
563
and PRN and ... god knows what else. They can be located anywhere in
564
the filesystem. For obvious reasons, we do not wish to normally permit
567
self.assertRaises(filepath.InsecurePath, self.path.child, "CON")
568
self.assertRaises(filepath.InsecurePath, self.path.child, "C:CON")
569
self.assertRaises(filepath.InsecurePath, self.path.child, r"C:\CON")
571
if platform.getType() != 'win32':
572
testInsecureWin32Whacky.skip = "Consider yourself lucky."
574
def testComparison(self):
575
self.assertEquals(filepath.FilePath('a'),
576
filepath.FilePath('a'))
577
self.failUnless(filepath.FilePath('z') >
578
filepath.FilePath('a'))
579
self.failUnless(filepath.FilePath('z') >=
580
filepath.FilePath('a'))
581
self.failUnless(filepath.FilePath('a') >=
582
filepath.FilePath('a'))
583
self.failUnless(filepath.FilePath('a') <=
584
filepath.FilePath('a'))
585
self.failUnless(filepath.FilePath('a') <
586
filepath.FilePath('z'))
587
self.failUnless(filepath.FilePath('a') <=
588
filepath.FilePath('z'))
589
self.failUnless(filepath.FilePath('a') !=
590
filepath.FilePath('z'))
591
self.failUnless(filepath.FilePath('z') !=
592
filepath.FilePath('a'))
594
self.failIf(filepath.FilePath('z') !=
595
filepath.FilePath('z'))
597
def testSibling(self):
598
p = self.path.child('sibling_start')
599
ts = p.sibling('sibling_test')
600
self.assertEquals(ts.dirname(), p.dirname())
601
self.assertEquals(ts.basename(), 'sibling_test')
603
self.assertIn(ts, self.path.children())
605
def testTemporarySibling(self):
606
ts = self.path.temporarySibling()
607
self.assertEquals(ts.dirname(), self.path.dirname())
608
self.assertNotIn(ts.basename(), self.path.listdir())
610
self.assertIn(ts, self.path.parent().children())
612
def testRemove(self):
614
self.failIf(self.path.exists())
617
def test_removeWithSymlink(self):
619
For a path which is a symbolic link, L{FilePath.remove} just deletes
620
the link, not the target.
622
link = self.path.child("sub1.link")
623
# setUp creates the sub1 child
624
self.symlink(self.path.child("sub1").path, link.path)
626
self.assertFalse(link.exists())
627
self.assertTrue(self.path.child("sub1").exists())
630
def test_copyTo(self):
631
self.assertRaises((OSError, IOError), self.path.copyTo, self.path.child('file1'))
632
oldPaths = list(self.path.walk()) # Record initial state
633
fp = filepath.FilePath(self.mktemp())
637
newPaths = list(self.path.walk()) # Record double-copy state
640
self.assertEquals(newPaths, oldPaths)
643
def test_copyToWithSymlink(self):
645
Verify that copying with followLinks=True copies symlink targets
648
self.symlink(self.path.child("sub1").path,
649
self.path.child("link1").path)
650
fp = filepath.FilePath(self.mktemp())
652
self.assertFalse(fp.child("link1").islink())
653
self.assertEquals([x.basename() for x in fp.child("sub1").children()],
654
[x.basename() for x in fp.child("link1").children()])
657
def test_copyToWithoutSymlink(self):
659
Verify that copying with followLinks=False copies symlinks as symlinks
661
self.symlink("sub1", self.path.child("link1").path)
662
fp = filepath.FilePath(self.mktemp())
663
self.path.copyTo(fp, followLinks=False)
664
self.assertTrue(fp.child("link1").islink())
665
self.assertEquals(os.readlink(self.path.child("link1").path),
666
os.readlink(fp.child("link1").path))
669
def test_moveTo(self):
671
Verify that moving an entire directory results into another directory
672
with the same content.
674
oldPaths = list(self.path.walk()) # Record initial state
675
fp = filepath.FilePath(self.mktemp())
678
newPaths = list(self.path.walk()) # Record double-move state
681
self.assertEquals(newPaths, oldPaths)
684
def test_moveToError(self):
686
Verify error behavior of moveTo: it should raises one of OSError or
687
IOError if you want to move a path into one of its child. It's simply
688
the error raised by the underlying rename system call.
690
self.assertRaises((OSError, IOError), self.path.moveTo, self.path.child('file1'))
693
def setUpFaultyRename(self):
695
Set up a C{os.rename} that will fail with L{errno.EXDEV} on first call.
696
This is used to simulate a cross-device rename failure.
698
@return: a list of pair (src, dest) of calls to C{os.rename}
699
@rtype: C{list} of C{tuple}
702
def faultyRename(src, dest):
703
invokedWith.append((src, dest))
704
if len(invokedWith) == 1:
705
raise OSError(errno.EXDEV, 'Test-induced failure simulating '
706
'cross-device rename failure')
707
return originalRename(src, dest)
709
originalRename = os.rename
710
self.patch(os, "rename", faultyRename)
714
def test_crossMountMoveTo(self):
716
C{moveTo} should be able to handle C{EXDEV} error raised by
717
C{os.rename} when trying to move a file on a different mounted
720
invokedWith = self.setUpFaultyRename()
721
# Bit of a whitebox test - force os.rename, which moveTo tries
722
# before falling back to a slower method, to fail, forcing moveTo to
723
# use the slower behavior.
725
# A bit of a sanity check for this whitebox test - if our rename
726
# was never invoked, the test has probably fallen into disrepair!
727
self.assertTrue(invokedWith)
730
def test_crossMountMoveToWithSymlink(self):
732
By default, when moving a symlink, it should follow the link and
733
actually copy the content of the linked node.
735
invokedWith = self.setUpFaultyRename()
736
f2 = self.path.child('file2')
737
f3 = self.path.child('file3')
738
self.symlink(self.path.child('file1').path, f2.path)
740
self.assertFalse(f3.islink())
741
self.assertEquals(f3.getContent(), 'file 1')
742
self.assertTrue(invokedWith)
745
def test_crossMountMoveToWithoutSymlink(self):
747
Verify that moveTo called with followLinks=False actually create
750
invokedWith = self.setUpFaultyRename()
751
f2 = self.path.child('file2')
752
f3 = self.path.child('file3')
753
self.symlink(self.path.child('file1').path, f2.path)
754
f2.moveTo(f3, followLinks=False)
755
self.assertTrue(f3.islink())
756
self.assertEquals(f3.getContent(), 'file 1')
757
self.assertTrue(invokedWith)
761
# Opening a file for reading when it does not already exist is an error
762
nonexistent = self.path.child('nonexistent')
763
e = self.assertRaises(IOError, nonexistent.open)
764
self.assertEquals(e.errno, errno.ENOENT)
766
# Opening a file for writing when it does not exist is okay
767
writer = self.path.child('writer')
772
# Make sure those bytes ended up there - and test opening a file for
773
# reading when it does exist at the same time
775
self.assertEquals(f.read(), 'abc\ndef')
778
# Re-opening that file in write mode should erase whatever was there.
782
self.assertEquals(f.read(), '')
785
# Put some bytes in a file so we can test that appending does not
787
appender = self.path.child('appender')
788
f = appender.open('w')
792
f = appender.open('a')
796
f = appender.open('r')
797
self.assertEquals(f.read(), 'abcdef')
800
# read/write should let us do both without erasing those bytes
801
f = appender.open('r+')
802
self.assertEquals(f.read(), 'abcdef')
803
# ANSI C *requires* an fseek or an fgetpos between an fread and an
804
# fwrite or an fwrite and a fread. We can't reliable get Python to
805
# invoke fgetpos, so we seek to a 0 byte offset from the current
806
# position instead. Also, Python sucks for making this seek
807
# relative to 1 instead of a symbolic constant representing the
808
# current file position.
810
# Put in some new bytes for us to test for later.
814
# Make sure those new bytes really showed up
815
f = appender.open('r')
816
self.assertEquals(f.read(), 'abcdefghi')
819
# write/read should let us do both, but erase anything that's there
821
f = appender.open('w+')
822
self.assertEquals(f.read(), '')
823
f.seek(0, 1) # Don't forget this!
827
# super append mode should let us read and write and also position the
828
# cursor at the end of the file, without erasing everything.
829
f = appender.open('a+')
831
# The order of these lines may seem surprising, but it is necessary.
832
# The cursor is not at the end of the file until after the first write.
834
f.seek(0, 1) # Asinine.
835
self.assertEquals(f.read(), '')
838
self.assertEquals(f.read(), '123456')
841
# Opening a file exclusively must fail if that file exists already.
842
nonexistent.requireCreate(True)
843
nonexistent.open('w').close()
844
existent = nonexistent
846
self.assertRaises((OSError, IOError), existent.open)
849
def test_existsCache(self):
851
Check that C{filepath.FilePath.exists} correctly restat the object if
852
an operation has occurred in the mean time.
854
fp = filepath.FilePath(self.mktemp())
855
self.assertEquals(fp.exists(), False)
858
self.assertEquals(fp.exists(), True)
862
from twisted.python import urlpath
864
class URLPathTestCase(unittest.TestCase):
866
self.path = urlpath.URLPath.fromString("http://example.com/foo/bar?yes=no&no=yes#footer")
868
def testStringConversion(self):
869
self.assertEquals(str(self.path), "http://example.com/foo/bar?yes=no&no=yes#footer")
871
def testChildString(self):
872
self.assertEquals(str(self.path.child('hello')), "http://example.com/foo/bar/hello")
873
self.assertEquals(str(self.path.child('hello').child('')), "http://example.com/foo/bar/hello/")
875
def testSiblingString(self):
876
self.assertEquals(str(self.path.sibling('baz')), 'http://example.com/foo/baz')
878
# The sibling of http://example.com/foo/bar/
879
# is http://example.comf/foo/bar/baz
880
# because really we are constructing a sibling of
881
# http://example.com/foo/bar/index.html
882
self.assertEquals(str(self.path.child('').sibling('baz')), 'http://example.com/foo/bar/baz')
884
def testParentString(self):
885
# parent should be equivalent to '..'
886
# 'foo' is the current directory, '/' is the parent directory
887
self.assertEquals(str(self.path.parent()), 'http://example.com/')
888
self.assertEquals(str(self.path.child('').parent()), 'http://example.com/foo/')
889
self.assertEquals(str(self.path.child('baz').parent()), 'http://example.com/foo/')
890
self.assertEquals(str(self.path.parent().parent().parent().parent().parent()), 'http://example.com/')
892
def testHereString(self):
893
# here should be equivalent to '.'
894
self.assertEquals(str(self.path.here()), 'http://example.com/foo/')
895
self.assertEquals(str(self.path.child('').here()), 'http://example.com/foo/bar/')