Bug: Matcher in request body crashes at `PactSwift.PactBuilder.process(element)`
surpher opened this issue ยท 3 comments
๐ Environment
- Xcode: 12
- Platform: macOS libpact_mock_server_ffi.dylib and iOS using libpact_mock_server.a
- Version/Release: any
- Dependency manager: carthage
๐ฌ Description
When writing a pact test with a matcher in a request body, the PactSwift framework throws (and crashes) stating body contains non-encodable element. Crashes when setting up the interaction, specifically .withRequest(body: [...])
๐ฆถ Reproduction Steps
Steps to reproduce the behavior:
- Install rust
brew install rust
(required to compilelibpact_mock_server_ffi.dylib
at carthage update step) - Clone surpher/pact-swift-examples repo
- Change directory into
pact-swift-examples/Pact-macOS-Example
- Update
Cartfile
to point to `github "surpher/PactSwift" "tech/macos-dylib" - Run
carthage update
- Open
Pact-macOS-Example
project in Xcode - Run unit test:
testCreateUser_WithBodyThatMatchesAType()
๐ค Expected Results
Pact test runs and asserts the expected statusCode is 201
๐ฒ Actual Results
Pact test runs and crashes with Can not instantiate a Request with non-encodable body.
๐ณ Logs
2020-10-14 16:38:52.568071+1100 Pact-macOS-Example[34770:14528492] ApplePersistenceIgnoreState: Existing state will not be touched. New state will be written to (null)
2020-10-14 16:38:54.350601+1100 Pact-macOS-Example[34770:14528492] NSDocumentController Info.plist warning: The values of CFBundleTypeRole entries must be 'Editor', 'Viewer', 'None', or 'Shell'.
Test Suite 'Selected tests' started at 2020-10-14 16:38:54.721
Test Suite 'Pact-macOS-ExampleTests.xctest' started at 2020-10-14 16:38:54.722
Test Suite 'Pact_macOS_Example_CarthageTests' started at 2020-10-14 16:38:54.722
Test Case '-[Pact_macOS_ExampleTests.Pact_macOS_Example_CarthageTests testCreateUser_WithBodyThatMatchesAType]' started.
2020-10-14 16:38:54.797824+1100 Pact-macOS-Example[34770:14528985] [Arbitration] starting DTServiceHub child handshake.0 (send: 0x800b, receive: 0xab07)
2020-10-14 16:38:54.798057+1100 Pact-macOS-Example[34770:14528492] [Arbitration] attempting connection to singleton: 34747 with send port: 0x15103
2020-10-14 16:38:54.798301+1100 Pact-macOS-Example[34770:14528492] [Arbitration] handshake SUCCESSFUL (child: 34773 -> singleton: 34747)
2020-10-14 16:38:54.802973+1100 Pact-macOS-Example[34770:14528492] PactSwift: Error casting '{
name = "PactSwift.Matcher.SomethingLike(value: \"Julia\", rules: [[\"match\": PactSwift.AnyEncodable(_encode: (Function))]])";
}' to a JSON safe Type: String, Int, Double, Decimal, Bool, Dictionary<String, Encodable>, Array<Encodable>):
Fatal error: Can not instantiate a `Request` with non-encodable `body`.: file /Users/marko/Developer/pact-foundation/pact-swift-examples/Pact-macOS-Example/Carthage/Checkouts/PactSwift/Sources/Definitions/Request.swift, line 74
2020-10-14 16:38:54.803340+1100 Pact-macOS-Example[34770:14528492] Fatal error: Can not instantiate a `Request` with non-encodable `body`.: file /Users/marko/Developer/pact-foundation/pact-swift-examples/Pact-macOS-Example/Carthage/Checkouts/PactSwift/Sources/Definitions/Request.swift, line 74
(lldb)
๐ Stack Traces
n/a
๐ค Relationships
- Related PRs or Issues: pact-foundation/pact-reference#78
This is doing my head in. The request body
goes through the same processing as response body
, yet when setting matchers in a response body
, everything is all good and dandy. It's not when setting matchers in request body
. Odd.
Narrowed it down to body
only containing one dict element or more elements of only one type of matcher.
The following is OK
[
"name": Matcher.SomethingLike("Foo"),
"age": Matcher.IntegerLike(42)
]
The following is NOT OK
[
"name": Matcher.SomethingLike("Foo"),
"age": Matcher.SomethingLike(42)
]
// or just
[
"name": Matcher.SomethingLike("Foo")
]
A test case for these was not written at MockServiceTests
in PactSwift and PactBuilder is failing to process it properly. Oddly enough, PactBuilderTests do cover testing single Matchers and the tests pass.
It appears Swift doesn't consider any of PactSwift
's matchers that conform to MatcherRuleExpressible
as a type of MatcherRuleExpressible
if there's only one in the dictionary for body
in either Request
or Response
. Same if Request
or Response
contain multiple matchers (or example generators) of the same type.
This only happens if Response
or Request
is set post Interaction
init (eg: Interaction(...).withRequest(_:)
) If Response
and Request
with same body
as described above are passed into the Interaction
initializer (eg: Interaction(_:response:request:)
) then matchers that conform to MatcherRuleExpressible
are considered of type MatcherRuleExpressible
and all is hunky dory.
Fixed with 7c7c96c