@@ -37,7 +37,7 @@ class FileSystemTests: XCTestCase {
3737
3838 // isSymlink()
3939 let sym = tempDirPath. appending ( component: " hello " )
40- try ! fs. createSymbolicLink ( sym, pointingAt: file. path)
40+ try ! fs. createSymbolicLink ( sym, pointingAt: file. path, relative : false )
4141 XCTAssertTrue ( fs. isSymlink ( sym) )
4242 XCTAssertTrue ( fs. isFile ( sym) )
4343 XCTAssertEqual ( try fs. getFileInfo ( sym) . fileType, . typeSymbolicLink)
@@ -46,7 +46,7 @@ class FileSystemTests: XCTestCase {
4646 // isExecutableFile
4747 let executable = tempDirPath. appending ( component: " exec-foo " )
4848 let executableSym = tempDirPath. appending ( component: " exec-sym " )
49- try ! fs. createSymbolicLink ( executableSym, pointingAt: executable)
49+ try ! fs. createSymbolicLink ( executableSym, pointingAt: executable, relative : false )
5050 let stream = BufferedOutputByteStream ( )
5151 stream <<< """
5252 #!/bin/sh
@@ -84,6 +84,74 @@ class FileSystemTests: XCTestCase {
8484 }
8585 }
8686
87+ func testResolvingSymlinks( ) {
88+ // Make sure the root path resolves to itself.
89+ XCTAssertEqual ( resolveSymlinks ( AbsolutePath . root) , AbsolutePath . root)
90+
91+ // For the rest of the tests we'll need a temporary directory.
92+ try ! withTemporaryDirectory ( removeTreeOnDeinit: true ) { path in
93+ // FIXME: it would be better to not need to resolve symbolic links, but we end up relying on /tmp -> /private/tmp.
94+ let tmpDirPath = resolveSymlinks ( path)
95+
96+ // Create a symbolic link and directory.
97+ let slnkPath = tmpDirPath. appending ( component: " slnk " )
98+ let fldrPath = tmpDirPath. appending ( component: " fldr " )
99+
100+ // Create a symbolic link pointing at the (so far non-existent) directory.
101+ try ! localFileSystem. createSymbolicLink ( slnkPath, pointingAt: fldrPath, relative: true )
102+
103+ // Resolving the symlink should not yet change anything.
104+ XCTAssertEqual ( resolveSymlinks ( slnkPath) , slnkPath)
105+
106+ // Create a directory to be the referent of the symbolic link.
107+ try ! makeDirectories ( fldrPath)
108+
109+ // Resolving the symlink should now point at the directory.
110+ XCTAssertEqual ( resolveSymlinks ( slnkPath) , fldrPath)
111+
112+ // Resolving the directory should still not change anything.
113+ XCTAssertEqual ( resolveSymlinks ( fldrPath) , fldrPath)
114+ }
115+ }
116+
117+ func testSymlinksNotWalked( ) {
118+ try ! withTemporaryDirectory ( removeTreeOnDeinit: true ) { path in
119+ // FIXME: it would be better to not need to resolve symbolic links, but we end up relying on /tmp -> /private/tmp.
120+ let tmpDirPath = resolveSymlinks ( path)
121+
122+ try ! makeDirectories ( tmpDirPath. appending ( component: " foo " ) )
123+ try ! makeDirectories ( tmpDirPath. appending ( components: " bar " , " baz " , " goo " ) )
124+ try ! localFileSystem. createSymbolicLink ( tmpDirPath. appending ( components: " foo " , " symlink " ) , pointingAt: tmpDirPath. appending ( component: " bar " ) , relative: true )
125+
126+ XCTAssertTrue ( localFileSystem. isSymlink ( tmpDirPath. appending ( components: " foo " , " symlink " ) ) )
127+ XCTAssertEqual ( resolveSymlinks ( tmpDirPath. appending ( components: " foo " , " symlink " ) ) , tmpDirPath. appending ( component: " bar " ) )
128+ XCTAssertTrue ( localFileSystem. isDirectory ( resolveSymlinks ( tmpDirPath. appending ( components: " foo " , " symlink " , " baz " ) ) ) )
129+
130+ let results = try ! walk ( tmpDirPath. appending ( component: " foo " ) ) . map { $0 }
131+
132+ XCTAssertEqual ( results, [ tmpDirPath. appending ( components: " foo " , " symlink " ) ] )
133+ }
134+ }
135+
136+ func testWalkingADirectorySymlinkResolvesOnce( ) {
137+ try ! withTemporaryDirectory ( removeTreeOnDeinit: true ) { tmpDirPath in
138+ try ! makeDirectories ( tmpDirPath. appending ( components: " foo " , " bar " ) )
139+ try ! makeDirectories ( tmpDirPath. appending ( components: " abc " , " bar " ) )
140+ try ! localFileSystem. createSymbolicLink ( tmpDirPath. appending ( component: " symlink " ) , pointingAt: tmpDirPath. appending ( component: " foo " ) , relative: true )
141+ try ! localFileSystem. createSymbolicLink ( tmpDirPath. appending ( components: " foo " , " baz " ) , pointingAt: tmpDirPath. appending ( component: " abc " ) , relative: true )
142+
143+ XCTAssertTrue ( localFileSystem. isSymlink ( tmpDirPath. appending ( component: " symlink " ) ) )
144+
145+ let results = try ! walk ( tmpDirPath. appending ( component: " symlink " ) ) . map { $0 } . sorted ( )
146+
147+ // we recurse a symlink to a directory, so this should work,
148+ // but `abc` should not show because `baz` is a symlink too
149+ // and that should *not* be followed
150+
151+ XCTAssertEqual ( results, [ tmpDirPath. appending ( components: " symlink " , " bar " ) , tmpDirPath. appending ( components: " symlink " , " baz " ) ] )
152+ }
153+ }
154+
87155 func testLocalExistsSymlink( ) throws {
88156 try testWithTemporaryDirectory { tmpdir in
89157 let fs = TSCBasic . localFileSystem
@@ -94,7 +162,7 @@ class FileSystemTests: XCTestCase {
94162
95163 // Source and target exist.
96164
97- try fs. createSymbolicLink ( source, pointingAt: target)
165+ try fs. createSymbolicLink ( source, pointingAt: target, relative : false )
98166 XCTAssertEqual ( fs. exists ( source) , true )
99167 XCTAssertEqual ( fs. exists ( source, followSymlink: true ) , true )
100168 XCTAssertEqual ( fs. exists ( source, followSymlink: false ) , true )
@@ -385,7 +453,7 @@ class FileSystemTests: XCTestCase {
385453
386454 // Source and target exist.
387455
388- try fs. createSymbolicLink ( source, pointingAt: target)
456+ try fs. createSymbolicLink ( source, pointingAt: target, relative : false )
389457 XCTAssertEqual ( fs. exists ( source) , true )
390458 XCTAssertEqual ( fs. exists ( source, followSymlink: true ) , true )
391459 XCTAssertEqual ( fs. exists ( source, followSymlink: false ) , true )
@@ -598,7 +666,7 @@ class FileSystemTests: XCTestCase {
598666
599667 // Source and target exist.
600668
601- try fs. createSymbolicLink ( source, pointingAt: target)
669+ try fs. createSymbolicLink ( source, pointingAt: target, relative : false )
602670 XCTAssertEqual ( fs. exists ( source) , true )
603671 XCTAssertEqual ( fs. exists ( source, followSymlink: true ) , true )
604672 XCTAssertEqual ( fs. exists ( source, followSymlink: false ) , true )
@@ -631,7 +699,7 @@ class FileSystemTests: XCTestCase {
631699 try fs. createDirectory ( dir, recursive: true )
632700 try fs. writeFileContents ( foo, bytes: " " )
633701 try fs. writeFileContents ( bar, bytes: " " )
634- try fs. createSymbolicLink ( sym, pointingAt: foo)
702+ try fs. createSymbolicLink ( sym, pointingAt: foo, relative : false )
635703
636704 // Set foo to unwritable.
637705 try fs. chmod ( . userUnWritable, path: foo)
0 commit comments