From 0e3a7832ea331058ca40c296dc13e1d52bb66952 Mon Sep 17 00:00:00 2001 From: 417-72KI <417.72ki@gmail.com> Date: Wed, 4 Dec 2019 14:50:40 +0900 Subject: [PATCH 1/7] Add `hasFormBody` helper function --- .../OHHTTPStubsSwift/OHHTTPStubsSwift.swift | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/Sources/OHHTTPStubsSwift/OHHTTPStubsSwift.swift b/Sources/OHHTTPStubsSwift/OHHTTPStubsSwift.swift index 07069daa..cee26cc9 100644 --- a/Sources/OHHTTPStubsSwift/OHHTTPStubsSwift.swift +++ b/Sources/OHHTTPStubsSwift/OHHTTPStubsSwift.swift @@ -425,6 +425,42 @@ public func hasJsonBody(_ jsonObject: [AnyHashable : Any]) -> HTTPStubsTestBlock } #endif +/** + * Matcher testing that the `NSURLRequest` content-type is `application/x-www-form-urlencoded` and body contains a query parameter + * + * - Parameter queryItems: The array of query parameters to check the presence for + * + * - Returns: a matcher that returns true if the `NSURLRequest`'s body contains the same query items as the parameter value + */ +#if swift(>=3.0) +public func hasFormBody(_ queryItems: [URLQueryItem]) -> HTTPStubsTestBlock { + return { req in + guard + case "application/x-www-form-urlencoded" = req.value(forHTTPHeaderField: "Content-Type"), + let httpBody = req.ohhttpStubs_httpBody, + let query = String(data: httpBody, encoding: .utf8) + else { return false } + let items: [URLQueryItem] = { + var comps = URLComponents() + comps.percentEncodedQuery = query + return comps.queryItems ?? [] + }() + return items.sorted(by: { $0.name < $1.name }) == queryItems.sorted(by: { $0.name < $1.name }) + } +} + +/** + * Matcher testing that the `NSURLRequest` content-type is `application/x-www-form-urlencoded` and body contains a query parameter + * + * - Parameter queryItems: The variables of query parameters to check the presence for + * + * - Returns: a matcher that returns true if the `NSURLRequest`'s body contains the same query items as the parameter value + */ +public func hasFormBody(_ queryItems: URLQueryItem...) -> HTTPStubsTestBlock { + return hasFormBody(queryItems) +} +#endif + // MARK: Operators on HTTPStubsTestBlock /** From db454f006152e0e7e70cc20fb0277ce898aba147 Mon Sep 17 00:00:00 2001 From: 417-72KI <417.72ki@gmail.com> Date: Wed, 4 Dec 2019 14:53:21 +0900 Subject: [PATCH 2/7] replace positions --- Sources/OHHTTPStubsSwift/OHHTTPStubsSwift.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/OHHTTPStubsSwift/OHHTTPStubsSwift.swift b/Sources/OHHTTPStubsSwift/OHHTTPStubsSwift.swift index cee26cc9..c18d2d3b 100644 --- a/Sources/OHHTTPStubsSwift/OHHTTPStubsSwift.swift +++ b/Sources/OHHTTPStubsSwift/OHHTTPStubsSwift.swift @@ -425,6 +425,7 @@ public func hasJsonBody(_ jsonObject: [AnyHashable : Any]) -> HTTPStubsTestBlock } #endif +#if swift(>=3.0) /** * Matcher testing that the `NSURLRequest` content-type is `application/x-www-form-urlencoded` and body contains a query parameter * @@ -432,7 +433,6 @@ public func hasJsonBody(_ jsonObject: [AnyHashable : Any]) -> HTTPStubsTestBlock * * - Returns: a matcher that returns true if the `NSURLRequest`'s body contains the same query items as the parameter value */ -#if swift(>=3.0) public func hasFormBody(_ queryItems: [URLQueryItem]) -> HTTPStubsTestBlock { return { req in guard From ad6057cc1c1e3441c18e65c7a0ac7c5ae5341082 Mon Sep 17 00:00:00 2001 From: 417-72KI <417.72ki@gmail.com> Date: Wed, 4 Dec 2019 15:25:56 +0900 Subject: [PATCH 3/7] Add matcher with dictionary --- Sources/OHHTTPStubsSwift/OHHTTPStubsSwift.swift | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Sources/OHHTTPStubsSwift/OHHTTPStubsSwift.swift b/Sources/OHHTTPStubsSwift/OHHTTPStubsSwift.swift index c18d2d3b..8932d05a 100644 --- a/Sources/OHHTTPStubsSwift/OHHTTPStubsSwift.swift +++ b/Sources/OHHTTPStubsSwift/OHHTTPStubsSwift.swift @@ -426,6 +426,17 @@ public func hasJsonBody(_ jsonObject: [AnyHashable : Any]) -> HTTPStubsTestBlock #endif #if swift(>=3.0) +/** + * Matcher testing that the `NSURLRequest` content-type is `application/x-www-form-urlencoded` and body contains a query parameter + * + * - Parameter params: The dictionary of query parameters to check the presence for + * + * - Returns: a matcher that returns true if the `NSURLRequest`'s body contains the same query items as the parameter value + */ +public func hasFormBody(_ params: [String: String?]) -> HTTPStubsTestBlock { + return hasFormBody(params.map(URLQueryItem.init)) +} + /** * Matcher testing that the `NSURLRequest` content-type is `application/x-www-form-urlencoded` and body contains a query parameter * From 84c4dd1a4fa80fbcea390005d1782e8ba8505e19 Mon Sep 17 00:00:00 2001 From: 417-72KI <417.72ki@gmail.com> Date: Wed, 4 Dec 2019 16:11:23 +0900 Subject: [PATCH 4/7] Add test cases --- .../SwiftHelpersTests.swift | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/Tests/OHHTTPStubsSwiftTests/SwiftHelpersTests.swift b/Tests/OHHTTPStubsSwiftTests/SwiftHelpersTests.swift index 9541e9cf..91aadbbc 100644 --- a/Tests/OHHTTPStubsSwiftTests/SwiftHelpersTests.swift +++ b/Tests/OHHTTPStubsSwiftTests/SwiftHelpersTests.swift @@ -522,6 +522,51 @@ class SwiftHelpersTests : XCTestCase { } #endif +#if swift(>=3.0) + func testHasFormBodyIsTrue() { + func assertMatchesFormBody(_ formBody: String, _ expectedKeyValues: [String: String?], file: StaticString = #file, line: UInt = #line) { + var req = URLRequest(url: URL(string: "foo://bar")!) + req.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") + req.httpBody = formBody.data(using: .utf8) + XCTAssertTrue(hasFormBody(expectedKeyValues)(req), file: file, line: line) + } + + // Exact match + assertMatchesFormBody("foo=bar&baz=42&qux=true", ["foo": "bar", "baz": "42", "qux": "true"]) + // Changed attribute order + assertMatchesFormBody("qux=true&foo=bar&baz=42", ["foo": "bar", "baz": "42", "qux": "true"]) + // Contains key with no value + assertMatchesFormBody("foo=bar&baz&qux=42", ["foo": "bar", "baz": nil, "qux": "42"]) + // Contains key with empty value + assertMatchesFormBody("foo=bar&baz=&qux=42", ["foo": "bar", "baz": "", "qux": "42"]) + // Contains escaped character + assertMatchesFormBody("foo=bar%40baz", ["foo": "bar@baz"]) + } +#endif + +#if swift(>=3.0) + func testHasFormBodyIsFalse() { + func assertNotMatchesFormBody(_ formBody: String, _ expectedKeyValues: [String: String?], file: StaticString = #file, line: UInt = #line) { + var req = URLRequest(url: URL(string: "foo://bar")!) + req.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") + req.httpBody = formBody.data(using: .utf8) + XCTAssertFalse(hasFormBody(expectedKeyValues)(req), file: file, line: line) + } + // Changed value + assertNotMatchesFormBody("foo=bar&baz=40", ["foo": "bar", "baz": "42"]) + // Changed key + assertNotMatchesFormBody("foo=bar&qux=42", ["foo": "bar", "baz": "42"]) + // Missing attribute + assertNotMatchesFormBody("foo=bar&baz=42&qux=true", ["foo": "bar", "baz": "42"]) + // Extraneous attribute + assertNotMatchesFormBody("foo=bar&baz=42", ["foo": "bar", "baz": "42", "qux": "true"]) + // Missing value + assertNotMatchesFormBody("foo=&bar=baz", ["foo": nil, "bar": "baz"]) + // Extraneous value + assertNotMatchesFormBody("foo&bar=baz", ["foo": "", "baz": "42"]) + } +#endif + let sampleURLs = [ // Absolute URLs "scheme:", From 45fa1a5d08dc693a1c7df7484b58ff9c343263b4 Mon Sep 17 00:00:00 2001 From: 417-72KI <417.72ki@gmail.com> Date: Wed, 4 Dec 2019 16:18:46 +0900 Subject: [PATCH 5/7] Update CHANGELOG --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ceff0b3..15f8434a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # OHHTTPStubs — CHANGELOG +## Master + +* Added `hasFormBody(_:)` matcher. +[@417-72KI](https://github.com/417-72KI) + ## [9.0.0](https://github.com/AliSoftware/OHHTTPStubs/releases/tag/9.0.0) * Added support for Swift Package Manager and dropped OH from all class names. From 1f5ddf0cc5d2e4a0503073cf5dc76a5ed0b6d8c9 Mon Sep 17 00:00:00 2001 From: 417-72KI <417.72ki@gmail.com> Date: Wed, 4 Dec 2019 17:04:00 +0900 Subject: [PATCH 6/7] Fix pattern matching as `Optional` --- Sources/OHHTTPStubsSwift/OHHTTPStubsSwift.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/OHHTTPStubsSwift/OHHTTPStubsSwift.swift b/Sources/OHHTTPStubsSwift/OHHTTPStubsSwift.swift index 8932d05a..87967e42 100644 --- a/Sources/OHHTTPStubsSwift/OHHTTPStubsSwift.swift +++ b/Sources/OHHTTPStubsSwift/OHHTTPStubsSwift.swift @@ -447,7 +447,7 @@ public func hasFormBody(_ params: [String: String?]) -> HTTPStubsTestBlock { public func hasFormBody(_ queryItems: [URLQueryItem]) -> HTTPStubsTestBlock { return { req in guard - case "application/x-www-form-urlencoded" = req.value(forHTTPHeaderField: "Content-Type"), + case "application/x-www-form-urlencoded"? = req.value(forHTTPHeaderField: "Content-Type"), let httpBody = req.ohhttpStubs_httpBody, let query = String(data: httpBody, encoding: .utf8) else { return false } From 366952520a63a29ddfe6a158b98c5842b546892b Mon Sep 17 00:00:00 2001 From: 417-72KI <417.72ki@gmail.com> Date: Wed, 4 Dec 2019 17:14:00 +0900 Subject: [PATCH 7/7] Add @available --- Sources/OHHTTPStubsSwift/OHHTTPStubsSwift.swift | 3 +++ Tests/OHHTTPStubsSwiftTests/SwiftHelpersTests.swift | 2 ++ 2 files changed, 5 insertions(+) diff --git a/Sources/OHHTTPStubsSwift/OHHTTPStubsSwift.swift b/Sources/OHHTTPStubsSwift/OHHTTPStubsSwift.swift index 87967e42..8a56aee9 100644 --- a/Sources/OHHTTPStubsSwift/OHHTTPStubsSwift.swift +++ b/Sources/OHHTTPStubsSwift/OHHTTPStubsSwift.swift @@ -433,6 +433,7 @@ public func hasJsonBody(_ jsonObject: [AnyHashable : Any]) -> HTTPStubsTestBlock * * - Returns: a matcher that returns true if the `NSURLRequest`'s body contains the same query items as the parameter value */ +@available(iOS 8.0, OSX 10.10, *) public func hasFormBody(_ params: [String: String?]) -> HTTPStubsTestBlock { return hasFormBody(params.map(URLQueryItem.init)) } @@ -444,6 +445,7 @@ public func hasFormBody(_ params: [String: String?]) -> HTTPStubsTestBlock { * * - Returns: a matcher that returns true if the `NSURLRequest`'s body contains the same query items as the parameter value */ +@available(iOS 8.0, OSX 10.10, *) public func hasFormBody(_ queryItems: [URLQueryItem]) -> HTTPStubsTestBlock { return { req in guard @@ -467,6 +469,7 @@ public func hasFormBody(_ queryItems: [URLQueryItem]) -> HTTPStubsTestBlock { * * - Returns: a matcher that returns true if the `NSURLRequest`'s body contains the same query items as the parameter value */ +@available(iOS 8.0, OSX 10.10, *) public func hasFormBody(_ queryItems: URLQueryItem...) -> HTTPStubsTestBlock { return hasFormBody(queryItems) } diff --git a/Tests/OHHTTPStubsSwiftTests/SwiftHelpersTests.swift b/Tests/OHHTTPStubsSwiftTests/SwiftHelpersTests.swift index 91aadbbc..b2791491 100644 --- a/Tests/OHHTTPStubsSwiftTests/SwiftHelpersTests.swift +++ b/Tests/OHHTTPStubsSwiftTests/SwiftHelpersTests.swift @@ -523,6 +523,7 @@ class SwiftHelpersTests : XCTestCase { #endif #if swift(>=3.0) + @available(iOS 8.0, OSX 10.10, *) func testHasFormBodyIsTrue() { func assertMatchesFormBody(_ formBody: String, _ expectedKeyValues: [String: String?], file: StaticString = #file, line: UInt = #line) { var req = URLRequest(url: URL(string: "foo://bar")!) @@ -545,6 +546,7 @@ class SwiftHelpersTests : XCTestCase { #endif #if swift(>=3.0) + @available(iOS 8.0, OSX 10.10, *) func testHasFormBodyIsFalse() { func assertNotMatchesFormBody(_ formBody: String, _ expectedKeyValues: [String: String?], file: StaticString = #file, line: UInt = #line) { var req = URLRequest(url: URL(string: "foo://bar")!)