Skip to content

Commit 88e933b

Browse files
committed
(137287143) URL path extension APIs should strip trailing slashes (swiftlang#965)
1 parent 95fe342 commit 88e933b

File tree

3 files changed

+58
-2
lines changed

3 files changed

+58
-2
lines changed

Sources/FoundationEssentials/String/String+Path.swift

+15-2
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,11 @@ extension String {
192192
guard let lastDot = self.utf8.lastIndex(of: dot) else {
193193
return self
194194
}
195-
return String(self[..<lastDot])
195+
var result = String(self[..<lastDot])
196+
if utf8.last == ._slash {
197+
result += "/"
198+
}
199+
return result
196200
}
197201

198202
private func validatePathExtension(_ pathExtension: String) -> Bool {
@@ -212,7 +216,16 @@ extension String {
212216
guard validatePathExtension(pathExtension) else {
213217
return self
214218
}
215-
return self + ".\(pathExtension)"
219+
var result = self._droppingTrailingSlashes
220+
guard result != "/" else {
221+
// Path was all slashes
222+
return self + ".\(pathExtension)"
223+
}
224+
result += ".\(pathExtension)"
225+
if utf8.last == ._slash {
226+
result += "/"
227+
}
228+
return result
216229
}
217230

218231
internal var pathExtension: String {

Tests/FoundationEssentialsTests/StringTests.swift

+22
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

+21
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)