Skip to content

Commit f3b0874

Browse files
committed
[android] Replace URL tests that use hardcoded /tmp
In Android /tmp doesn't exist, and the temporary directory is normally /data/local/tmp. It is not a symlink. The tests were mostly working, but because `resolvingSymlinksInPath` returns a trailing slash if the directory actually exists, in Android it was returning without the final trailing slash in some of the cases. The changes split the large test into smaller pieces that test one of the behaviours of `resolvingSymlinksInPath`, and tries not to use the temporarl directory by itself or suppose anything about it. There are, however, a couple of tests that check behaviours that are only applicable to Darwin, so those tests are only performed in Darwin platforms.
1 parent a764480 commit f3b0874

File tree

1 file changed

+134
-50
lines changed

1 file changed

+134
-50
lines changed

TestFoundation/TestURL.swift

Lines changed: 134 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -48,19 +48,57 @@ private func getTestData() -> [Any]? {
4848

4949
class TestURL : XCTestCase {
5050
static var allTests: [(String, (TestURL) -> () throws -> Void)] {
51-
return [
51+
var tests: [(String, (TestURL) -> () throws -> Void)] = [
5252
("test_URLStrings", test_URLStrings),
5353
("test_fileURLWithPath_relativeTo", test_fileURLWithPath_relativeTo ),
5454
// TODO: these tests fail on linux, more investigation is needed
5555
("test_fileURLWithPath", test_fileURLWithPath),
5656
("test_fileURLWithPath_isDirectory", test_fileURLWithPath_isDirectory),
57-
("test_URLByResolvingSymlinksInPath", test_URLByResolvingSymlinksInPath),
57+
("test_URLByResolvingSymlinksInPathShouldRemoveDuplicatedPathSeparators", test_URLByResolvingSymlinksInPathShouldRemoveDuplicatedPathSeparators),
58+
("test_URLByResolvingSymlinksInPathShouldRemoveSingleDotsBetweenSeparators", test_URLByResolvingSymlinksInPathShouldRemoveSingleDotsBetweenSeparators),
59+
("test_URLByResolvingSymlinksInPathShouldCompressDoubleDotsBetweenSeparators", test_URLByResolvingSymlinksInPathShouldCompressDoubleDotsBetweenSeparators),
60+
("test_URLByResolvingSymlinksInPathShouldUseTheCurrentDirectory", test_URLByResolvingSymlinksInPathShouldUseTheCurrentDirectory),
61+
("test_resolvingSymlinksInPathShouldAppendTrailingSlashWhenExistingDirectory", test_resolvingSymlinksInPathShouldAppendTrailingSlashWhenExistingDirectory),
62+
("test_resolvingSymlinksInPathShouldResolvesSymlinks", test_resolvingSymlinksInPathShouldResolvesSymlinks),
63+
("test_resolvingSymlinksInPathShouldNotChangeNonFileURLs", test_resolvingSymlinksInPathShouldNotChangeNonFileURLs),
64+
("test_resolvingSymlinksInPathShouldNotChangePathlessURLs", test_resolvingSymlinksInPathShouldNotChangePathlessURLs),
5865
("test_reachable", test_reachable),
5966
("test_copy", test_copy),
6067
("test_itemNSCoding", test_itemNSCoding),
6168
("test_dataRepresentation", test_dataRepresentation),
6269
("test_description", test_description),
6370
]
71+
72+
#if canImport(Darwin)
73+
tests += [
74+
("test_resolvingSymlinksInPathShouldRemovePrivatePrefix", test_resolvingSymlinksInPathShouldRemovePrivatePrefix),
75+
("test_resolvingSymlinksInPathShouldNotRemovePrivatePrefixIfOnlyComponent", test_resolvingSymlinksInPathShouldNotRemovePrivatePrefixIfOnlyComponent),
76+
]
77+
#endif
78+
79+
return tests
80+
}
81+
82+
var writableTestDirectoryURL: URL!
83+
84+
override func setUp() {
85+
super.setUp()
86+
87+
let pid = ProcessInfo.processInfo.processIdentifier
88+
writableTestDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("org.swift.TestFoundation.TestURL.\(pid)")
89+
}
90+
91+
override func tearDown() {
92+
if let directoryURL = writableTestDirectoryURL,
93+
(try? FileManager.default.attributesOfItem(atPath: directoryURL.path)) != nil {
94+
do {
95+
try FileManager.default.removeItem(at: directoryURL)
96+
} catch {
97+
NSLog("Could not remove test directory at URL \(directoryURL): \(error)")
98+
}
99+
}
100+
101+
super.tearDown()
64102
}
65103

66104
func test_fileURLWithPath_relativeTo() {
@@ -383,58 +421,104 @@ class TestURL : XCTestCase {
383421
XCTAssertTrue(strncmp(TestURL.gFileDoesNotExistName, relativePath, lengthOfRelativePath) == 0, "fileSystemRepresentation of file path is wrong")
384422
}
385423

386-
func test_URLByResolvingSymlinksInPath() {
387-
let files = [
388-
NSTemporaryDirectory() + "ABC/test_URLByResolvingSymlinksInPath"
389-
]
390-
391-
guard ensureFiles(files) else {
392-
XCTAssert(false, "Could create files for testing.")
393-
return
394-
}
395-
396-
// tmp is special because it is symlinked to /private/tmp and this /private prefix should be dropped,
397-
// so tmp is tmp. On Linux tmp is not symlinked so it would be the same.
398-
do {
399-
let url = URL(fileURLWithPath: "/.//tmp/ABC/..")
400-
let result = url.resolvingSymlinksInPath().absoluteString
401-
XCTAssertEqual(result, "file:///tmp/", "URLByResolvingSymlinksInPath removes extraneous path components and resolve symlinks.")
402-
}
403-
404-
do {
405-
let url = URL(fileURLWithPath: "~")
406-
let result = url.resolvingSymlinksInPath().absoluteString
407-
let expected = "file://" + FileManager.default.currentDirectoryPath + "/~"
408-
XCTAssertEqual(result, expected, "URLByResolvingSymlinksInPath resolves relative paths using current working directory.")
409-
}
424+
func test_URLByResolvingSymlinksInPathShouldRemoveDuplicatedPathSeparators() {
425+
let url = URL(fileURLWithPath: "//foo///bar////baz/")
426+
let result = url.resolvingSymlinksInPath()
427+
XCTAssertEqual(result, URL(fileURLWithPath: "/foo/bar/baz"))
428+
}
410429

411-
do {
412-
let url = URL(fileURLWithPath: "anysite.com/search")
413-
let result = url.resolvingSymlinksInPath().absoluteString
414-
let expected = "file://" + FileManager.default.currentDirectoryPath + "/anysite.com/search"
415-
XCTAssertEqual(result, expected)
416-
}
430+
func test_URLByResolvingSymlinksInPathShouldRemoveSingleDotsBetweenSeparators() {
431+
let url = URL(fileURLWithPath: "/./foo/./.bar/./baz/./")
432+
let result = url.resolvingSymlinksInPath()
433+
XCTAssertEqual(result, URL(fileURLWithPath: "/foo/.bar/baz"))
434+
}
417435

418-
// tmp is symlinked on macOS only
419-
#if os(macOS)
420-
do {
421-
let url = URL(fileURLWithPath: "/tmp/..")
422-
let result = url.resolvingSymlinksInPath().absoluteString
423-
XCTAssertEqual(result, "file:///private/")
424-
}
425-
#else
426-
do {
427-
let url = URL(fileURLWithPath: "/tmp/ABC/test_URLByResolvingSymlinksInPath")
428-
let result = url.resolvingSymlinksInPath().absoluteString
429-
XCTAssertEqual(result, "file:///tmp/ABC/test_URLByResolvingSymlinksInPath", "URLByResolvingSymlinksInPath appends trailing slash for existing directories only")
430-
}
431-
#endif
436+
func test_URLByResolvingSymlinksInPathShouldCompressDoubleDotsBetweenSeparators() {
437+
let url = URL(fileURLWithPath: "/foo/../..bar/../baz/")
438+
let result = url.resolvingSymlinksInPath()
439+
XCTAssertEqual(result, URL(fileURLWithPath: "/baz"))
440+
}
432441

433-
do {
434-
let url = URL(fileURLWithPath: "/tmp/ABC/..")
435-
let result = url.resolvingSymlinksInPath().absoluteString
436-
XCTAssertEqual(result, "file:///tmp/")
442+
func test_URLByResolvingSymlinksInPathShouldUseTheCurrentDirectory() throws {
443+
let fileManager = FileManager.default
444+
try fileManager.createDirectory(at: writableTestDirectoryURL, withIntermediateDirectories: true)
445+
defer { try? fileManager.removeItem(at: writableTestDirectoryURL) }
446+
447+
let previousCurrentDirectory = fileManager.currentDirectoryPath
448+
fileManager.changeCurrentDirectoryPath(writableTestDirectoryURL.path)
449+
defer { fileManager.changeCurrentDirectoryPath(previousCurrentDirectory) }
450+
451+
// In Darwin, because temporary directory is inside /private,
452+
// writableTestDirectoryURL will be something like /var/folders/...,
453+
// but /var points to /private/var, which is only removed if the
454+
// destination exists, so we create the destination to avoid having to
455+
// compare against /private in Darwin.
456+
try fileManager.createDirectory(at: writableTestDirectoryURL.appendingPathComponent("foo/bar"), withIntermediateDirectories: true)
457+
try "".write(to: writableTestDirectoryURL.appendingPathComponent("foo/bar/baz"), atomically: true, encoding: .utf8)
458+
459+
let url = URL(fileURLWithPath: "foo/bar/baz")
460+
let result = url.resolvingSymlinksInPath()
461+
XCTAssertEqual(result, URL(fileURLWithPath: writableTestDirectoryURL.path + "/foo/bar/baz"))
462+
}
463+
464+
func test_resolvingSymlinksInPathShouldAppendTrailingSlashWhenExistingDirectory() throws {
465+
let fileManager = FileManager.default
466+
try fileManager.createDirectory(at: writableTestDirectoryURL, withIntermediateDirectories: true)
467+
defer { try? fileManager.removeItem(at: writableTestDirectoryURL) }
468+
469+
var path = writableTestDirectoryURL.path
470+
if path.hasSuffix("/") {
471+
path.remove(at: path.index(path.endIndex, offsetBy: -1))
437472
}
473+
let url = URL(fileURLWithPath: path)
474+
let result = url.resolvingSymlinksInPath()
475+
XCTAssertEqual(result, URL(fileURLWithPath: path + "/"))
476+
}
477+
478+
func test_resolvingSymlinksInPathShouldResolvesSymlinks() throws {
479+
// NOTE: this test only works on file systems that support symlinks.
480+
let fileManager = FileManager.default
481+
try fileManager.createDirectory(at: writableTestDirectoryURL, withIntermediateDirectories: true)
482+
defer { try? fileManager.removeItem(at: writableTestDirectoryURL) }
483+
484+
let symbolicLink = writableTestDirectoryURL.appendingPathComponent("origin")
485+
print(symbolicLink)
486+
let destination = writableTestDirectoryURL.appendingPathComponent("destination")
487+
print(destination)
488+
try "".write(to: destination, atomically: true, encoding: .utf8)
489+
try fileManager.createSymbolicLink(at: symbolicLink, withDestinationURL: destination)
490+
491+
let result = symbolicLink.resolvingSymlinksInPath()
492+
print(result)
493+
XCTAssertEqual(result, URL(fileURLWithPath: writableTestDirectoryURL.path + "/destination"))
494+
}
495+
496+
func test_resolvingSymlinksInPathShouldRemovePrivatePrefix() {
497+
// NOTE: this test only works on Darwin, since the code that removes
498+
// /private relies on /private/tmp existing.
499+
let url = URL(fileURLWithPath: "/private/tmp")
500+
let result = url.resolvingSymlinksInPath()
501+
XCTAssertEqual(result, URL(fileURLWithPath: "/tmp"))
502+
}
503+
504+
func test_resolvingSymlinksInPathShouldNotRemovePrivatePrefixIfOnlyComponent() {
505+
// NOTE: this test only works on Darwin, since only there /tmp is
506+
// symlinked to /private/tmp.
507+
let url = URL(fileURLWithPath: "/tmp/..")
508+
let result = url.resolvingSymlinksInPath()
509+
XCTAssertEqual(result, URL(fileURLWithPath: "/private"))
510+
}
511+
512+
func test_resolvingSymlinksInPathShouldNotChangeNonFileURLs() {
513+
let url = URL(string: "myscheme://server/foo/bar/baz")!
514+
let result = url.resolvingSymlinksInPath().absoluteString
515+
XCTAssertEqual(result, "myscheme://server/foo/bar/baz")
516+
}
517+
518+
func test_resolvingSymlinksInPathShouldNotChangePathlessURLs() {
519+
let url = URL(string: "file://")!
520+
let result = url.resolvingSymlinksInPath().absoluteString
521+
XCTAssertEqual(result, "file://")
438522
}
439523

440524
func test_reachable() {

0 commit comments

Comments
 (0)