@@ -3770,14 +3770,6 @@ extension KeyValuePairsTests {
3770
3770
)
3771
3771
}
3772
3772
3773
- func testAssignment( ) {
3774
- // FIXME: Test assigning a KeyValuePairs instance from another URL.
3775
- }
3776
- }
3777
-
3778
-
3779
- extension KeyValuePairsTests {
3780
-
3781
3773
/// Tests using a key-value string schema with ASCII alpha delimiters.
3782
3774
///
3783
3775
/// While not recommended, in theory it should work.
@@ -3812,75 +3804,117 @@ extension KeyValuePairsTests {
3812
3804
}
3813
3805
}
3814
3806
3807
+ extension KeyValuePairsTests {
3808
+
3809
+ /// Tests assigning a KeyValuePairs view from one URL to another.
3810
+ ///
3811
+ /// This is not generally allowed, but there are a handful of situations where it works.
3812
+ /// Unfortunately we can't test the situations where it doesn't work, because they trigger a fatal error
3813
+ /// and XCTest doesn't support testing such things.
3814
+ ///
3815
+ func testAssignment( ) {
3816
+
3817
+ // Straightforward 'queryParams' assignment.
3818
+ // This works because 'queryParams' includes a 'set' accessor, in addition to 'modify'.
3815
3819
3820
+ do {
3821
+ let srcQuery = " test=src&foo=bar&specials= \( Self . SpecialCharacters_Escaped_PrctEnc_Query) "
3816
3822
3823
+ let src = WebURL ( " http://src/? \( srcQuery) " ) !
3824
+ var dst = WebURL ( " file://dst/ " ) !
3825
+ XCTAssertEqual ( src. queryParams. count, 3 )
3826
+ XCTAssertEqual ( dst. queryParams. count, 0 )
3817
3827
3828
+ dst. queryParams = src. queryParams
3818
3829
3830
+ XCTAssertEqual ( src. serialized ( ) , " http://src/? \( srcQuery) " )
3831
+ XCTAssertEqual ( dst. serialized ( ) , " file://dst/? \( srcQuery) " )
3832
+ XCTAssertEqual ( src. queryParams. count, 3 )
3833
+ XCTAssertEqual ( dst. queryParams. count, 3 )
3834
+ }
3819
3835
3836
+ // Assigning different views originating from the same storage.
3837
+ // This works basically as a side-effect of how the mutating scope ID is calculated 😕,
3838
+ // but it's also not _really_ a problem because data outside the viewed component cannot be changed.
3820
3839
3840
+ do {
3841
+ var url1 = WebURL ( " file://xyz/ " ) !
3842
+ var url2 = url1
3843
+
3844
+ url2. withMutableKeyValuePairs ( in: . query, schema: . formEncoded) { kvps2 in
3845
+ url1. withMutableKeyValuePairs ( in: . query, schema: . formEncoded) { kvps1 in
3846
+ kvps2 += [ ( " hello " , " world " ) ]
3847
+ kvps1 = kvps2
3848
+ kvps2 += [ ( " after " , " wards " ) ]
3849
+ }
3850
+ }
3851
+
3852
+ XCTAssertEqual ( url1. serialized ( ) , " file://xyz/?hello=world " )
3853
+ XCTAssertEqual ( url2. serialized ( ) , " file://xyz/?hello=world&after=wards " )
3854
+ }
3821
3855
3856
+ // These should all cause runtime traps.
3857
+ // Unfortunately we can't test that with XCTest :(
3822
3858
3859
+ #if false
3823
3860
3861
+ let check = 0
3824
3862
3863
+ // Reassignment via modify accessor. Different source URLs.
3825
3864
3826
- // func testAssignment() {
3827
- //
3828
- // do {
3829
- // var url0 = WebURL("http://example.com?a=b&c+is the key=d&&e=&=foo&e=g&e&h=👀&e=f")!
3830
- // XCTAssertEqual(url0.serialized(), "http://example.com/?a=b&c+is%20the%20key=d&&e=&=foo&e=g&e&h=%F0%9F%91%80&e=f")
3831
- // XCTAssertEqual(url0.query, "a=b&c+is%20the%20key=d&&e=&=foo&e=g&e&h=%F0%9F%91%80&e=f")
3832
- // XCTAssertFalse(url0.storage.structure.queryIsKnownFormEncoded)
3833
- //
3834
- // var url1 = WebURL("foo://bar")!
3835
- // XCTAssertEqual(url1.serialized(), "foo://bar")
3836
- // XCTAssertNil(url1.query)
3837
- // XCTAssertTrue(url1.storage.structure.queryIsKnownFormEncoded)
3838
- //
3839
- // // Set url1's formParams from empty to url0's non-empty formParams.
3840
- // // url1's query string should be the form-encoded version version of url0's query, which itself remains unchanged.
3841
- // url1.queryParams = url0.queryParams
3842
- // XCTAssertEqual(url1.serialized(), "foo://bar?a=b&c+is%20the%20key=d&&e=&=foo&e=g&e&h=%F0%9F%91%80&e=f")
3843
- // XCTAssertEqual(url1.query, "a=b&c+is%20the%20key=d&&e=&=foo&e=g&e&h=%F0%9F%91%80&e=f")
3844
- // XCTAssertEqual(url0.serialized(), "http://example.com/?a=b&c+is%20the%20key=d&&e=&=foo&e=g&e&h=%F0%9F%91%80&e=f")
3845
- // XCTAssertEqual(url0.query, "a=b&c+is%20the%20key=d&&e=&=foo&e=g&e&h=%F0%9F%91%80&e=f")
3846
- // XCTAssertFalse(url0.storage.structure.queryIsKnownFormEncoded)
3847
- // XCTAssertFalse(url1.storage.structure.queryIsKnownFormEncoded)
3848
- // XCTAssertURLIsIdempotent(url1)
3849
- //
3850
- // // Reset url1 to a nil query. Set url0's non-empty params to url1's empty params.
3851
- // // url0 should now have a nil query, and url1 remains unchanged.
3852
- // url1 = WebURL("foo://bar")!
3853
- // XCTAssertEqual(url1.serialized(), "foo://bar")
3854
- // XCTAssertNil(url1.query)
3855
- // XCTAssertTrue(url1.storage.structure.queryIsKnownFormEncoded)
3856
- //
3857
- // url0.queryParams = url1.queryParams
3858
- // XCTAssertEqual(url0.serialized(), "http://example.com/")
3859
- // XCTAssertNil(url0.query)
3860
- // XCTAssertTrue(url0.storage.structure.queryIsKnownFormEncoded)
3861
- // XCTAssertEqual(url1.serialized(), "foo://bar")
3862
- // XCTAssertNil(url1.query)
3863
- // XCTAssertTrue(url1.storage.structure.queryIsKnownFormEncoded)
3864
- // XCTAssertURLIsIdempotent(url0)
3865
- // }
3866
- //
3867
- // // Assigning a URL's query parameters to itself has no effect.
3868
- // do {
3869
- // var url = WebURL("http://example.com?a=b&c+is the key=d&&e=&=foo&e=g&e&h=👀&e=f&&&")!
3870
- // XCTAssertEqual(
3871
- // url.serialized(), "http://example.com/?a=b&c+is%20the%20key=d&&e=&=foo&e=g&e&h=%F0%9F%91%80&e=f&&&"
3872
- // )
3873
- // XCTAssertEqual(url.query, "a=b&c+is%20the%20key=d&&e=&=foo&e=g&e&h=%F0%9F%91%80&e=f&&&")
3874
- // XCTAssertFalse(url.storage.structure.queryIsKnownFormEncoded)
3875
- //
3876
- // url.queryParams = url.queryParams
3877
- // XCTAssertEqual(
3878
- // url.serialized(), "http://example.com/?a=b&c+is%20the%20key=d&&e=&=foo&e=g&e&h=%F0%9F%91%80&e=f&&&"
3879
- // )
3880
- // XCTAssertEqual(url.query, "a=b&c+is%20the%20key=d&&e=&=foo&e=g&e&h=%F0%9F%91%80&e=f&&&")
3881
- // XCTAssertFalse(url.storage.structure.queryIsKnownFormEncoded)
3882
- // XCTAssertURLIsIdempotent(url)
3883
- // }
3884
- // }
3885
- //
3886
- //}
3865
+ if check == 0 {
3866
+ let src = WebURL ( " http://src/ " ) !
3867
+ var dst = WebURL ( " file://dst/ " ) !
3868
+
3869
+ @inline ( never)
3870
+ func assign< T> ( _ x: inout T , to y: T ) {
3871
+ x = y
3872
+ }
3873
+
3874
+ assign ( & dst. queryParams, to: src. queryParams)
3875
+ XCTFail ( " Should have trapped " )
3876
+ }
3877
+
3878
+ // Reassignment via modify accessor. Same source URLs, different components.
3879
+
3880
+ if check == 1 {
3881
+ let url1 = WebURL ( " http://xyz/ " ) !
3882
+ var url2 = url1
3883
+
3884
+ @inline ( never)
3885
+ func assign< T> ( _ x: inout T , to y: T ) {
3886
+ x = y
3887
+ }
3888
+
3889
+ assign ( & url2. queryParams, to: url1. keyValuePairs ( in: . fragment, schema: . formEncoded) )
3890
+ XCTFail ( " Should have trapped " )
3891
+ }
3892
+
3893
+ // Reassignment via scoped method. Different source URLs.
3894
+
3895
+ if check == 2 {
3896
+ let src = WebURL ( " http://src/ " ) !
3897
+ var dst = WebURL ( " file://dst/ " ) !
3898
+
3899
+ dst. withMutableKeyValuePairs ( in: . query, schema: . formEncoded) { $0 = src. queryParams }
3900
+ XCTFail ( " Should have trapped " )
3901
+ }
3902
+
3903
+ // Reassignment via scoped method. Same source URLs, different components.
3904
+
3905
+ if check == 3 {
3906
+ var url1 = WebURL ( " file://xyz/ " ) !
3907
+ var url2 = url1
3908
+
3909
+ url1. withMutableKeyValuePairs ( in: . query, schema: . formEncoded) { kvps1 in
3910
+ url2. withMutableKeyValuePairs ( in: . fragment, schema: . formEncoded) { kvps2 in
3911
+ kvps2 += [ ( " hello " , " world " ) ]
3912
+ kvps1 = kvps2
3913
+ }
3914
+ }
3915
+ XCTFail ( " Should have trapped " )
3916
+ }
3917
+
3918
+ #endif
3919
+ }
3920
+ }
0 commit comments