Skip to content

Commit dabc6e4

Browse files
committed
(137287143) URL path extension APIs should strip trailing slashes (swiftlang#965)
1 parent a02bd72 commit dabc6e4

File tree

3 files changed

+58
-2
lines changed

3 files changed

+58
-2
lines changed

Sources/FoundationEssentials/String/String+Path.swift

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,11 @@ extension String {
194194
guard let lastDot = self.utf8.lastIndex(of: dot) else {
195195
return self
196196
}
197-
return String(self[..<lastDot])
197+
var result = String(self[..<lastDot])
198+
if utf8.last == ._slash {
199+
result += "/"
200+
}
201+
return result
198202
}
199203

200204
private func validatePathExtension(_ pathExtension: String) -> Bool {
@@ -214,7 +218,16 @@ extension String {
214218
guard validatePathExtension(pathExtension) else {
215219
return self
216220
}
217-
return self + ".\(pathExtension)"
221+
var result = self._droppingTrailingSlashes
222+
guard result != "/" else {
223+
// Path was all slashes
224+
return self + ".\(pathExtension)"
225+
}
226+
result += ".\(pathExtension)"
227+
if utf8.last == ._slash {
228+
result += "/"
229+
}
230+
return result
218231
}
219232

220233
internal var pathExtension: String {

Tests/FoundationEssentialsTests/StringTests.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,19 @@ final class StringTests : XCTestCase {
812812
}
813813
}
814814

815+
func testAppendingPathExtension() {
816+
XCTAssertEqual("".appendingPathExtension("foo"), ".foo")
817+
XCTAssertEqual("/".appendingPathExtension("foo"), "/.foo")
818+
XCTAssertEqual("//".appendingPathExtension("foo"), "//.foo")
819+
XCTAssertEqual("/path".appendingPathExtension("foo"), "/path.foo")
820+
XCTAssertEqual("/path.zip".appendingPathExtension("foo"), "/path.zip.foo")
821+
XCTAssertEqual("/path/".appendingPathExtension("foo"), "/path.foo/")
822+
XCTAssertEqual("/path//".appendingPathExtension("foo"), "/path.foo/")
823+
XCTAssertEqual("path".appendingPathExtension("foo"), "path.foo")
824+
XCTAssertEqual("path/".appendingPathExtension("foo"), "path.foo/")
825+
XCTAssertEqual("path//".appendingPathExtension("foo"), "path.foo/")
826+
}
827+
815828
func testDeletingPathExtenstion() {
816829
XCTAssertEqual("".deletingPathExtension(), "")
817830
XCTAssertEqual("/".deletingPathExtension(), "/")
@@ -834,6 +847,15 @@ final class StringTests : XCTestCase {
834847
XCTAssertEqual("/foo.bar/bar.baz/baz.zip".deletingPathExtension(), "/foo.bar/bar.baz/baz")
835848
XCTAssertEqual("/.././.././a.zip".deletingPathExtension(), "/.././.././a")
836849
XCTAssertEqual("/.././.././.".deletingPathExtension(), "/.././.././.")
850+
851+
XCTAssertEqual("path.foo".deletingPathExtension(), "path")
852+
XCTAssertEqual("path.foo.zip".deletingPathExtension(), "path.foo")
853+
XCTAssertEqual("/path.foo".deletingPathExtension(), "/path")
854+
XCTAssertEqual("/path.foo.zip".deletingPathExtension(), "/path.foo")
855+
XCTAssertEqual("path.foo/".deletingPathExtension(), "path/")
856+
XCTAssertEqual("path.foo//".deletingPathExtension(), "path/")
857+
XCTAssertEqual("/path.foo/".deletingPathExtension(), "/path/")
858+
XCTAssertEqual("/path.foo//".deletingPathExtension(), "/path/")
837859
}
838860

839861
func test_dataUsingEncoding() {

Tests/FoundationEssentialsTests/URLTests.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,27 @@ final class URLTests : XCTestCase {
659659
XCTAssertEqual(url.path().utf8.last, ._slash)
660660
}
661661

662+
func testURLPathExtensions() throws {
663+
var url = URL(filePath: "/path", directoryHint: .notDirectory)
664+
url.appendPathExtension("foo")
665+
XCTAssertEqual(url.path(), "/path.foo")
666+
url.deletePathExtension()
667+
XCTAssertEqual(url.path(), "/path")
668+
669+
url = URL(filePath: "/path", directoryHint: .isDirectory)
670+
url.appendPathExtension("foo")
671+
XCTAssertEqual(url.path(), "/path.foo/")
672+
url.deletePathExtension()
673+
XCTAssertEqual(url.path(), "/path/")
674+
675+
url = URL(filePath: "/path/", directoryHint: .inferFromPath)
676+
url.appendPathExtension("foo")
677+
XCTAssertEqual(url.path(), "/path.foo/")
678+
url.append(path: "/////")
679+
url.deletePathExtension()
680+
XCTAssertEqual(url.path(), "/path/")
681+
}
682+
662683
func testURLComponentsPercentEncodedUnencodedProperties() throws {
663684
var comp = URLComponents()
664685

0 commit comments

Comments
 (0)