Skip to content

Commit 09bdd0d

Browse files
authored
(137287143) URL path extension APIs should strip trailing slashes (#965)
1 parent bc7c257 commit 09bdd0d

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
@@ -186,7 +186,11 @@ extension String {
186186
guard let lastDot = utf8.lastIndex(of: ._dot) else {
187187
return self
188188
}
189-
return String(self[..<lastDot])
189+
var result = String(self[..<lastDot])
190+
if utf8.last == ._slash {
191+
result += "/"
192+
}
193+
return result
190194
}
191195

192196
private func validatePathExtension(_ pathExtension: String) -> Bool {
@@ -206,7 +210,16 @@ extension String {
206210
guard validatePathExtension(pathExtension) else {
207211
return self
208212
}
209-
return self + ".\(pathExtension)"
213+
var result = self._droppingTrailingSlashes
214+
guard result != "/" else {
215+
// Path was all slashes
216+
return self + ".\(pathExtension)"
217+
}
218+
result += ".\(pathExtension)"
219+
if utf8.last == ._slash {
220+
result += "/"
221+
}
222+
return result
210223
}
211224

212225
internal var pathExtension: String {

Tests/FoundationEssentialsTests/StringTests.swift

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

816+
func testAppendingPathExtension() {
817+
XCTAssertEqual("".appendingPathExtension("foo"), ".foo")
818+
XCTAssertEqual("/".appendingPathExtension("foo"), "/.foo")
819+
XCTAssertEqual("//".appendingPathExtension("foo"), "//.foo")
820+
XCTAssertEqual("/path".appendingPathExtension("foo"), "/path.foo")
821+
XCTAssertEqual("/path.zip".appendingPathExtension("foo"), "/path.zip.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+
XCTAssertEqual("path//".appendingPathExtension("foo"), "path.foo/")
827+
}
828+
816829
func testDeletingPathExtenstion() {
817830
XCTAssertEqual("".deletingPathExtension(), "")
818831
XCTAssertEqual("/".deletingPathExtension(), "/")
@@ -835,6 +848,15 @@ final class StringTests : XCTestCase {
835848
XCTAssertEqual("/foo.bar/bar.baz/baz.zip".deletingPathExtension(), "/foo.bar/bar.baz/baz")
836849
XCTAssertEqual("/.././.././a.zip".deletingPathExtension(), "/.././.././a")
837850
XCTAssertEqual("/.././.././.".deletingPathExtension(), "/.././.././.")
851+
852+
XCTAssertEqual("path.foo".deletingPathExtension(), "path")
853+
XCTAssertEqual("path.foo.zip".deletingPathExtension(), "path.foo")
854+
XCTAssertEqual("/path.foo".deletingPathExtension(), "/path")
855+
XCTAssertEqual("/path.foo.zip".deletingPathExtension(), "/path.foo")
856+
XCTAssertEqual("path.foo/".deletingPathExtension(), "path/")
857+
XCTAssertEqual("path.foo//".deletingPathExtension(), "path/")
858+
XCTAssertEqual("/path.foo/".deletingPathExtension(), "/path/")
859+
XCTAssertEqual("/path.foo//".deletingPathExtension(), "/path/")
838860
}
839861

840862
func testPathComponents() {

Tests/FoundationEssentialsTests/URLTests.swift

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

650+
func testURLPathExtensions() throws {
651+
var url = URL(filePath: "/path", directoryHint: .notDirectory)
652+
url.appendPathExtension("foo")
653+
XCTAssertEqual(url.path(), "/path.foo")
654+
url.deletePathExtension()
655+
XCTAssertEqual(url.path(), "/path")
656+
657+
url = URL(filePath: "/path", directoryHint: .isDirectory)
658+
url.appendPathExtension("foo")
659+
XCTAssertEqual(url.path(), "/path.foo/")
660+
url.deletePathExtension()
661+
XCTAssertEqual(url.path(), "/path/")
662+
663+
url = URL(filePath: "/path/", directoryHint: .inferFromPath)
664+
url.appendPathExtension("foo")
665+
XCTAssertEqual(url.path(), "/path.foo/")
666+
url.append(path: "/////")
667+
url.deletePathExtension()
668+
XCTAssertEqual(url.path(), "/path/")
669+
}
670+
650671
func testURLComponentsPercentEncodedUnencodedProperties() throws {
651672
var comp = URLComponents()
652673

0 commit comments

Comments
 (0)