From 3e3d09dc8a3a71af1130e0032dbf988f2dc7ff40 Mon Sep 17 00:00:00 2001 From: Ilya Puchka Date: Thu, 9 Aug 2018 15:15:47 +0100 Subject: [PATCH 1/2] introduce CodableMatchedStringRepresentable protocol --- Example/Tests/Features/ExampleFeatures.swift | 5 +++++ .../Tests/StepDefinitions/SanitySteps.swift | 8 ++++++++ Pod/Core/MatchedStringRepresentable.swift | 19 +++++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/Example/Tests/Features/ExampleFeatures.swift b/Example/Tests/Features/ExampleFeatures.swift index 2d2b039..922b9e3 100644 --- a/Example/Tests/Features/ExampleFeatures.swift +++ b/Example/Tests/Features/ExampleFeatures.swift @@ -81,4 +81,9 @@ final class ExampleFeatures: XCTestCase { func testStepAnchorMatching() { Given("This is a substring") } + + func testCodableMatches() { + let person = Person(name: "Nick") + Given("This is Nick \(person)") + } } diff --git a/Example/Tests/StepDefinitions/SanitySteps.swift b/Example/Tests/StepDefinitions/SanitySteps.swift index 168cf94..0c0e377 100644 --- a/Example/Tests/StepDefinitions/SanitySteps.swift +++ b/Example/Tests/StepDefinitions/SanitySteps.swift @@ -122,5 +122,13 @@ final class SanitySteps: StepDefiner { step("This is a substring") { // This step should match instead of the one above, even though the other one is defined first } + + step("This is Nick (.+)") { (match: Person) in + XCTAssertEqual(match.name, "Nick") + } } } + +struct Person: CodableMatchedStringRepresentable { + let name: String +} diff --git a/Pod/Core/MatchedStringRepresentable.swift b/Pod/Core/MatchedStringRepresentable.swift index a3d16b8..bdf2361 100644 --- a/Pod/Core/MatchedStringRepresentable.swift +++ b/Pod/Core/MatchedStringRepresentable.swift @@ -38,3 +38,22 @@ extension Int: MatchedStringRepresentable { self.init(match, radix: 10) } } + +public protocol CodableMatchedStringRepresentable: Codable, CustomStringConvertible, MatchedStringRepresentable {} + +extension CodableMatchedStringRepresentable { + public init?(fromMatch match: String) { + let decoder = JSONDecoder() + guard let data = match.data(using: .utf8), + let decoded = try? decoder.decode(Self.self, from: data) else { + return nil + } + self = decoded + } + + public var description: String { + let encoder = JSONEncoder() + let encoded = try! encoder.encode(self) + return String(data: encoded, encoding: .utf8)! + } +} From 39c8182a055c70cea893fa57c8da80292cf624c2 Mon Sep 17 00:00:00 2001 From: Ilya Puchka Date: Sat, 11 Aug 2018 12:34:25 +0100 Subject: [PATCH 2/2] Update README.md --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.md b/README.md index 0cbef41..25d9ef5 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,28 @@ step("This value should be between ([0-9]*) and ([0-9]*)") { (match1: String, ma } ``` +### Captured value types + +In step definition with captured values you can use any type conforming to `MatchedStringRepresentable`. `String`, `Double`, `Int` and `Bool` types already conform to this protocol. You can also match your custom types by conforming them to `CodableMatchedStringRepresentable`. This requires type to implement only `Codable` protocol methods, `MatchedStringRepresentable` implementation is provided by the library. + +```swift +struct Person: Codable, Equatable { + let name: String +} +extension Person: CodableMatchedStringRepresentable { +} + +step("User is logged in as (.+)") { (match: Person) in + let loggedInUser = ... + XCTAssertEqual(loggedInUser, match) +} + +func testLoggedInUser() { + let nick = Person(name: "Nick") + Given("User is loggeed in as \(nick)") +} +``` + ### Examples and feature outlines If you want to test the same situation with a set of data, Gherkin allows you to specify example input for your tests. We used this all over our previous tests so we needed to deal with it here too!