| OLD | NEW |
| (Empty) |
| 1 # Copyright (c) 2001-2008 Twisted Matrix Laboratories. | |
| 2 # See LICENSE for details. | |
| 3 | |
| 4 """ | |
| 5 Test cases covering L{twisted.python.filepath} and L{twisted.python.zippath}. | |
| 6 """ | |
| 7 | |
| 8 import os, time, pickle, errno, zipfile, stat | |
| 9 | |
| 10 from twisted.python.win32 import WindowsError, ERROR_DIRECTORY | |
| 11 from twisted.python import filepath | |
| 12 from twisted.python.zippath import ZipArchive | |
| 13 from twisted.python.runtime import platform | |
| 14 | |
| 15 from twisted.trial import unittest | |
| 16 | |
| 17 | |
| 18 class AbstractFilePathTestCase(unittest.TestCase): | |
| 19 | |
| 20 f1content = "file 1" | |
| 21 f2content = "file 2" | |
| 22 | |
| 23 def _mkpath(self, *p): | |
| 24 x = os.path.abspath(os.path.join(self.cmn, *p)) | |
| 25 self.all.append(x) | |
| 26 return x | |
| 27 | |
| 28 def subdir(self, *dirname): | |
| 29 os.mkdir(self._mkpath(*dirname)) | |
| 30 | |
| 31 def subfile(self, *dirname): | |
| 32 return open(self._mkpath(*dirname), "wb") | |
| 33 | |
| 34 def setUp(self): | |
| 35 self.now = time.time() | |
| 36 cmn = self.cmn = os.path.abspath(self.mktemp()) | |
| 37 self.all = [cmn] | |
| 38 os.mkdir(cmn) | |
| 39 self.subdir("sub1") | |
| 40 f = self.subfile("file1") | |
| 41 f.write(self.f1content) | |
| 42 f = self.subfile("sub1", "file2") | |
| 43 f.write(self.f2content) | |
| 44 self.subdir('sub3') | |
| 45 f = self.subfile("sub3", "file3.ext1") | |
| 46 f = self.subfile("sub3", "file3.ext2") | |
| 47 f = self.subfile("sub3", "file3.ext3") | |
| 48 self.all.sort() | |
| 49 | |
| 50 self.path = filepath.FilePath(cmn) | |
| 51 | |
| 52 def test_segmentsFromPositive(self): | |
| 53 """ | |
| 54 Verify that the segments between two paths are correctly identified. | |
| 55 """ | |
| 56 self.assertEquals( | |
| 57 self.path.child("a").child("b").child("c").segmentsFrom(self.path), | |
| 58 ["a", "b", "c"]) | |
| 59 | |
| 60 def test_segmentsFromNegative(self): | |
| 61 """Verify that segmentsFrom notices when the ancestor isn't an ancestor. | |
| 62 """ | |
| 63 self.assertRaises( | |
| 64 ValueError, | |
| 65 self.path.child("a").child("b").child("c").segmentsFrom, | |
| 66 self.path.child("d").child("c").child("e")) | |
| 67 | |
| 68 def test_walk(self): | |
| 69 """Verify that walking the path gives the same result as the known file | |
| 70 hierarchy. | |
| 71 """ | |
| 72 x = [foo.path for foo in self.path.walk()] | |
| 73 x.sort() | |
| 74 self.assertEquals(x, self.all) | |
| 75 | |
| 76 def test_validSubdir(self): | |
| 77 """Verify that a valid subdirectory will show up as a directory, but not
as a | |
| 78 file, not as a symlink, and be listable. | |
| 79 """ | |
| 80 sub1 = self.path.child('sub1') | |
| 81 self.failUnless(sub1.exists(), | |
| 82 "This directory does exist.") | |
| 83 self.failUnless(sub1.isdir(), | |
| 84 "It's a directory.") | |
| 85 self.failUnless(not sub1.isfile(), | |
| 86 "It's a directory.") | |
| 87 self.failUnless(not sub1.islink(), | |
| 88 "It's a directory.") | |
| 89 self.failUnlessEqual(sub1.listdir(), | |
| 90 ['file2']) | |
| 91 | |
| 92 | |
| 93 def test_invalidSubdir(self): | |
| 94 """ | |
| 95 Verify that a subdirectory that doesn't exist is reported as such. | |
| 96 """ | |
| 97 sub2 = self.path.child('sub2') | |
| 98 self.failIf(sub2.exists(), | |
| 99 "This directory does not exist.") | |
| 100 | |
| 101 def test_validFiles(self): | |
| 102 """ | |
| 103 Make sure that we can read existent non-empty files. | |
| 104 """ | |
| 105 f1 = self.path.child('file1') | |
| 106 self.failUnlessEqual(f1.open().read(), self.f1content) | |
| 107 f2 = self.path.child('sub1').child('file2') | |
| 108 self.failUnlessEqual(f2.open().read(), self.f2content) | |
| 109 | |
| 110 | |
| 111 def test_dictionaryKeys(self): | |
| 112 """ | |
| 113 Verify that path instances are usable as dictionary keys. | |
| 114 """ | |
| 115 f1 = self.path.child('file1') | |
| 116 f1prime = self.path.child('file1') | |
| 117 f2 = self.path.child('file2') | |
| 118 dictoid = {} | |
| 119 dictoid[f1] = 3 | |
| 120 dictoid[f1prime] = 4 | |
| 121 self.assertEquals(dictoid[f1], 4) | |
| 122 self.assertEquals(dictoid.keys(), [f1]) | |
| 123 self.assertIdentical(dictoid.keys()[0], f1) | |
| 124 self.assertNotIdentical(dictoid.keys()[0], f1prime) # sanity check | |
| 125 dictoid[f2] = 5 | |
| 126 self.assertEquals(dictoid[f2], 5) | |
| 127 self.assertEquals(len(dictoid), 2) | |
| 128 | |
| 129 | |
| 130 def test_dictionaryKeyWithString(self): | |
| 131 """ | |
| 132 Verify that path instances are usable as dictionary keys which do not cl
ash | |
| 133 with their string counterparts. | |
| 134 """ | |
| 135 f1 = self.path.child('file1') | |
| 136 dictoid = {f1: 'hello'} | |
| 137 dictoid[f1.path] = 'goodbye' | |
| 138 self.assertEquals(len(dictoid), 2) | |
| 139 | |
| 140 | |
| 141 def test_childrenNonexistentError(self): | |
| 142 """ | |
| 143 Verify that children raises the appropriate exception for non-existent | |
| 144 directories. | |
| 145 """ | |
| 146 self.assertRaises(filepath.UnlistableError, | |
| 147 self.path.child('not real').children) | |
| 148 | |
| 149 def test_childrenNotDirectoryError(self): | |
| 150 """ | |
| 151 Verify that listdir raises the appropriate exception for attempting to l
ist | |
| 152 a file rather than a directory. | |
| 153 """ | |
| 154 self.assertRaises(filepath.UnlistableError, | |
| 155 self.path.child('file1').children) | |
| 156 | |
| 157 | |
| 158 def test_newTimesAreFloats(self): | |
| 159 """ | |
| 160 Verify that all times returned from the various new time functions are i
nts | |
| 161 (and hopefully therefore 'high precision'). | |
| 162 """ | |
| 163 for p in self.path, self.path.child('file1'): | |
| 164 self.failUnlessEqual(type(p.getAccessTime()), float) | |
| 165 self.failUnlessEqual(type(p.getModificationTime()), float) | |
| 166 self.failUnlessEqual(type(p.getStatusChangeTime()), float) | |
| 167 | |
| 168 | |
| 169 def test_oldTimesAreInts(self): | |
| 170 """ | |
| 171 Verify that all times returned from the various time functions are | |
| 172 integers, for compatibility. | |
| 173 """ | |
| 174 for p in self.path, self.path.child('file1'): | |
| 175 self.failUnlessEqual(type(p.getatime()), int) | |
| 176 self.failUnlessEqual(type(p.getmtime()), int) | |
| 177 self.failUnlessEqual(type(p.getctime()), int) | |
| 178 | |
| 179 | |
| 180 | |
| 181 class FakeWindowsPath(filepath.FilePath): | |
| 182 """ | |
| 183 A test version of FilePath which overrides listdir to raise L{WindowsError}. | |
| 184 """ | |
| 185 | |
| 186 def listdir(self): | |
| 187 """ | |
| 188 @raise WindowsError: always. | |
| 189 """ | |
| 190 raise WindowsError( | |
| 191 ERROR_DIRECTORY, | |
| 192 "A directory's validness was called into question") | |
| 193 | |
| 194 | |
| 195 class ListingCompatibilityTests(unittest.TestCase): | |
| 196 """ | |
| 197 These tests verify compatibility with legacy behavior of directory listing. | |
| 198 """ | |
| 199 | |
| 200 def test_windowsErrorExcept(self): | |
| 201 """ | |
| 202 Verify that when a WindowsError is raised from listdir, catching | |
| 203 WindowsError works. | |
| 204 """ | |
| 205 fwp = FakeWindowsPath(self.mktemp()) | |
| 206 self.assertRaises(filepath.UnlistableError, fwp.children) | |
| 207 self.assertRaises(WindowsError, fwp.children) | |
| 208 | |
| 209 | |
| 210 def test_alwaysCatchOSError(self): | |
| 211 """ | |
| 212 Verify that in the normal case where a directory does not exist, we will | |
| 213 get an OSError. | |
| 214 """ | |
| 215 fp = filepath.FilePath(self.mktemp()) | |
| 216 self.assertRaises(OSError, fp.children) | |
| 217 | |
| 218 | |
| 219 def test_keepOriginalAttributes(self): | |
| 220 """ | |
| 221 Verify that the Unlistable exception raised will preserve the attributes
of | |
| 222 the previously-raised exception. | |
| 223 """ | |
| 224 fp = filepath.FilePath(self.mktemp()) | |
| 225 ose = self.assertRaises(OSError, fp.children) | |
| 226 d1 = ose.__dict__.keys() | |
| 227 d1.remove('originalException') | |
| 228 d2 = ose.originalException.__dict__.keys() | |
| 229 d1.sort() | |
| 230 d2.sort() | |
| 231 self.assertEquals(d1, d2) | |
| 232 | |
| 233 | |
| 234 | |
| 235 def zipit(dirname, zfname): | |
| 236 """ | |
| 237 create a zipfile on zfname, containing the contents of dirname' | |
| 238 """ | |
| 239 zf = zipfile.ZipFile(zfname, "w") | |
| 240 basedir = os.path.basename(dirname) | |
| 241 for root, dirs, files, in os.walk(dirname): | |
| 242 for fname in files: | |
| 243 fspath = os.path.join(root, fname) | |
| 244 arcpath = os.path.join(root, fname)[len(dirname)+1:] | |
| 245 # print fspath, '=>', arcpath | |
| 246 zf.write(fspath, arcpath) | |
| 247 zf.close() | |
| 248 | |
| 249 class ZipFilePathTestCase(AbstractFilePathTestCase): | |
| 250 | |
| 251 def setUp(self): | |
| 252 AbstractFilePathTestCase.setUp(self) | |
| 253 zipit(self.cmn, self.cmn+'.zip') | |
| 254 self.path = ZipArchive(self.cmn+'.zip') | |
| 255 self.all = [x.replace(self.cmn, self.cmn+'.zip') for x in self.all] | |
| 256 | |
| 257 | |
| 258 class FilePathTestCase(AbstractFilePathTestCase): | |
| 259 | |
| 260 def test_chmod(self): | |
| 261 """ | |
| 262 Make sure that calling L{FilePath.chmod} modifies the permissions of | |
| 263 the passed file as expected (using C{os.stat} to check). We use some | |
| 264 basic modes that should work everywhere (even on Windows). | |
| 265 """ | |
| 266 for mode in (0555, 0777): | |
| 267 self.path.child("sub1").chmod(mode) | |
| 268 self.assertEquals( | |
| 269 stat.S_IMODE(os.stat(self.path.child("sub1").path).st_mode), | |
| 270 mode) | |
| 271 | |
| 272 | |
| 273 def test_getAndSet(self): | |
| 274 content = 'newcontent' | |
| 275 self.path.child('new').setContent(content) | |
| 276 newcontent = self.path.child('new').getContent() | |
| 277 self.failUnlessEqual(content, newcontent) | |
| 278 content = 'content' | |
| 279 self.path.child('new').setContent(content, '.tmp') | |
| 280 newcontent = self.path.child('new').getContent() | |
| 281 self.failUnlessEqual(content, newcontent) | |
| 282 | |
| 283 | |
| 284 def test_symbolicLink(self): | |
| 285 """ | |
| 286 Verify the behavior of the C{isLink} method against links and | |
| 287 non-links. Also check that the symbolic link shares the directory | |
| 288 property with its target. | |
| 289 """ | |
| 290 s4 = self.path.child("sub4") | |
| 291 s3 = self.path.child("sub3") | |
| 292 os.symlink(s3.path, s4.path) | |
| 293 self.assertTrue(s4.islink()) | |
| 294 self.assertFalse(s3.islink()) | |
| 295 self.assertTrue(s4.isdir()) | |
| 296 self.assertTrue(s3.isdir()) | |
| 297 | |
| 298 | |
| 299 def test_linkTo(self): | |
| 300 """ | |
| 301 Verify that symlink creates a valid symlink that is both a link and a | |
| 302 file if its target is a file, or a directory if its target is a | |
| 303 directory. | |
| 304 """ | |
| 305 targetLinks = [ | |
| 306 (self.path.child("sub2"), self.path.child("sub2.link")), | |
| 307 (self.path.child("sub2").child("file3.ext1"), | |
| 308 self.path.child("file3.ext1.link")) | |
| 309 ] | |
| 310 for target, link in targetLinks: | |
| 311 target.linkTo(link) | |
| 312 self.assertTrue(link.islink(), "This is a link") | |
| 313 self.assertEquals(target.isdir(), link.isdir()) | |
| 314 self.assertEquals(target.isfile(), link.isfile()) | |
| 315 | |
| 316 | |
| 317 def test_linkToErrors(self): | |
| 318 """ | |
| 319 Verify C{linkTo} fails in the following case: | |
| 320 - the target is in a directory that doesn't exist | |
| 321 - the target already exists | |
| 322 """ | |
| 323 self.assertRaises(OSError, self.path.child("file1").linkTo, | |
| 324 self.path.child('nosub').child('file1')) | |
| 325 self.assertRaises(OSError, self.path.child("file1").linkTo, | |
| 326 self.path.child('sub1').child('file2')) | |
| 327 | |
| 328 | |
| 329 if not getattr(os, "symlink", None): | |
| 330 skipMsg = "Your platform does not support symbolic links." | |
| 331 test_symbolicLink.skip = skipMsg | |
| 332 test_linkTo.skip = skipMsg | |
| 333 test_linkToErrors.skip = skipMsg | |
| 334 | |
| 335 | |
| 336 def testMultiExt(self): | |
| 337 f3 = self.path.child('sub3').child('file3') | |
| 338 exts = '.foo','.bar', 'ext1','ext2','ext3' | |
| 339 self.failIf(f3.siblingExtensionSearch(*exts)) | |
| 340 f3e = f3.siblingExtension(".foo") | |
| 341 f3e.touch() | |
| 342 self.failIf(not f3.siblingExtensionSearch(*exts).exists()) | |
| 343 self.failIf(not f3.siblingExtensionSearch('*').exists()) | |
| 344 f3e.remove() | |
| 345 self.failIf(f3.siblingExtensionSearch(*exts)) | |
| 346 | |
| 347 def testPreauthChild(self): | |
| 348 fp = filepath.FilePath('.') | |
| 349 fp.preauthChild('foo/bar') | |
| 350 self.assertRaises(filepath.InsecurePath, fp.child, '/foo') | |
| 351 | |
| 352 def testStatCache(self): | |
| 353 p = self.path.child('stattest') | |
| 354 p.touch() | |
| 355 self.failUnlessEqual(p.getsize(), 0) | |
| 356 self.failUnlessEqual(abs(p.getmtime() - time.time()) // 20, 0) | |
| 357 self.failUnlessEqual(abs(p.getctime() - time.time()) // 20, 0) | |
| 358 self.failUnlessEqual(abs(p.getatime() - time.time()) // 20, 0) | |
| 359 self.failUnlessEqual(p.exists(), True) | |
| 360 self.failUnlessEqual(p.exists(), True) | |
| 361 # OOB removal: FilePath.remove() will automatically restat | |
| 362 os.remove(p.path) | |
| 363 # test caching | |
| 364 self.failUnlessEqual(p.exists(), True) | |
| 365 p.restat(reraise=False) | |
| 366 self.failUnlessEqual(p.exists(), False) | |
| 367 self.failUnlessEqual(p.islink(), False) | |
| 368 self.failUnlessEqual(p.isdir(), False) | |
| 369 self.failUnlessEqual(p.isfile(), False) | |
| 370 | |
| 371 def testPersist(self): | |
| 372 newpath = pickle.loads(pickle.dumps(self.path)) | |
| 373 self.failUnlessEqual(self.path.__class__, newpath.__class__) | |
| 374 self.failUnlessEqual(self.path.path, newpath.path) | |
| 375 | |
| 376 def testInsecureUNIX(self): | |
| 377 self.assertRaises(filepath.InsecurePath, self.path.child, "..") | |
| 378 self.assertRaises(filepath.InsecurePath, self.path.child, "/etc") | |
| 379 self.assertRaises(filepath.InsecurePath, self.path.child, "../..") | |
| 380 | |
| 381 def testInsecureWin32(self): | |
| 382 self.assertRaises(filepath.InsecurePath, self.path.child, r"..\..") | |
| 383 self.assertRaises(filepath.InsecurePath, self.path.child, r"C:randomfile
") | |
| 384 | |
| 385 if platform.getType() != 'win32': | |
| 386 testInsecureWin32.skip = "Consider yourself lucky." | |
| 387 | |
| 388 def testInsecureWin32Whacky(self): | |
| 389 """Windows has 'special' filenames like NUL and CON and COM1 and LPR | |
| 390 and PRN and ... god knows what else. They can be located anywhere in | |
| 391 the filesystem. For obvious reasons, we do not wish to normally permit | |
| 392 access to these. | |
| 393 """ | |
| 394 self.assertRaises(filepath.InsecurePath, self.path.child, "CON") | |
| 395 self.assertRaises(filepath.InsecurePath, self.path.child, "C:CON") | |
| 396 self.assertRaises(filepath.InsecurePath, self.path.child, r"C:\CON") | |
| 397 | |
| 398 if platform.getType() != 'win32': | |
| 399 testInsecureWin32Whacky.skip = "Consider yourself lucky." | |
| 400 | |
| 401 def testComparison(self): | |
| 402 self.assertEquals(filepath.FilePath('a'), | |
| 403 filepath.FilePath('a')) | |
| 404 self.failUnless(filepath.FilePath('z') > | |
| 405 filepath.FilePath('a')) | |
| 406 self.failUnless(filepath.FilePath('z') >= | |
| 407 filepath.FilePath('a')) | |
| 408 self.failUnless(filepath.FilePath('a') >= | |
| 409 filepath.FilePath('a')) | |
| 410 self.failUnless(filepath.FilePath('a') <= | |
| 411 filepath.FilePath('a')) | |
| 412 self.failUnless(filepath.FilePath('a') < | |
| 413 filepath.FilePath('z')) | |
| 414 self.failUnless(filepath.FilePath('a') <= | |
| 415 filepath.FilePath('z')) | |
| 416 self.failUnless(filepath.FilePath('a') != | |
| 417 filepath.FilePath('z')) | |
| 418 self.failUnless(filepath.FilePath('z') != | |
| 419 filepath.FilePath('a')) | |
| 420 | |
| 421 self.failIf(filepath.FilePath('z') != | |
| 422 filepath.FilePath('z')) | |
| 423 | |
| 424 def testSibling(self): | |
| 425 p = self.path.child('sibling_start') | |
| 426 ts = p.sibling('sibling_test') | |
| 427 self.assertEquals(ts.dirname(), p.dirname()) | |
| 428 self.assertEquals(ts.basename(), 'sibling_test') | |
| 429 ts.createDirectory() | |
| 430 self.assertIn(ts, self.path.children()) | |
| 431 | |
| 432 def testTemporarySibling(self): | |
| 433 ts = self.path.temporarySibling() | |
| 434 self.assertEquals(ts.dirname(), self.path.dirname()) | |
| 435 self.assertNotIn(ts.basename(), self.path.listdir()) | |
| 436 ts.createDirectory() | |
| 437 self.assertIn(ts, self.path.parent().children()) | |
| 438 | |
| 439 def testRemove(self): | |
| 440 self.path.remove() | |
| 441 self.failIf(self.path.exists()) | |
| 442 | |
| 443 | |
| 444 def test_removeWithSymlink(self): | |
| 445 """ | |
| 446 For a path which is a symbolic link, L{FilePath.remove} just deletes | |
| 447 the link, not the target. | |
| 448 """ | |
| 449 link = self.path.child("sub1.link") | |
| 450 # setUp creates the sub1 child | |
| 451 os.symlink(self.path.child("sub1").path, link.path) | |
| 452 link.remove() | |
| 453 self.assertFalse(link.exists()) | |
| 454 self.assertTrue(self.path.child("sub1").exists()) | |
| 455 | |
| 456 if getattr(os, 'symlink', None) is None: | |
| 457 test_removeWithSymlink.skip = "Platform doesn't support symbolic links" | |
| 458 | |
| 459 | |
| 460 def testCopyTo(self): | |
| 461 self.assertRaises((OSError, IOError), self.path.copyTo, self.path.child(
'file1')) | |
| 462 oldPaths = list(self.path.walk()) # Record initial state | |
| 463 fp = filepath.FilePath(self.mktemp()) | |
| 464 self.path.copyTo(fp) | |
| 465 self.path.remove() | |
| 466 fp.copyTo(self.path) | |
| 467 newPaths = list(self.path.walk()) # Record double-copy state | |
| 468 newPaths.sort() | |
| 469 oldPaths.sort() | |
| 470 self.assertEquals(newPaths, oldPaths) | |
| 471 | |
| 472 def testMoveTo(self): | |
| 473 self.assertRaises((OSError, IOError), self.path.moveTo, self.path.child(
'file1')) | |
| 474 oldPaths = list(self.path.walk()) # Record initial state | |
| 475 fp = filepath.FilePath(self.mktemp()) | |
| 476 self.path.moveTo(fp) | |
| 477 fp.moveTo(self.path) | |
| 478 newPaths = list(self.path.walk()) # Record double-move state | |
| 479 newPaths.sort() | |
| 480 oldPaths.sort() | |
| 481 self.assertEquals(newPaths, oldPaths) | |
| 482 | |
| 483 | |
| 484 def test_crossMountMoveTo(self): | |
| 485 """ | |
| 486 C{moveTo} should be able to handle C{EXDEV} error raised by | |
| 487 C{os.rename} when trying to move a file on a different mounted | |
| 488 filesystem. | |
| 489 """ | |
| 490 # Bit of a whitebox test - force os.rename, which moveTo tries | |
| 491 # before falling back to a slower method, to fail, forcing moveTo to | |
| 492 # use the slower behavior. | |
| 493 invokedWith = [] | |
| 494 def faultyRename(src, dest): | |
| 495 invokedWith.append((src, dest)) | |
| 496 if len(invokedWith) == 2: | |
| 497 raise OSError(errno.EXDEV, 'Test-induced failure simulating cros
s-device rename failure') | |
| 498 return originalRename(src, dest) | |
| 499 | |
| 500 originalRename = os.rename | |
| 501 os.rename = faultyRename | |
| 502 try: | |
| 503 self.testMoveTo() | |
| 504 # A bit of a sanity check for this whitebox test - if our rename | |
| 505 # was never invoked, the test has probably fallen into | |
| 506 # disrepair! | |
| 507 self.failUnless(len(invokedWith) >= 2) | |
| 508 finally: | |
| 509 os.rename = originalRename | |
| 510 | |
| 511 | |
| 512 def testOpen(self): | |
| 513 # Opening a file for reading when it does not already exist is an error | |
| 514 nonexistent = self.path.child('nonexistent') | |
| 515 e = self.assertRaises(IOError, nonexistent.open) | |
| 516 self.assertEquals(e.errno, errno.ENOENT) | |
| 517 | |
| 518 # Opening a file for writing when it does not exist is okay | |
| 519 writer = self.path.child('writer') | |
| 520 f = writer.open('w') | |
| 521 f.write('abc\ndef') | |
| 522 f.close() | |
| 523 | |
| 524 # Make sure those bytes ended up there - and test opening a file for | |
| 525 # reading when it does exist at the same time | |
| 526 f = writer.open() | |
| 527 self.assertEquals(f.read(), 'abc\ndef') | |
| 528 f.close() | |
| 529 | |
| 530 # Re-opening that file in write mode should erase whatever was there. | |
| 531 f = writer.open('w') | |
| 532 f.close() | |
| 533 f = writer.open() | |
| 534 self.assertEquals(f.read(), '') | |
| 535 f.close() | |
| 536 | |
| 537 # Put some bytes in a file so we can test that appending does not | |
| 538 # destroy them. | |
| 539 appender = self.path.child('appender') | |
| 540 f = appender.open('w') | |
| 541 f.write('abc') | |
| 542 f.close() | |
| 543 | |
| 544 f = appender.open('a') | |
| 545 f.write('def') | |
| 546 f.close() | |
| 547 | |
| 548 f = appender.open('r') | |
| 549 self.assertEquals(f.read(), 'abcdef') | |
| 550 f.close() | |
| 551 | |
| 552 # read/write should let us do both without erasing those bytes | |
| 553 f = appender.open('r+') | |
| 554 self.assertEquals(f.read(), 'abcdef') | |
| 555 # ANSI C *requires* an fseek or an fgetpos between an fread and an | |
| 556 # fwrite or an fwrite and a fread. We can't reliable get Python to | |
| 557 # invoke fgetpos, so we seek to a 0 byte offset from the current | |
| 558 # position instead. Also, Python sucks for making this seek | |
| 559 # relative to 1 instead of a symbolic constant representing the | |
| 560 # current file position. | |
| 561 f.seek(0, 1) | |
| 562 # Put in some new bytes for us to test for later. | |
| 563 f.write('ghi') | |
| 564 f.close() | |
| 565 | |
| 566 # Make sure those new bytes really showed up | |
| 567 f = appender.open('r') | |
| 568 self.assertEquals(f.read(), 'abcdefghi') | |
| 569 f.close() | |
| 570 | |
| 571 # write/read should let us do both, but erase anything that's there | |
| 572 # already. | |
| 573 f = appender.open('w+') | |
| 574 self.assertEquals(f.read(), '') | |
| 575 f.seek(0, 1) # Don't forget this! | |
| 576 f.write('123') | |
| 577 f.close() | |
| 578 | |
| 579 # super append mode should let us read and write and also position the | |
| 580 # cursor at the end of the file, without erasing everything. | |
| 581 f = appender.open('a+') | |
| 582 | |
| 583 # The order of these lines may seem surprising, but it is necessary. | |
| 584 # The cursor is not at the end of the file until after the first write. | |
| 585 f.write('456') | |
| 586 f.seek(0, 1) # Asinine. | |
| 587 self.assertEquals(f.read(), '') | |
| 588 | |
| 589 f.seek(0, 0) | |
| 590 self.assertEquals(f.read(), '123456') | |
| 591 f.close() | |
| 592 | |
| 593 # Opening a file exclusively must fail if that file exists already. | |
| 594 nonexistent.requireCreate(True) | |
| 595 nonexistent.open('w').close() | |
| 596 existent = nonexistent | |
| 597 del nonexistent | |
| 598 self.assertRaises((OSError, IOError), existent.open) | |
| 599 | |
| 600 | |
| 601 def test_existsCache(self): | |
| 602 """ | |
| 603 Check that C{filepath.FilePath.exists} correctly restat the object if | |
| 604 an operation has occurred in the mean time. | |
| 605 """ | |
| 606 fp = filepath.FilePath(self.mktemp()) | |
| 607 self.assertEquals(fp.exists(), False) | |
| 608 | |
| 609 fp.makedirs() | |
| 610 self.assertEquals(fp.exists(), True) | |
| 611 | |
| 612 | |
| 613 | |
| 614 from twisted.python import urlpath | |
| 615 | |
| 616 class URLPathTestCase(unittest.TestCase): | |
| 617 def setUp(self): | |
| 618 self.path = urlpath.URLPath.fromString("http://example.com/foo/bar?yes=n
o&no=yes#footer") | |
| 619 | |
| 620 def testStringConversion(self): | |
| 621 self.assertEquals(str(self.path), "http://example.com/foo/bar?yes=no&no=
yes#footer") | |
| 622 | |
| 623 def testChildString(self): | |
| 624 self.assertEquals(str(self.path.child('hello')), "http://example.com/foo
/bar/hello") | |
| 625 self.assertEquals(str(self.path.child('hello').child('')), "http://examp
le.com/foo/bar/hello/") | |
| 626 | |
| 627 def testSiblingString(self): | |
| 628 self.assertEquals(str(self.path.sibling('baz')), 'http://example.com/foo
/baz') | |
| 629 | |
| 630 # The sibling of http://example.com/foo/bar/ | |
| 631 # is http://example.comf/foo/bar/baz | |
| 632 # because really we are constructing a sibling of | |
| 633 # http://example.com/foo/bar/index.html | |
| 634 self.assertEquals(str(self.path.child('').sibling('baz')), 'http://examp
le.com/foo/bar/baz') | |
| 635 | |
| 636 def testParentString(self): | |
| 637 # parent should be equivalent to '..' | |
| 638 # 'foo' is the current directory, '/' is the parent directory | |
| 639 self.assertEquals(str(self.path.parent()), 'http://example.com/') | |
| 640 self.assertEquals(str(self.path.child('').parent()), 'http://example.com
/foo/') | |
| 641 self.assertEquals(str(self.path.child('baz').parent()), 'http://example.
com/foo/') | |
| 642 self.assertEquals(str(self.path.parent().parent().parent().parent().pare
nt()), 'http://example.com/') | |
| 643 | |
| 644 def testHereString(self): | |
| 645 # here should be equivalent to '.' | |
| 646 self.assertEquals(str(self.path.here()), 'http://example.com/foo/') | |
| 647 self.assertEquals(str(self.path.child('').here()), 'http://example.com/f
oo/bar/') | |
| 648 | |
| OLD | NEW |