@@ -23,6 +23,18 @@ import TestSupport
23
23
@testable import Foundation
24
24
#endif
25
25
26
+ private func checkBehavior< T: Equatable > ( _ result: T , new: T , old: T , file: StaticString = #filePath, line: UInt = #line) {
27
+ #if FOUNDATION_FRAMEWORK
28
+ if foundation_swift_url_enabled ( ) {
29
+ XCTAssertEqual ( result, new, file: file, line: line)
30
+ } else {
31
+ XCTAssertEqual ( result, old, file: file, line: line)
32
+ }
33
+ #else
34
+ XCTAssertEqual ( result, new, file: file, line: line)
35
+ #endif
36
+ }
37
+
26
38
final class URLTests : XCTestCase {
27
39
28
40
func testURLBasics( ) throws {
@@ -87,11 +99,7 @@ final class URLTests : XCTestCase {
87
99
XCTAssertEqual ( relativeURLWithBase. password ( ) , baseURL. password ( ) )
88
100
XCTAssertEqual ( relativeURLWithBase. host ( ) , baseURL. host ( ) )
89
101
XCTAssertEqual ( relativeURLWithBase. port, baseURL. port)
90
- #if !FOUNDATION_FRAMEWORK_NSURL
91
- XCTAssertEqual ( relativeURLWithBase. path ( ) , " /base/relative/path " )
92
- #else
93
- XCTAssertEqual ( relativeURLWithBase. path ( ) , " relative/path " )
94
- #endif
102
+ checkBehavior ( relativeURLWithBase. path ( ) , new: " /base/relative/path " , old: " relative/path " )
95
103
XCTAssertEqual ( relativeURLWithBase. relativePath, " relative/path " )
96
104
XCTAssertEqual ( relativeURLWithBase. query ( ) , " query " )
97
105
XCTAssertEqual ( relativeURLWithBase. fragment ( ) , " fragment " )
@@ -154,7 +162,7 @@ final class URLTests : XCTestCase {
154
162
" http:g " : " http:g " , // For strict parsers
155
163
]
156
164
157
- #if FOUNDATION_FRAMEWORK_NSURL
165
+ #if FOUNDATION_FRAMEWORK
158
166
let testsFailingWithoutSwiftURL = Set ( [
159
167
" " ,
160
168
" ../../../g " ,
@@ -165,8 +173,8 @@ final class URLTests : XCTestCase {
165
173
#endif
166
174
167
175
for test in tests {
168
- #if FOUNDATION_FRAMEWORK_NSURL
169
- if testsFailingWithoutSwiftURL. contains ( test. key) {
176
+ #if FOUNDATION_FRAMEWORK
177
+ if !foundation_swift_url_enabled ( ) , testsFailingWithoutSwiftURL. contains ( test. key) {
170
178
continue
171
179
}
172
180
#endif
@@ -178,8 +186,8 @@ final class URLTests : XCTestCase {
178
186
}
179
187
180
188
func testURLPathAPIsResolveAgainstBase( ) throws {
181
- #if FOUNDATION_FRAMEWORK_NSURL
182
- try XCTSkipIf ( true )
189
+ #if FOUNDATION_FRAMEWORK
190
+ try XCTSkipIf ( !foundation_swift_url_enabled ( ) )
183
191
#endif
184
192
// Borrowing the same test cases from RFC 3986, but checking paths
185
193
let base = URL ( string: " http://a/b/c/d;p?q " )
@@ -246,8 +254,8 @@ final class URLTests : XCTestCase {
246
254
}
247
255
248
256
func testURLPathComponentsPercentEncodedSlash( ) throws {
249
- #if FOUNDATION_FRAMEWORK_NSURL
250
- try XCTSkipIf ( true )
257
+ #if FOUNDATION_FRAMEWORK
258
+ try XCTSkipIf ( !foundation_swift_url_enabled ( ) )
251
259
#endif
252
260
253
261
var url = try XCTUnwrap ( URL ( string: " https://example.com/https%3A%2F%2Fexample.com " ) )
@@ -270,8 +278,8 @@ final class URLTests : XCTestCase {
270
278
}
271
279
272
280
func testURLRootlessPath( ) throws {
273
- #if FOUNDATION_FRAMEWORK_NSURL
274
- try XCTSkipIf ( true )
281
+ #if FOUNDATION_FRAMEWORK
282
+ try XCTSkipIf ( !foundation_swift_url_enabled ( ) )
275
283
#endif
276
284
277
285
let paths = [ " " , " path " ]
@@ -565,13 +573,8 @@ final class URLTests : XCTestCase {
565
573
// `appending(component:)` should explicitly treat `component` as a single
566
574
// path component, meaning "/" should be encoded to "%2F" before appending
567
575
appended = url. appending ( component: slashComponent, directoryHint: . notDirectory)
568
- #if FOUNDATION_FRAMEWORK_NSURL
569
- XCTAssertEqual ( appended. absoluteString, " file:///var/mobile/relative/with:slash " )
570
- XCTAssertEqual ( appended. relativePath, " relative/with:slash " )
571
- #else
572
- XCTAssertEqual ( appended. absoluteString, " file:///var/mobile/relative/%2Fwith:slash " )
573
- XCTAssertEqual ( appended. relativePath, " relative/%2Fwith:slash " )
574
- #endif
576
+ checkBehavior ( appended. absoluteString, new: " file:///var/mobile/relative/%2Fwith:slash " , old: " file:///var/mobile/relative/with:slash " )
577
+ checkBehavior ( appended. relativePath, new: " relative/%2Fwith:slash " , old: " relative/with:slash " )
575
578
576
579
appended = url. appendingPathComponent ( component, isDirectory: false )
577
580
XCTAssertEqual ( appended. absoluteString, " file:///var/mobile/relative/no:slash " )
@@ -685,12 +688,48 @@ final class URLTests : XCTestCase {
685
688
XCTAssertEqual ( url. path ( ) , " /path.foo/ " )
686
689
url. append ( path: " ///// " )
687
690
url. deletePathExtension ( )
688
- #if !FOUNDATION_FRAMEWORK_NSURL
689
- XCTAssertEqual ( url. path ( ) , " /path/ " )
690
- #else
691
691
// Old behavior only searches the last empty component, so the extension isn't actually removed
692
- XCTAssertEqual ( url. path ( ) , " /path.foo/// " )
693
- #endif
692
+ checkBehavior ( url. path ( ) , new: " /path/ " , old: " /path.foo/// " )
693
+ }
694
+
695
+ func testURLAppendingToEmptyPath( ) throws {
696
+ let baseURL = URL ( filePath: " /base/directory " , directoryHint: . isDirectory)
697
+ let emptyPathURL = URL ( filePath: " " , relativeTo: baseURL)
698
+ let url = emptyPathURL. appending ( path: " main.swift " )
699
+ XCTAssertEqual ( url. relativePath, " ./main.swift " )
700
+ XCTAssertEqual ( url. path, " /base/directory/main.swift " )
701
+
702
+ var example = try XCTUnwrap ( URL ( string: " https://example.com " ) )
703
+ XCTAssertEqual ( example. host ( ) , " example.com " )
704
+ XCTAssertTrue ( example. path ( ) . isEmpty)
705
+
706
+ // Appending to an empty path should add a slash if an authority exists
707
+ // The appended path should never become part of the host
708
+ example. append ( path: " foo " )
709
+ XCTAssertEqual ( example. host ( ) , " example.com " )
710
+ XCTAssertEqual ( example. path ( ) , " /foo " )
711
+ XCTAssertEqual ( example. absoluteString, " https://example.com/foo " )
712
+
713
+ var emptyHost = try XCTUnwrap ( URL ( string: " scheme:// " ) )
714
+ XCTAssertTrue ( emptyHost. host ( ) ? . isEmpty ?? true )
715
+ XCTAssertTrue ( emptyHost. path ( ) . isEmpty)
716
+
717
+ emptyHost. append ( path: " foo " )
718
+ XCTAssertTrue ( emptyHost. host ( ) ? . isEmpty ?? true )
719
+ // Old behavior failed to append correctly to an empty host
720
+ // Modern parsers agree that "foo" relative to "scheme://" is "scheme:///foo"
721
+ checkBehavior ( emptyHost. path ( ) , new: " /foo " , old: " " )
722
+ checkBehavior ( emptyHost. absoluteString, new: " scheme:///foo " , old: " scheme:// " )
723
+
724
+ var schemeOnly = try XCTUnwrap ( URL ( string: " scheme: " ) )
725
+ XCTAssertTrue ( schemeOnly. host ( ) ? . isEmpty ?? true )
726
+ XCTAssertTrue ( schemeOnly. path ( ) . isEmpty)
727
+
728
+ schemeOnly. append ( path: " foo " )
729
+ XCTAssertTrue ( schemeOnly. host ( ) ? . isEmpty ?? true )
730
+ // Old behavior appends to the string, but is missing the path
731
+ checkBehavior ( schemeOnly. path ( ) , new: " foo " , old: " " )
732
+ XCTAssertEqual ( schemeOnly. absoluteString, " scheme:foo " )
694
733
}
695
734
696
735
func testURLComponentsPercentEncodedUnencodedProperties( ) throws {
0 commit comments