Add Dictionary and String extensions for creating URL query strings. Add tests.
This commit is contained in:
parent
c3bcf82713
commit
f430d6a095
@ -7,6 +7,9 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
8409DB2C200AE4D700CE879E /* Dictionary+RSWeb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8409DB2B200AE4D700CE879E /* Dictionary+RSWeb.swift */; };
|
||||
8409DB2E200AE74400CE879E /* DictionaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8409DB2D200AE74400CE879E /* DictionaryTests.swift */; };
|
||||
8409DB30200AE81400CE879E /* String+RSWeb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8409DB2F200AE81400CE879E /* String+RSWeb.swift */; };
|
||||
84245C5A1FDC690A0074AFBB /* WebServiceProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84245C591FDC690A0074AFBB /* WebServiceProvider.swift */; };
|
||||
84245C5B1FDC690A0074AFBB /* WebServiceProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84245C591FDC690A0074AFBB /* WebServiceProvider.swift */; };
|
||||
84245C5D1FDC697A0074AFBB /* Credentials.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84245C5C1FDC697A0074AFBB /* Credentials.swift */; };
|
||||
@ -15,6 +18,7 @@
|
||||
84245C611FDC69F20074AFBB /* APICall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84245C5F1FDC69F20074AFBB /* APICall.swift */; };
|
||||
84245C6F1FDDCD8C0074AFBB /* HTTPResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84245C6E1FDDCD8C0074AFBB /* HTTPResult.swift */; };
|
||||
84245C701FDDCD8C0074AFBB /* HTTPResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84245C6E1FDDCD8C0074AFBB /* HTTPResult.swift */; };
|
||||
84261183200AE918004D89DD /* StringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84261182200AE918004D89DD /* StringTests.swift */; };
|
||||
842ED2E71E12FB8A000CF738 /* HTTPRequestHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED2E61E12FB8A000CF738 /* HTTPRequestHeader.swift */; };
|
||||
842ED2E81E12FB8A000CF738 /* HTTPRequestHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED2E61E12FB8A000CF738 /* HTTPRequestHeader.swift */; };
|
||||
842ED2EA1E12FB91000CF738 /* HTTPMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842ED2E91E12FB91000CF738 /* HTTPMethod.swift */; };
|
||||
@ -61,10 +65,14 @@
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
8409DB2B200AE4D700CE879E /* Dictionary+RSWeb.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "Dictionary+RSWeb.swift"; path = "RSWeb/Dictionary+RSWeb.swift"; sourceTree = "<group>"; };
|
||||
8409DB2D200AE74400CE879E /* DictionaryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DictionaryTests.swift; sourceTree = "<group>"; };
|
||||
8409DB2F200AE81400CE879E /* String+RSWeb.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "String+RSWeb.swift"; path = "RSWeb/String+RSWeb.swift"; sourceTree = "<group>"; };
|
||||
84245C591FDC690A0074AFBB /* WebServiceProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebServiceProvider.swift; sourceTree = "<group>"; };
|
||||
84245C5C1FDC697A0074AFBB /* Credentials.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Credentials.swift; path = RSWeb/Credentials.swift; sourceTree = "<group>"; };
|
||||
84245C5F1FDC69F20074AFBB /* APICall.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APICall.swift; sourceTree = "<group>"; };
|
||||
84245C6E1FDDCD8C0074AFBB /* HTTPResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = HTTPResult.swift; path = RSWeb/HTTPResult.swift; sourceTree = "<group>"; };
|
||||
84261182200AE918004D89DD /* StringTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringTests.swift; sourceTree = "<group>"; };
|
||||
842ED2E61E12FB8A000CF738 /* HTTPRequestHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HTTPRequestHeader.swift; path = RSWeb/HTTPRequestHeader.swift; sourceTree = "<group>"; };
|
||||
842ED2E91E12FB91000CF738 /* HTTPMethod.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HTTPMethod.swift; path = RSWeb/HTTPMethod.swift; sourceTree = "<group>"; };
|
||||
842ED2EC1E12FB97000CF738 /* HTTPResponseCode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HTTPResponseCode.swift; path = RSWeb/HTTPResponseCode.swift; sourceTree = "<group>"; };
|
||||
@ -143,6 +151,8 @@
|
||||
842ED2D41E11FE8B000CF738 /* Constants */,
|
||||
849C09231E0CAD67006B03FA /* Downloading */,
|
||||
842ED30A1E12FBD8000CF738 /* URL+RSWeb.swift */,
|
||||
8409DB2B200AE4D700CE879E /* Dictionary+RSWeb.swift */,
|
||||
8409DB2F200AE81400CE879E /* String+RSWeb.swift */,
|
||||
842ED3131E12FBE7000CF738 /* MimeType.swift */,
|
||||
842ED3101E12FBE1000CF738 /* MacWebBrowser.swift */,
|
||||
84245C5C1FDC697A0074AFBB /* Credentials.swift */,
|
||||
@ -177,6 +187,8 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
849C08C41E0CAC86006B03FA /* RSWebTests.swift */,
|
||||
8409DB2D200AE74400CE879E /* DictionaryTests.swift */,
|
||||
84261182200AE918004D89DD /* StringTests.swift */,
|
||||
849C08C61E0CAC86006B03FA /* Info.plist */,
|
||||
);
|
||||
path = RSWebTests;
|
||||
@ -367,6 +379,7 @@
|
||||
842ED3081E12FBD2000CF738 /* URLRequest+RSWeb.swift in Sources */,
|
||||
842ED3051E12FBCC000CF738 /* NSMutableURLRequest+RSWeb.swift in Sources */,
|
||||
842ED2E71E12FB8A000CF738 /* HTTPRequestHeader.swift in Sources */,
|
||||
8409DB30200AE81400CE879E /* String+RSWeb.swift in Sources */,
|
||||
842ED3111E12FBE1000CF738 /* MacWebBrowser.swift in Sources */,
|
||||
842ED3141E12FBE7000CF738 /* MimeType.swift in Sources */,
|
||||
84245C5D1FDC697A0074AFBB /* Credentials.swift in Sources */,
|
||||
@ -376,6 +389,7 @@
|
||||
842ED2F91E12FBB5000CF738 /* DownloadProgress.swift in Sources */,
|
||||
842ED2EA1E12FB91000CF738 /* HTTPMethod.swift in Sources */,
|
||||
842ED3021E12FBC7000CF738 /* HTTPConditionalGetInfo.swift in Sources */,
|
||||
8409DB2C200AE4D700CE879E /* Dictionary+RSWeb.swift in Sources */,
|
||||
842ED2ED1E12FB97000CF738 /* HTTPResponseCode.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -385,6 +399,8 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
849C08C51E0CAC86006B03FA /* RSWebTests.swift in Sources */,
|
||||
84261183200AE918004D89DD /* StringTests.swift in Sources */,
|
||||
8409DB2E200AE74400CE879E /* DictionaryTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
46
Frameworks/RSWeb/RSWeb/Dictionary+RSWeb.swift
Normal file
46
Frameworks/RSWeb/RSWeb/Dictionary+RSWeb.swift
Normal file
@ -0,0 +1,46 @@
|
||||
//
|
||||
// Dictionary+RSWeb.swift
|
||||
// RSWeb
|
||||
//
|
||||
// Created by Brent Simmons on 1/13/18.
|
||||
// Copyright © 2018 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public extension Dictionary {
|
||||
|
||||
public func urlQueryString() -> String? {
|
||||
|
||||
// Turn a dictionary into string like foo=bar¶m2=some+thing
|
||||
// Return nil if empty dictionary.
|
||||
|
||||
if isEmpty {
|
||||
return nil
|
||||
}
|
||||
|
||||
var s = ""
|
||||
var numberAdded = 0
|
||||
for (key, value) in self {
|
||||
|
||||
guard let key = key as? String, let value = value as? String else {
|
||||
continue
|
||||
}
|
||||
guard let encodedKey = key.encodedForURLQuery(), let encodedValue = value.encodedForURLQuery() else {
|
||||
continue
|
||||
}
|
||||
|
||||
if numberAdded > 0 {
|
||||
s += "&"
|
||||
}
|
||||
s += "\(encodedKey)=\(encodedValue)"
|
||||
numberAdded += 1
|
||||
}
|
||||
|
||||
if numberAdded < 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
}
|
21
Frameworks/RSWeb/RSWeb/String+RSWeb.swift
Normal file
21
Frameworks/RSWeb/RSWeb/String+RSWeb.swift
Normal file
@ -0,0 +1,21 @@
|
||||
//
|
||||
// String+RSWeb.swift
|
||||
// RSWeb
|
||||
//
|
||||
// Created by Brent Simmons on 1/13/18.
|
||||
// Copyright © 2018 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public extension String {
|
||||
|
||||
public func encodedForURLQuery() -> String? {
|
||||
|
||||
let s = replacingOccurrences(of: " ", with: "+")
|
||||
guard let encodedString = s.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {
|
||||
return nil
|
||||
}
|
||||
return encodedString.replacingOccurrences(of: "&", with: "%38")
|
||||
}
|
||||
}
|
45
Frameworks/RSWeb/RSWebTests/DictionaryTests.swift
Normal file
45
Frameworks/RSWeb/RSWebTests/DictionaryTests.swift
Normal file
@ -0,0 +1,45 @@
|
||||
//
|
||||
// DictionaryTests.swift
|
||||
// RSWebTests
|
||||
//
|
||||
// Created by Brent Simmons on 1/13/18.
|
||||
// Copyright © 2018 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
class DictionaryTests: XCTestCase {
|
||||
|
||||
func testSimpleQueryString() {
|
||||
|
||||
let d = ["foo": "bar", "param1": "This is a value."]
|
||||
let s = d.urlQueryString()
|
||||
|
||||
XCTAssertTrue(s == "foo=bar¶m1=This+is+a+value." || s == "param1=This+is+a+value.&foo=bar")
|
||||
}
|
||||
|
||||
func testQueryStringWithAmpersand() {
|
||||
|
||||
let d = ["fo&o": "bar", "param1": "This is a&value."]
|
||||
let s = d.urlQueryString()
|
||||
|
||||
XCTAssertTrue(s == "fo%38o=bar¶m1=This+is+a%38value." || s == "param1=This+is+a%38value.&fo%38o=bar")
|
||||
}
|
||||
|
||||
func testQueryStringWithAccentedCharacters() {
|
||||
|
||||
let d = ["fée": "bør"]
|
||||
let s = d.urlQueryString()
|
||||
|
||||
XCTAssertTrue(s == "f%C3%A9e=b%C3%B8r")
|
||||
}
|
||||
|
||||
func testQueryStringWithEmoji() {
|
||||
|
||||
let d = ["🌴e": "bar🎩🌴"]
|
||||
let s = d.urlQueryString()
|
||||
|
||||
XCTAssertTrue(s == "%F0%9F%8C%B4e=bar%F0%9F%8E%A9%F0%9F%8C%B4")
|
||||
}
|
||||
|
||||
}
|
24
Frameworks/RSWeb/RSWebTests/StringTests.swift
Normal file
24
Frameworks/RSWeb/RSWebTests/StringTests.swift
Normal file
@ -0,0 +1,24 @@
|
||||
//
|
||||
// StringTests.swift
|
||||
// RSWebTests
|
||||
//
|
||||
// Created by Brent Simmons on 1/13/18.
|
||||
// Copyright © 2018 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
class StringTests: XCTestCase {
|
||||
|
||||
func testURLQueryEncoding() {
|
||||
|
||||
var s = "foo".encodedForURLQuery()
|
||||
XCTAssertEqual(s, "foo")
|
||||
|
||||
s = "foo bar".encodedForURLQuery()
|
||||
XCTAssertEqual(s, "foo+bar")
|
||||
|
||||
s = "foo bar &well".encodedForURLQuery()
|
||||
XCTAssertEqual(s, "foo+bar+%38well")
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user