From dd6072671a01fa640827a3d4d2f4a72300a012d1 Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Sat, 24 Feb 2024 02:24:43 +0530 Subject: [PATCH 01/34] Matchers v1 --- src/pact_matchers.erl | 73 ++++++++++++++++++++++++++++++++++ test/pact_end_to_end_SUITE.erl | 17 +++++++- 2 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 src/pact_matchers.erl diff --git a/src/pact_matchers.erl b/src/pact_matchers.erl new file mode 100644 index 0000000..75bd95a --- /dev/null +++ b/src/pact_matchers.erl @@ -0,0 +1,73 @@ +-module(pact_matchers). + + +-export([ + integer_or_identifier/0, + integer_or_identifier/1, + float/0, + float/1, + string/0, + string/1, + bool/0, + bool/1 +]). + + +-export([ + like/1, + each_like/1, + each_key/2, + regex_match/2 +]). + +-spec like(binary() | boolean() | number()) -> thoas:json_term(). +like(Term) -> + [ + {<<"value">>, Term}, + {<<"pact:matcher:type">>, <<"type">>} + ]. + +-spec each_like(binary() | boolean() | number()) -> thoas:json_term(). +each_like(Term) -> + [ + {<<"value">>, [Term]}, + {<<"pact:matcher:type">>, <<"type">>} + ]. + +-spec regex_match(binary() | boolean() | number(), binary()) -> thoas:json_term(). +regex_match(Value, Regex) -> + [ + {<<"value">>, Value}, + {<<"pact:matcher:type">>, <<"regex">>}, + {<<"regex">>, Regex} + ]. + +-spec each_key(binary() | boolean() | number(), binary()) -> thoas:json_term(). +each_key(Value, Regex) -> + [ + {<<"value">>, Value}, + {<<"pact:matcher:type">>, <<"eachKey">>}, + {<<"rules">>, [ + ?MODULE:regex_match(<<"">>, Regex) + ]} + ]. + +integer_or_identifier() -> + ?MODULE:integer_or_identifier(1). +integer_or_identifier(Value) -> + like(Value). + +float() -> + ?MODULE:float(1.0). +float(Value) -> + like(Value). + +string() -> + ?MODULE:string(<<"">>). +string(Value) -> + like(Value). + +bool() -> + ?MODULE:bool(true). +bool(Value) -> + like(Value). diff --git a/test/pact_end_to_end_SUITE.erl b/test/pact_end_to_end_SUITE.erl index ed63099..e4178a2 100644 --- a/test/pact_end_to_end_SUITE.erl +++ b/test/pact_end_to_end_SUITE.erl @@ -104,7 +104,20 @@ get_animal_failure(Config) -> create_animal(Config) -> PactRef = ?config(pact_ref, Config), - AnimalObject = #{<<"name">> => <<"Max">>, <<"type">> => <<"dog">>}, + AnimalPactObject = [ + {<<"name">>, pact_matchers:string(<<"Max">>)}, + {<<"type">>, pact_matchers:string(<<"dog">>)}, + {<<"age">>, pact_matchers:integer_or_identifier(3)}, + {<<"gender">>, pact_matchers:regex_match(<<"male">>, <<"(male|female)">>)}, + {<<"carnivorous">>, pact_matchers:bool(true)} + ], + AnimalObject = [ + {<<"name">>, <<"Max">>}, + {<<"type">>, <<"dog">>}, + {<<"age">>, 3}, + {<<"gender">>, <<"male">>}, + {<<"carnivorous">>, true} + ], {ok, Port} = pact:interaction(PactRef, #{ upon_receiving => <<"a request to create an animal: Max">>, @@ -114,7 +127,7 @@ create_animal(Config) -> headers => #{ <<"Content-Type">> => <<"application/json">> }, - body => thoas:encode(AnimalObject) + body => thoas:encode(AnimalPactObject) }, will_respond_with => #{ status => 201 From 750e1b321e40508f7ad54913beee5555c179bb72 Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Sat, 24 Feb 2024 02:26:52 +0530 Subject: [PATCH 02/34] Added formatting --- src/pact_matchers.erl | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/pact_matchers.erl b/src/pact_matchers.erl index 75bd95a..95bca1d 100644 --- a/src/pact_matchers.erl +++ b/src/pact_matchers.erl @@ -1,6 +1,5 @@ -module(pact_matchers). - -export([ integer_or_identifier/0, integer_or_identifier/1, @@ -12,7 +11,6 @@ bool/1 ]). - -export([ like/1, each_like/1, @@ -20,21 +18,21 @@ regex_match/2 ]). --spec like(binary() | boolean() | number()) -> thoas:json_term(). +-spec like(binary() | boolean() | number()) -> thoas:json_term(). like(Term) -> [ {<<"value">>, Term}, {<<"pact:matcher:type">>, <<"type">>} ]. --spec each_like(binary() | boolean() | number()) -> thoas:json_term(). +-spec each_like(binary() | boolean() | number()) -> thoas:json_term(). each_like(Term) -> [ {<<"value">>, [Term]}, {<<"pact:matcher:type">>, <<"type">>} ]. --spec regex_match(binary() | boolean() | number(), binary()) -> thoas:json_term(). +-spec regex_match(binary() | boolean() | number(), binary()) -> thoas:json_term(). regex_match(Value, Regex) -> [ {<<"value">>, Value}, @@ -42,7 +40,7 @@ regex_match(Value, Regex) -> {<<"regex">>, Regex} ]. --spec each_key(binary() | boolean() | number(), binary()) -> thoas:json_term(). +-spec each_key(binary() | boolean() | number(), binary()) -> thoas:json_term(). each_key(Value, Regex) -> [ {<<"value">>, Value}, @@ -55,7 +53,7 @@ each_key(Value, Regex) -> integer_or_identifier() -> ?MODULE:integer_or_identifier(1). integer_or_identifier(Value) -> - like(Value). + like(Value). float() -> ?MODULE:float(1.0). From 57ff83a80997ab4ede9d8ef0f83d048b97fb9c9f Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Sat, 24 Feb 2024 02:30:45 +0530 Subject: [PATCH 03/34] More tests --- test/pact_end_to_end_SUITE.erl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/pact_end_to_end_SUITE.erl b/test/pact_end_to_end_SUITE.erl index e4178a2..a300c57 100644 --- a/test/pact_end_to_end_SUITE.erl +++ b/test/pact_end_to_end_SUITE.erl @@ -109,14 +109,16 @@ create_animal(Config) -> {<<"type">>, pact_matchers:string(<<"dog">>)}, {<<"age">>, pact_matchers:integer_or_identifier(3)}, {<<"gender">>, pact_matchers:regex_match(<<"male">>, <<"(male|female)">>)}, - {<<"carnivorous">>, pact_matchers:bool(true)} + {<<"carnivorous">>, pact_matchers:bool(true)}, + {<<"siblings">>, pact_matchers:each_like(<<"lola">>)} ], AnimalObject = [ {<<"name">>, <<"Max">>}, {<<"type">>, <<"dog">>}, {<<"age">>, 3}, {<<"gender">>, <<"male">>}, - {<<"carnivorous">>, true} + {<<"carnivorous">>, true}, + {<<"siblings">>, [<<"lola">>, <<"mary">>]} ], {ok, Port} = pact:interaction(PactRef, #{ From 663089b166da0efdfc14611cdf7e38375f5095bb Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Sat, 24 Feb 2024 03:07:32 +0530 Subject: [PATCH 04/34] updated readme and changelog --- CHANGELOG.md | 2 ++ README.md | 23 +++++++++++++++++++++-- src/pact_matchers.erl | 24 ++++++++++++++++++++---- 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 451124d..230cd1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Added - Introduced ability to add params inside given in pact interaction +- Introduced basic pact matchers + ## [0.2.2] - 2023-11-03 diff --git a/README.md b/README.md index 537d3d6..c8a4dd4 100644 --- a/README.md +++ b/README.md @@ -81,8 +81,27 @@ pact:cleanup(PactRef). Matching request path and request/response headers, and body values ----- -Easy-to-use matchers module is not implemented yet, but matchers can be used by manually specifying a matcher string. -Check the possible values here: https://github.com/pact-foundation/pact-reference/blob/master/rust/pact_ffi/IntegrationJson.md +```erlang +%% Alternatively, you can also match things inside each request/response +pact:interaction(PactRef, + #{ + upon_receiving => <<"a request to create an animal: Lazgo">>, + with_request => #{ + method => <<"POST">>, + path => <<"/animals">>, + headers => #{ + <<"Content-Type">> => <<"application/json">> + }, + body => thoas:encode( + {<<"name">>, pact_matchers:string(<<"Lazgo">>)}, + {<<"type">>, pact_matchers:string(<<"dog">>)} + ) + }, + will_respond_with => #{ + status => 201 + } + }) +``` Release Checklist ----- diff --git a/src/pact_matchers.erl b/src/pact_matchers.erl index 95bca1d..3eeb9ac 100644 --- a/src/pact_matchers.erl +++ b/src/pact_matchers.erl @@ -18,21 +18,24 @@ regex_match/2 ]). --spec like(binary() | boolean() | number()) -> thoas:json_term(). +%% @doc function for matching with type of the given term +-spec like(binary() | boolean() | number()) -> list(). like(Term) -> [ {<<"value">>, Term}, {<<"pact:matcher:type">>, <<"type">>} ]. --spec each_like(binary() | boolean() | number()) -> thoas:json_term(). +%% @doc function for matching each entity inside a list with type of given term +-spec each_like(binary() | boolean() | number()) -> list(). each_like(Term) -> [ {<<"value">>, [Term]}, {<<"pact:matcher:type">>, <<"type">>} ]. --spec regex_match(binary() | boolean() | number(), binary()) -> thoas:json_term(). +%% @doc function for matching with regex +-spec regex_match(binary() | boolean() | number(), binary()) -> list(). regex_match(Value, Regex) -> [ {<<"value">>, Value}, @@ -40,7 +43,8 @@ regex_match(Value, Regex) -> {<<"regex">>, Regex} ]. --spec each_key(binary() | boolean() | number(), binary()) -> thoas:json_term(). +%% @doc function for matching each key inside a map with regex +-spec each_key(binary() | boolean() | number(), binary()) -> list(). each_key(Value, Regex) -> [ {<<"value">>, Value}, @@ -50,22 +54,34 @@ each_key(Value, Regex) -> ]} ]. +%% @doc function for matching integer +-spec integer_or_identifier() -> list(). integer_or_identifier() -> ?MODULE:integer_or_identifier(1). +-spec integer_or_identifier(integer()) -> list(). integer_or_identifier(Value) -> like(Value). +%% @doc function for matching float +-spec float() -> list(). float() -> ?MODULE:float(1.0). +-spec float(float()) -> list(). float(Value) -> like(Value). +%% @doc function for matching string +-spec string() -> list(). string() -> ?MODULE:string(<<"">>). +-spec string(string()) -> list(). string(Value) -> like(Value). +%% @doc function for matching boolean +-spec bool() -> list(). bool() -> ?MODULE:bool(true). +-spec bool(boolean()) -> list(). bool(Value) -> like(Value). From 37ed0a3a5b074fea0581c30a832e6d93f6cd66bb Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Sat, 24 Feb 2024 03:09:44 +0530 Subject: [PATCH 05/34] Minor fix --- src/pact_matchers.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pact_matchers.erl b/src/pact_matchers.erl index 3eeb9ac..1e59593 100644 --- a/src/pact_matchers.erl +++ b/src/pact_matchers.erl @@ -74,7 +74,7 @@ float(Value) -> -spec string() -> list(). string() -> ?MODULE:string(<<"">>). --spec string(string()) -> list(). +-spec string(binary()) -> list(). string(Value) -> like(Value). From 5382e2f77fc2335dce1edf7b8b787cc4641f4533 Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Sat, 24 Feb 2024 08:31:50 +0530 Subject: [PATCH 06/34] Added more tests --- test/pact_end_to_end_SUITE.erl | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/test/pact_end_to_end_SUITE.erl b/test/pact_end_to_end_SUITE.erl index a300c57..e543661 100644 --- a/test/pact_end_to_end_SUITE.erl +++ b/test/pact_end_to_end_SUITE.erl @@ -107,18 +107,24 @@ create_animal(Config) -> AnimalPactObject = [ {<<"name">>, pact_matchers:string(<<"Max">>)}, {<<"type">>, pact_matchers:string(<<"dog">>)}, - {<<"age">>, pact_matchers:integer_or_identifier(3)}, + {<<"age">>, pact_matchers:integer_or_identifier()}, + {<<"nickname">>, pact_matchers:string()}, + {<<"weight_kg">>, pact_matchers:float()}, {<<"gender">>, pact_matchers:regex_match(<<"male">>, <<"(male|female)">>)}, - {<<"carnivorous">>, pact_matchers:bool(true)}, - {<<"siblings">>, pact_matchers:each_like(<<"lola">>)} + {<<"carnivorous">>, pact_matchers:bool()}, + {<<"siblings">>, pact_matchers:each_like(<<"lola">>)}, + {<<"attributes">>, pact_matchers:each_key([{<<"happy">>, true}], <<"(happy|ferocious)">>)} ], AnimalObject = [ {<<"name">>, <<"Max">>}, {<<"type">>, <<"dog">>}, {<<"age">>, 3}, + {<<"nickname">>, <<"lazgo">>}, + {<<"weight_kg">>, 10.0}, {<<"gender">>, <<"male">>}, {<<"carnivorous">>, true}, - {<<"siblings">>, [<<"lola">>, <<"mary">>]} + {<<"siblings">>, [<<"lola">>, <<"mary">>]}, + {<<"attributes">>, [{<<"ferocious">>, false}]} ], {ok, Port} = pact:interaction(PactRef, #{ From 45da2c18968abcb1f6d8103b7edfa864ef6aac79 Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Thu, 7 Mar 2024 19:58:58 +0530 Subject: [PATCH 07/34] Review comments --- src/pact.erl | 28 +++++++- src/pact_consumer_http.erl | 12 ++-- src/pact_matchers.erl | 121 +++++++++++++-------------------- test/pact_end_to_end_SUITE.erl | 30 ++++---- 4 files changed, 94 insertions(+), 97 deletions(-) diff --git a/src/pact.erl b/src/pact.erl index 6d8f50b..567ba60 100644 --- a/src/pact.erl +++ b/src/pact.erl @@ -6,7 +6,11 @@ verify/1, write/1, write/2, - cleanup/1 + cleanup/1, + like/1, + each_like/1, + regex_match/2, + each_key/2, ]). -type consumer() :: binary(). @@ -47,3 +51,25 @@ write(PactPid, Path) -> -spec cleanup(pact_pid()) -> ok. cleanup(PactPid) -> pact_consumer:cleanup(PactPid). + +%% @doc Matches all the child objects (and their child objects etc.) +%% Matched according to their types +-spec like(any()) -> map(). +like(Term) -> + pact_matchers:like(Term). + +%% @doc Asserts the Term is an array type that consists of elements +%% Like the one passed in +-spec like(any()) -> map(). +each_like(Term) -> + pact_matchers:each_like(Term). + +%% @doc Asserts the value should match the given regular expression +-spec like(binary() | boolean() | number(), binary()) -> map(). +regex_match(Value, Regex) -> + pact_matchers:regex_match(Value, Regex). + +%% @doc Asserts that each key of Value should match the given regular expression +-spec like(binary() | boolean() | number(), binary()) -> map(). +each_key(Value, Regex) -> + pact_matchers:each_key(Value, Regex). diff --git a/src/pact_consumer_http.erl b/src/pact_consumer_http.erl index ebd96ae..b55c5b5 100644 --- a/src/pact_consumer_http.erl +++ b/src/pact_consumer_http.erl @@ -81,13 +81,13 @@ start_mock_server(PactPid, PactRef, Host, Port, InteractionPart) -> insert_request_details(InteractionRef, RequestDetails) -> ReqMethod = maps:get(method, RequestDetails), ReqPath = maps:get(path, RequestDetails), - pactffi_nif:with_request(InteractionRef, ReqMethod, ReqPath), + pactffi_nif:with_request(InteractionRef, ReqMethod, thoas:encode(ReqPath)), ReqHeaders = maps:get(headers, RequestDetails, #{}), ContentType = get_content_type(ReqHeaders), maps:fold( fun(Key, Value, _Acc) -> %% FIXME: 4th parameter is Index.. need to increment - pactffi_nif:with_header_v2(InteractionRef, 0, Key, 0, Value) + pactffi_nif:with_header_v2(InteractionRef, 0, Key, 0, thoas:encode(Value)) end, ok, ReqHeaders @@ -95,7 +95,7 @@ insert_request_details(InteractionRef, RequestDetails) -> ReqBody = maps:get(body, RequestDetails, undefined), case ReqBody of undefined -> ok; - _ -> pactffi_nif:with_body(InteractionRef, 0, ContentType, ReqBody) + _ -> pactffi_nif:with_body(InteractionRef, 0, ContentType, thoas:encode(ReqBody)) end, ReqQueryParams = maps:get(query_params, RequestDetails, undefined), case ReqQueryParams of @@ -105,7 +105,7 @@ insert_request_details(InteractionRef, RequestDetails) -> maps:fold( fun(Key, Value, _Acc) -> %% FIXME: 3rd parameter is Index.. need to increment - pactffi_nif:with_query_parameter_v2(InteractionRef, Key, 0, Value) + pactffi_nif:with_query_parameter_v2(InteractionRef, Key, 0, thoas:encode(Value)) end, ok, ReqQueryParams @@ -125,7 +125,7 @@ insert_response_details(InteractionRef, ResponseDetails) -> maps:fold( fun(Key, Value, _Acc) -> %% FIXME: 4th parameter is Index.. need to increment - pactffi_nif:with_header_v2(InteractionRef, 1, Key, 0, Value) + pactffi_nif:with_header_v2(InteractionRef, 1, Key, 0, thoas:encode(Value)) end, ok, ResHeaders @@ -133,7 +133,7 @@ insert_response_details(InteractionRef, ResponseDetails) -> ResBody = maps:get(body, ResponseDetails, undefined), case ResBody of undefined -> ok; - _ -> pactffi_nif:with_body(InteractionRef, 1, ContentType, ResBody) + _ -> pactffi_nif:with_body(InteractionRef, 1, ContentType, thoas:encode(ResBody)) end, ok. diff --git a/src/pact_matchers.erl b/src/pact_matchers.erl index 1e59593..472eefe 100644 --- a/src/pact_matchers.erl +++ b/src/pact_matchers.erl @@ -1,16 +1,5 @@ -module(pact_matchers). --export([ - integer_or_identifier/0, - integer_or_identifier/1, - float/0, - float/1, - string/0, - string/1, - bool/0, - bool/1 -]). - -export([ like/1, each_like/1, @@ -18,70 +7,52 @@ regex_match/2 ]). -%% @doc function for matching with type of the given term --spec like(binary() | boolean() | number()) -> list(). -like(Term) -> - [ - {<<"value">>, Term}, - {<<"pact:matcher:type">>, <<"type">>} - ]. - -%% @doc function for matching each entity inside a list with type of given term --spec each_like(binary() | boolean() | number()) -> list(). -each_like(Term) -> - [ - {<<"value">>, [Term]}, - {<<"pact:matcher:type">>, <<"type">>} - ]. - -%% @doc function for matching with regex --spec regex_match(binary() | boolean() | number(), binary()) -> list(). +%% @doc Function for matching with type of the given term +-spec like(binary() | boolean() | number() | map()) -> map(). +like(Term) when (is_integer(Term) orelse is_binary(Term) orelse is_boolean(Term)) -> + #{ + <<"value">> => Term, + <<"pact:matcher:type">> => <<"type">> + }; +like(Term) when (is_map(Term)) -> + maps:map( + fun(Key, InitValue) -> + ?MODULE:like(InitValue) + end, + Term + ). + +%% @doc Function for matching each entity inside a list with type of given term +-spec each_like(binary() | boolean() | number() | map()) -> map(). +each_like(Term) when (is_integer(Term) orelse is_binary(Term) orelse is_boolean(Term)) -> + #{ + <<"value">> => [Term], + <<"pact:matcher:type">> => <<"type">> + }; +each_like(Term) when (is_map(Term)) -> + maps:map( + fun(Key, InitValue) -> + ?MODULE:each_like(InitValue) + end, + Term + ). + +%% @doc Function for matching with regex +-spec regex_match(binary() | boolean() | number(), binary()) -> map(). regex_match(Value, Regex) -> - [ - {<<"value">>, Value}, - {<<"pact:matcher:type">>, <<"regex">>}, - {<<"regex">>, Regex} - ]. - -%% @doc function for matching each key inside a map with regex --spec each_key(binary() | boolean() | number(), binary()) -> list(). + #{ + <<"value">> => Value, + <<"pact:matcher:type">> => <<"regex">>, + <<"regex">> => Regex + }. + +%% @doc Function for matching each key inside a map with regex +-spec each_key(binary() | boolean() | number(), binary()) -> map(). each_key(Value, Regex) -> - [ - {<<"value">>, Value}, - {<<"pact:matcher:type">>, <<"eachKey">>}, - {<<"rules">>, [ + #{ + <<"value">> => Value, + <<"pact:matcher:type">> => <<"eachKey">>, + <<"rules">> => [ ?MODULE:regex_match(<<"">>, Regex) - ]} - ]. - -%% @doc function for matching integer --spec integer_or_identifier() -> list(). -integer_or_identifier() -> - ?MODULE:integer_or_identifier(1). --spec integer_or_identifier(integer()) -> list(). -integer_or_identifier(Value) -> - like(Value). - -%% @doc function for matching float --spec float() -> list(). -float() -> - ?MODULE:float(1.0). --spec float(float()) -> list(). -float(Value) -> - like(Value). - -%% @doc function for matching string --spec string() -> list(). -string() -> - ?MODULE:string(<<"">>). --spec string(binary()) -> list(). -string(Value) -> - like(Value). - -%% @doc function for matching boolean --spec bool() -> list(). -bool() -> - ?MODULE:bool(true). --spec bool(boolean()) -> list(). -bool(Value) -> - like(Value). + ] + }. diff --git a/test/pact_end_to_end_SUITE.erl b/test/pact_end_to_end_SUITE.erl index e543661..9736ee4 100644 --- a/test/pact_end_to_end_SUITE.erl +++ b/test/pact_end_to_end_SUITE.erl @@ -51,7 +51,7 @@ get_animal_success(Config) -> headers => #{ <<"Content-Type">> => <<"application/json">> }, - body => thoas:encode(AnimalObject) + body => AnimalObject } }), ?assertMatch({ok, AnimalObject}, animal_service_interface:get_animal(Port, "Mary")), @@ -95,7 +95,7 @@ get_animal_failure(Config) -> headers => #{ <<"Content-Type">> => <<"application/json">> }, - body => thoas:encode(#{error => not_found}) + body => #{error => not_found} } }), ?assertMatch({error, not_found}, animal_service_interface:get_animal(Port, "Miles")), @@ -104,17 +104,17 @@ get_animal_failure(Config) -> create_animal(Config) -> PactRef = ?config(pact_ref, Config), - AnimalPactObject = [ - {<<"name">>, pact_matchers:string(<<"Max">>)}, - {<<"type">>, pact_matchers:string(<<"dog">>)}, - {<<"age">>, pact_matchers:integer_or_identifier()}, - {<<"nickname">>, pact_matchers:string()}, - {<<"weight_kg">>, pact_matchers:float()}, - {<<"gender">>, pact_matchers:regex_match(<<"male">>, <<"(male|female)">>)}, - {<<"carnivorous">>, pact_matchers:bool()}, - {<<"siblings">>, pact_matchers:each_like(<<"lola">>)}, - {<<"attributes">>, pact_matchers:each_key([{<<"happy">>, true}], <<"(happy|ferocious)">>)} - ], + AnimalPactObject = pact:like(#{ + <<"name">> => <<"Max">>, + <<"type">> => <<"dog">>, + <<"age">> => 1, + <<"nickname">> => <<"koko">>, + <<"weight_kg">> => 12.0, + <<"gender">> => pact_matchers:regex_match(<<"male">>, <<"(male|female)">>), + <<"carnivorous">> => true, + <<"siblings">> => pact_matchers:each_like(<<"lola">>), + <<"attributes">> => pact_matchers:each_key(#{<<"happy">> => true}, <<"(happy|ferocious)">>) + }), AnimalObject = [ {<<"name">>, <<"Max">>}, {<<"type">>, <<"dog">>}, @@ -135,7 +135,7 @@ create_animal(Config) -> headers => #{ <<"Content-Type">> => <<"application/json">> }, - body => thoas:encode(AnimalPactObject) + body => AnimalPactObject }, will_respond_with => #{ status => 201 @@ -165,7 +165,7 @@ search_animals(Config) -> headers => #{ <<"Content-Type">> => <<"application/json">> }, - body => thoas:encode(Result) + body => Result } }), ?assertMatch({ok, Result}, animal_service_interface:search_animals(Port, Query)), From 49ec30a8fd90b70d0e683c08443d8e85214e4580 Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Thu, 7 Mar 2024 20:00:05 +0530 Subject: [PATCH 08/34] fix --- src/pact.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pact.erl b/src/pact.erl index 567ba60..d5d6204 100644 --- a/src/pact.erl +++ b/src/pact.erl @@ -10,7 +10,7 @@ like/1, each_like/1, regex_match/2, - each_key/2, + each_key/2 ]). -type consumer() :: binary(). From 3aab2c43e8daaf068ca4ac5e405bc2ccf0292e2d Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Thu, 7 Mar 2024 20:01:13 +0530 Subject: [PATCH 09/34] fix --- src/pact_matchers.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pact_matchers.erl b/src/pact_matchers.erl index 472eefe..3b62305 100644 --- a/src/pact_matchers.erl +++ b/src/pact_matchers.erl @@ -16,7 +16,7 @@ like(Term) when (is_integer(Term) orelse is_binary(Term) orelse is_boolean(Term) }; like(Term) when (is_map(Term)) -> maps:map( - fun(Key, InitValue) -> + fun(_Key, InitValue) -> ?MODULE:like(InitValue) end, Term @@ -31,7 +31,7 @@ each_like(Term) when (is_integer(Term) orelse is_binary(Term) orelse is_boolean( }; each_like(Term) when (is_map(Term)) -> maps:map( - fun(Key, InitValue) -> + fun(_Key, InitValue) -> ?MODULE:each_like(InitValue) end, Term From 253e407418b2202e9c7c42ab9acf5f7ed66f8487 Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Thu, 7 Mar 2024 20:02:43 +0530 Subject: [PATCH 10/34] fixed specs --- src/pact.erl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pact.erl b/src/pact.erl index d5d6204..7d2f36b 100644 --- a/src/pact.erl +++ b/src/pact.erl @@ -60,16 +60,16 @@ like(Term) -> %% @doc Asserts the Term is an array type that consists of elements %% Like the one passed in --spec like(any()) -> map(). +-spec each_like(any()) -> map(). each_like(Term) -> pact_matchers:each_like(Term). %% @doc Asserts the value should match the given regular expression --spec like(binary() | boolean() | number(), binary()) -> map(). +-spec regex_match(binary() | boolean() | number(), binary()) -> map(). regex_match(Value, Regex) -> pact_matchers:regex_match(Value, Regex). %% @doc Asserts that each key of Value should match the given regular expression --spec like(binary() | boolean() | number(), binary()) -> map(). +-spec each_key(binary() | boolean() | number(), binary()) -> map(). each_key(Value, Regex) -> pact_matchers:each_key(Value, Regex). From 24bc1ca2ddfc2a33f79254ef3a6fac575547ee08 Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Thu, 7 Mar 2024 20:35:22 +0530 Subject: [PATCH 11/34] Fixed readme and minor issues --- README.md | 2 +- src/pact_consumer_http.erl | 32 ++++++++++++++++++++++++++++---- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c8a4dd4..3ad45c3 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ PactRef = pact:v4(<<"consumer">>, <<"producer">>). headers => #{ <<"Content-Type">> => <<"application/json">> }, - body => jsx:encode(#{users => [#{user_id => 1, user_name => <<"ranjan">>, age => 26}]}) + body => thoas:encode(#{users => [#{user_id => 1, user_name => <<"ranjan">>, age => 26}]}) } }). diff --git a/src/pact_consumer_http.erl b/src/pact_consumer_http.erl index b55c5b5..fa9f503 100644 --- a/src/pact_consumer_http.erl +++ b/src/pact_consumer_http.erl @@ -79,15 +79,27 @@ start_mock_server(PactPid, PactRef, Host, Port, InteractionPart) -> -spec insert_request_details(pact_interaction_ref(), request_details()) -> ok. insert_request_details(InteractionRef, RequestDetails) -> + %% Checking if someone used regex_match + CheckIfMap = + fun(Value) -> + case is_map(Value, 2) of + true -> + thoas:encode(Value); + false -> + Value + end + end, ReqMethod = maps:get(method, RequestDetails), ReqPath = maps:get(path, RequestDetails), - pactffi_nif:with_request(InteractionRef, ReqMethod, thoas:encode(ReqPath)), + NewReqPath = CheckIfMap(ReqPath), + pactffi_nif:with_request(InteractionRef, ReqMethod, NewReqPath), ReqHeaders = maps:get(headers, RequestDetails, #{}), ContentType = get_content_type(ReqHeaders), maps:fold( fun(Key, Value, _Acc) -> %% FIXME: 4th parameter is Index.. need to increment - pactffi_nif:with_header_v2(InteractionRef, 0, Key, 0, thoas:encode(Value)) + NewValue = CheckIfMap(Value), + pactffi_nif:with_header_v2(InteractionRef, 0, Key, 0, NewValue) end, ok, ReqHeaders @@ -105,7 +117,8 @@ insert_request_details(InteractionRef, RequestDetails) -> maps:fold( fun(Key, Value, _Acc) -> %% FIXME: 3rd parameter is Index.. need to increment - pactffi_nif:with_query_parameter_v2(InteractionRef, Key, 0, thoas:encode(Value)) + NewValue = CheckIfMap(Value), + pactffi_nif:with_query_parameter_v2(InteractionRef, Key, 0, NewValue) end, ok, ReqQueryParams @@ -115,6 +128,16 @@ insert_request_details(InteractionRef, RequestDetails) -> -spec insert_response_details(pact_interaction_ref(), response_details()) -> ok. insert_response_details(InteractionRef, ResponseDetails) -> + %% Checking if someone used regex_match + CheckIfMap = + fun(Value) -> + case is_map(Value, 2) of + true -> + thoas:encode(Value); + false -> + Value + end + end, ResponseStatusCode = maps:get(status, ResponseDetails, undefined), case ResponseStatusCode of undefined -> ok; @@ -125,7 +148,8 @@ insert_response_details(InteractionRef, ResponseDetails) -> maps:fold( fun(Key, Value, _Acc) -> %% FIXME: 4th parameter is Index.. need to increment - pactffi_nif:with_header_v2(InteractionRef, 1, Key, 0, thoas:encode(Value)) + NewValue = CheckIfMap(Value), + pactffi_nif:with_header_v2(InteractionRef, 1, Key, 0, NewValue) end, ok, ResHeaders From 01602f1c568d0c5fbcea200f8b5664e348d93455 Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Thu, 7 Mar 2024 20:36:39 +0530 Subject: [PATCH 12/34] Fixed is_map call --- src/pact_consumer_http.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pact_consumer_http.erl b/src/pact_consumer_http.erl index fa9f503..1f93c29 100644 --- a/src/pact_consumer_http.erl +++ b/src/pact_consumer_http.erl @@ -82,7 +82,7 @@ insert_request_details(InteractionRef, RequestDetails) -> %% Checking if someone used regex_match CheckIfMap = fun(Value) -> - case is_map(Value, 2) of + case is_map(Value) of true -> thoas:encode(Value); false -> @@ -131,7 +131,7 @@ insert_response_details(InteractionRef, ResponseDetails) -> %% Checking if someone used regex_match CheckIfMap = fun(Value) -> - case is_map(Value, 2) of + case is_map(Value) of true -> thoas:encode(Value); false -> From 54fb23846d8c46110993725e82b062ca21c80a74 Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Thu, 7 Mar 2024 21:00:58 +0530 Subject: [PATCH 13/34] fix --- src/pact_matchers.erl | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/pact_matchers.erl b/src/pact_matchers.erl index 3b62305..46d7ee7 100644 --- a/src/pact_matchers.erl +++ b/src/pact_matchers.erl @@ -8,12 +8,20 @@ ]). %% @doc Function for matching with type of the given term --spec like(binary() | boolean() | number() | map()) -> map(). -like(Term) when (is_integer(Term) orelse is_binary(Term) orelse is_boolean(Term)) -> +-spec like(binary() | boolean() | number() | list() | map()) -> map(). +like(Term) when (is_number(Term) orelse is_binary(Term) orelse is_boolean(Term)) -> #{ <<"value">> => Term, <<"pact:matcher:type">> => <<"type">> }; +like(Term) when (is_list(Term)) -> + lists:foldr( + fun(Elem, Acc) -> + [?MODULE:like(Elem) | Acc] + end, + [], + Term + ); like(Term) when (is_map(Term)) -> maps:map( fun(_Key, InitValue) -> @@ -23,12 +31,20 @@ like(Term) when (is_map(Term)) -> ). %% @doc Function for matching each entity inside a list with type of given term --spec each_like(binary() | boolean() | number() | map()) -> map(). -each_like(Term) when (is_integer(Term) orelse is_binary(Term) orelse is_boolean(Term)) -> +-spec each_like(binary() | boolean() | number() | map() | list()) -> map(). +each_like(Term) when (is_number(Term) orelse is_binary(Term) orelse is_boolean(Term)) -> #{ <<"value">> => [Term], <<"pact:matcher:type">> => <<"type">> }; +each_like(Term) when (is_list(Term)) -> + lists:foldr( + fun(Elem, Acc) -> + [?MODULE:each_like(Elem) | Acc] + end, + [], + Term + ); each_like(Term) when (is_map(Term)) -> maps:map( fun(_Key, InitValue) -> @@ -38,7 +54,7 @@ each_like(Term) when (is_map(Term)) -> ). %% @doc Function for matching with regex --spec regex_match(binary() | boolean() | number(), binary()) -> map(). +-spec regex_match(binary() | boolean() | number() | map() | list(), binary()) -> map(). regex_match(Value, Regex) -> #{ <<"value">> => Value, @@ -47,7 +63,7 @@ regex_match(Value, Regex) -> }. %% @doc Function for matching each key inside a map with regex --spec each_key(binary() | boolean() | number(), binary()) -> map(). +-spec each_key(binary() | boolean() | number() | map() | list(), binary()) -> map(). each_key(Value, Regex) -> #{ <<"value">> => Value, From 5cf7dade5a1a32d3fdf61f529641cb55269093b0 Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Thu, 7 Mar 2024 21:29:09 +0530 Subject: [PATCH 14/34] fix --- test/pact_end_to_end_SUITE.erl | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/test/pact_end_to_end_SUITE.erl b/test/pact_end_to_end_SUITE.erl index 9736ee4..d9e63bb 100644 --- a/test/pact_end_to_end_SUITE.erl +++ b/test/pact_end_to_end_SUITE.erl @@ -104,7 +104,18 @@ get_animal_failure(Config) -> create_animal(Config) -> PactRef = ?config(pact_ref, Config), - AnimalPactObject = pact:like(#{ + % AnimalPactObject = pact:like(#{ + % <<"name">> => <<"Max">>, + % <<"type">> => <<"dog">>, + % <<"age">> => 1, + % <<"nickname">> => <<"koko">>, + % <<"weight_kg">> => 12.0, + % <<"gender">> => pact_matchers:regex_match(<<"male">>, <<"(male|female)">>), + % <<"carnivorous">> => true, + % <<"siblings">> => pact_matchers:each_like(<<"lola">>), + % <<"attributes">> => pact_matchers:each_key(#{<<"happy">> => true}, <<"(happy|ferocious)">>) + % }), + AnimalPactObject = #{ <<"name">> => <<"Max">>, <<"type">> => <<"dog">>, <<"age">> => 1, @@ -114,7 +125,7 @@ create_animal(Config) -> <<"carnivorous">> => true, <<"siblings">> => pact_matchers:each_like(<<"lola">>), <<"attributes">> => pact_matchers:each_key(#{<<"happy">> => true}, <<"(happy|ferocious)">>) - }), + }, AnimalObject = [ {<<"name">>, <<"Max">>}, {<<"type">>, <<"dog">>}, From 56afd2a97dc7e6dc97dc335adb08707ce2d97cc0 Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Thu, 7 Mar 2024 21:32:33 +0530 Subject: [PATCH 15/34] fix --- test/pact_end_to_end_SUITE.erl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/pact_end_to_end_SUITE.erl b/test/pact_end_to_end_SUITE.erl index d9e63bb..692fc6d 100644 --- a/test/pact_end_to_end_SUITE.erl +++ b/test/pact_end_to_end_SUITE.erl @@ -118,13 +118,13 @@ create_animal(Config) -> AnimalPactObject = #{ <<"name">> => <<"Max">>, <<"type">> => <<"dog">>, - <<"age">> => 1, - <<"nickname">> => <<"koko">>, - <<"weight_kg">> => 12.0, - <<"gender">> => pact_matchers:regex_match(<<"male">>, <<"(male|female)">>), + <<"age">> => 3, + <<"nickname">> => <<"lazgo">>, + <<"weight_kg">> => 10.0, + <<"gender">> => <<"male">>, <<"carnivorous">> => true, - <<"siblings">> => pact_matchers:each_like(<<"lola">>), - <<"attributes">> => pact_matchers:each_key(#{<<"happy">> => true}, <<"(happy|ferocious)">>) + <<"siblings">> => [<<"lola">>, <<"mary">>], + <<"attributes">> => #{<<"ferocious">> => false} }, AnimalObject = [ {<<"name">>, <<"Max">>}, From 830346cd221a67d748197373e75b79ed7b6707c1 Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Thu, 7 Mar 2024 21:34:58 +0530 Subject: [PATCH 16/34] fix --- test/pact_end_to_end_SUITE.erl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/pact_end_to_end_SUITE.erl b/test/pact_end_to_end_SUITE.erl index 692fc6d..e640d25 100644 --- a/test/pact_end_to_end_SUITE.erl +++ b/test/pact_end_to_end_SUITE.erl @@ -121,10 +121,10 @@ create_animal(Config) -> <<"age">> => 3, <<"nickname">> => <<"lazgo">>, <<"weight_kg">> => 10.0, - <<"gender">> => <<"male">>, + <<"gender">> => pact_matchers:regex_match(<<"male">>, <<"(male|female)">>),, <<"carnivorous">> => true, - <<"siblings">> => [<<"lola">>, <<"mary">>], - <<"attributes">> => #{<<"ferocious">> => false} + <<"siblings">> => pact_matchers:each_like(<<"lola">>), + <<"attributes">> => pact_matchers:each_key(#{<<"happy">> => true}, <<"(happy|ferocious)">>) }, AnimalObject = [ {<<"name">>, <<"Max">>}, From a0efbf5af4a5354527b8ffcc84717ec2482b1138 Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Thu, 7 Mar 2024 21:35:56 +0530 Subject: [PATCH 17/34] fix --- test/pact_end_to_end_SUITE.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/pact_end_to_end_SUITE.erl b/test/pact_end_to_end_SUITE.erl index e640d25..e67f0b4 100644 --- a/test/pact_end_to_end_SUITE.erl +++ b/test/pact_end_to_end_SUITE.erl @@ -121,7 +121,7 @@ create_animal(Config) -> <<"age">> => 3, <<"nickname">> => <<"lazgo">>, <<"weight_kg">> => 10.0, - <<"gender">> => pact_matchers:regex_match(<<"male">>, <<"(male|female)">>),, + <<"gender">> => pact_matchers:regex_match(<<"male">>, <<"(male|female)">>), <<"carnivorous">> => true, <<"siblings">> => pact_matchers:each_like(<<"lola">>), <<"attributes">> => pact_matchers:each_key(#{<<"happy">> => true}, <<"(happy|ferocious)">>) From 14b817ab0cb301d5091aa92383dbcf608242932f Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Thu, 7 Mar 2024 21:57:47 +0530 Subject: [PATCH 18/34] fix --- src/pact_matchers.erl | 36 ++++++++++++++++++++++------------ test/pact_end_to_end_SUITE.erl | 32 +++++++++++++++--------------- 2 files changed, 40 insertions(+), 28 deletions(-) diff --git a/src/pact_matchers.erl b/src/pact_matchers.erl index 46d7ee7..c11d29e 100644 --- a/src/pact_matchers.erl +++ b/src/pact_matchers.erl @@ -23,12 +23,18 @@ like(Term) when (is_list(Term)) -> Term ); like(Term) when (is_map(Term)) -> - maps:map( - fun(_Key, InitValue) -> - ?MODULE:like(InitValue) - end, - Term - ). + Keys = maps:keys(Term), + case lists:member(<<"pact:matcher:type">>, Keys) of + true -> + Term; + false -> + maps:map( + fun(_Key, InitValue) -> + ?MODULE:like(InitValue) + end, + Term + ) + end. %% @doc Function for matching each entity inside a list with type of given term -spec each_like(binary() | boolean() | number() | map() | list()) -> map(). @@ -46,12 +52,18 @@ each_like(Term) when (is_list(Term)) -> Term ); each_like(Term) when (is_map(Term)) -> - maps:map( - fun(_Key, InitValue) -> - ?MODULE:each_like(InitValue) - end, - Term - ). + Keys = maps:keys(Term), + case lists:member(<<"pact:matcher:type">>, Keys) of + true -> + Term; + false -> + maps:map( + fun(_Key, InitValue) -> + ?MODULE:each_like(InitValue) + end, + Term + ) + end. %% @doc Function for matching with regex -spec regex_match(binary() | boolean() | number() | map() | list(), binary()) -> map(). diff --git a/test/pact_end_to_end_SUITE.erl b/test/pact_end_to_end_SUITE.erl index e67f0b4..48b924e 100644 --- a/test/pact_end_to_end_SUITE.erl +++ b/test/pact_end_to_end_SUITE.erl @@ -104,28 +104,28 @@ get_animal_failure(Config) -> create_animal(Config) -> PactRef = ?config(pact_ref, Config), - % AnimalPactObject = pact:like(#{ - % <<"name">> => <<"Max">>, - % <<"type">> => <<"dog">>, - % <<"age">> => 1, - % <<"nickname">> => <<"koko">>, - % <<"weight_kg">> => 12.0, - % <<"gender">> => pact_matchers:regex_match(<<"male">>, <<"(male|female)">>), - % <<"carnivorous">> => true, - % <<"siblings">> => pact_matchers:each_like(<<"lola">>), - % <<"attributes">> => pact_matchers:each_key(#{<<"happy">> => true}, <<"(happy|ferocious)">>) - % }), - AnimalPactObject = #{ + AnimalPactObject = pact:like(#{ <<"name">> => <<"Max">>, <<"type">> => <<"dog">>, - <<"age">> => 3, - <<"nickname">> => <<"lazgo">>, - <<"weight_kg">> => 10.0, + <<"age">> => 1, + <<"nickname">> => <<"koko">>, + <<"weight_kg">> => 12.0, <<"gender">> => pact_matchers:regex_match(<<"male">>, <<"(male|female)">>), <<"carnivorous">> => true, <<"siblings">> => pact_matchers:each_like(<<"lola">>), <<"attributes">> => pact_matchers:each_key(#{<<"happy">> => true}, <<"(happy|ferocious)">>) - }, + }), + % AnimalPactObject = #{ + % <<"name">> => <<"Max">>, + % <<"type">> => <<"dog">>, + % <<"age">> => 3, + % <<"nickname">> => <<"lazgo">>, + % <<"weight_kg">> => 10.0, + % <<"gender">> => pact_matchers:regex_match(<<"male">>, <<"(male|female)">>), + % <<"carnivorous">> => true, + % <<"siblings">> => pact_matchers:each_like(<<"lola">>), + % <<"attributes">> => pact_matchers:each_key(#{<<"happy">> => true}, <<"(happy|ferocious)">>) + % }, AnimalObject = [ {<<"name">>, <<"Max">>}, {<<"type">>, <<"dog">>}, From 7c7aff23fa8049ac7adef6769b75e4836269782d Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Thu, 7 Mar 2024 22:11:37 +0530 Subject: [PATCH 19/34] fix format --- src/pact_matchers.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pact_matchers.erl b/src/pact_matchers.erl index c11d29e..e68a287 100644 --- a/src/pact_matchers.erl +++ b/src/pact_matchers.erl @@ -8,7 +8,7 @@ ]). %% @doc Function for matching with type of the given term --spec like(binary() | boolean() | number() | list() | map()) -> map(). +-spec like(binary() | boolean() | number() | list() | map()) -> map(). like(Term) when (is_number(Term) orelse is_binary(Term) orelse is_boolean(Term)) -> #{ <<"value">> => Term, From ea2b9ef34b55f1e5af68dfc69ac3a09ded3531a4 Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Fri, 8 Mar 2024 10:08:56 +0530 Subject: [PATCH 20/34] more tests --- src/pact_matchers.erl | 38 ++++++++++++++++++---------------- test/pact_end_to_end_SUITE.erl | 14 +++++++------ 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/pact_matchers.erl b/src/pact_matchers.erl index e68a287..42585d5 100644 --- a/src/pact_matchers.erl +++ b/src/pact_matchers.erl @@ -44,26 +44,28 @@ each_like(Term) when (is_number(Term) orelse is_binary(Term) orelse is_boolean(T <<"pact:matcher:type">> => <<"type">> }; each_like(Term) when (is_list(Term)) -> - lists:foldr( - fun(Elem, Acc) -> - [?MODULE:each_like(Elem) | Acc] - end, - [], - Term - ); + #{ + <<"value">> => Term, + <<"pact:matcher:type">> => <<"type">> + }; each_like(Term) when (is_map(Term)) -> Keys = maps:keys(Term), - case lists:member(<<"pact:matcher:type">>, Keys) of - true -> - Term; - false -> - maps:map( - fun(_Key, InitValue) -> - ?MODULE:each_like(InitValue) - end, - Term - ) - end. + Map = + case lists:member(<<"pact:matcher:type">>, Keys) of + true -> + Term; + false -> + maps:map( + fun(_Key, InitValue) -> + ?MODULE:like(InitValue) + end, + Term + ) + end, + #{ + <<"value">> => [Map], + <<"pact:matcher:type">> => <<"type">> + }. %% @doc Function for matching with regex -spec regex_match(binary() | boolean() | number() | map() | list(), binary()) -> map(). diff --git a/test/pact_end_to_end_SUITE.erl b/test/pact_end_to_end_SUITE.erl index 48b924e..52d4152 100644 --- a/test/pact_end_to_end_SUITE.erl +++ b/test/pact_end_to_end_SUITE.erl @@ -88,12 +88,12 @@ get_animal_failure(Config) -> upon_receiving => <<"a request to GET a non-existing animal: Miles">>, with_request => #{ method => <<"GET">>, - path => <<"/animals/Miles">> + path => pact:regex_match(<<"/animals/Miles">>, <<"^\/animals\/[a-zA-Z]+">>) }, will_respond_with => #{ status => 404, headers => #{ - <<"Content-Type">> => <<"application/json">> + <<"Content-Type">> => pact:like(<<"application/json">>) }, body => #{error => not_found} } @@ -107,13 +107,15 @@ create_animal(Config) -> AnimalPactObject = pact:like(#{ <<"name">> => <<"Max">>, <<"type">> => <<"dog">>, - <<"age">> => 1, + <<"age">> => 3, <<"nickname">> => <<"koko">>, <<"weight_kg">> => 12.0, - <<"gender">> => pact_matchers:regex_match(<<"male">>, <<"(male|female)">>), + <<"gender">> => pact:regex_match(<<"male">>, <<"(male|female)">>), <<"carnivorous">> => true, - <<"siblings">> => pact_matchers:each_like(<<"lola">>), - <<"attributes">> => pact_matchers:each_key(#{<<"happy">> => true}, <<"(happy|ferocious)">>) + <<"siblings">> => pact:each_like(<<"lola">>), + <<"children">> => [<<"coco">>], + <<"children_details">> => pact:each_like(#{<<"name">> => <<"coco">>, <<"age">> => 1, <<"body_size">> => [3,4,5]}), + <<"attributes">> => pact:each_key(#{<<"happy">> => true}, <<"(happy|ferocious)">>) }), % AnimalPactObject = #{ % <<"name">> => <<"Max">>, From 96fe4e8aa05afc5ae81cbf9b29039c6eead1e094 Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Fri, 8 Mar 2024 10:49:59 +0530 Subject: [PATCH 21/34] test fix --- test/animal_service.erl | 7 ++++++- test/pact_end_to_end_SUITE.erl | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/test/animal_service.erl b/test/animal_service.erl index 7410b2a..4a5a6e0 100644 --- a/test/animal_service.erl +++ b/test/animal_service.erl @@ -122,5 +122,10 @@ make_json_response(Code, Body) -> Length = io_lib:format("~w", [io_lib:chars_length(BodyJson)]), {proceed, [{response, {response, [{code, Code}, {content_length, Length}, {content_type, "application/json"}], BodyJson}}]}. +make_json_response(Code, Body, ExtraHeaders) -> + BodyJson = erlang:binary_to_list(thoas:encode(Body)), + Length = io_lib:format("~w", [io_lib:chars_length(BodyJson)]), + {proceed, [{response, {response, ExtraHeaders ++ [{code, Code}, {content_length, Length}, {content_type, "application/json"}], BodyJson}}]}. + make_404_response() -> - make_json_response(404, #{error => not_found}). + make_json_response(404, #{error => not_found}, [{error_details, "not found"}]). diff --git a/test/pact_end_to_end_SUITE.erl b/test/pact_end_to_end_SUITE.erl index 52d4152..84e7b59 100644 --- a/test/pact_end_to_end_SUITE.erl +++ b/test/pact_end_to_end_SUITE.erl @@ -93,7 +93,8 @@ get_animal_failure(Config) -> will_respond_with => #{ status => 404, headers => #{ - <<"Content-Type">> => pact:like(<<"application/json">>) + <<"error_details">> => pact:like(<<"animal not found">>), + <<"Content-Type">> => <<"application/json">> }, body => #{error => not_found} } From 763bdb94d001f0b129cc9e3d938f7a960c4aa999 Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Fri, 8 Mar 2024 10:53:25 +0530 Subject: [PATCH 22/34] test fix --- test/pact_end_to_end_SUITE.erl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/pact_end_to_end_SUITE.erl b/test/pact_end_to_end_SUITE.erl index 84e7b59..1297225 100644 --- a/test/pact_end_to_end_SUITE.erl +++ b/test/pact_end_to_end_SUITE.erl @@ -138,6 +138,8 @@ create_animal(Config) -> {<<"gender">>, <<"male">>}, {<<"carnivorous">>, true}, {<<"siblings">>, [<<"lola">>, <<"mary">>]}, + {<<"children">>, [<<"coco">>]}, + {<<"children_details">>, [{<<"name">>, <<"coco">>}, {<<"age">>, 1}, {<<"body_size">>, [3,4,5]}]}, {<<"attributes">>, [{<<"ferocious">>, false}]} ], {ok, Port} = pact:interaction(PactRef, From 6114a27f7dad33005518fdb0e630a4d6a4b28276 Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Fri, 8 Mar 2024 10:54:58 +0530 Subject: [PATCH 23/34] test fix --- test/pact_end_to_end_SUITE.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/pact_end_to_end_SUITE.erl b/test/pact_end_to_end_SUITE.erl index 1297225..7338c61 100644 --- a/test/pact_end_to_end_SUITE.erl +++ b/test/pact_end_to_end_SUITE.erl @@ -139,7 +139,7 @@ create_animal(Config) -> {<<"carnivorous">>, true}, {<<"siblings">>, [<<"lola">>, <<"mary">>]}, {<<"children">>, [<<"coco">>]}, - {<<"children_details">>, [{<<"name">>, <<"coco">>}, {<<"age">>, 1}, {<<"body_size">>, [3,4,5]}]}, + {<<"children_details">>, [[{<<"name">>, <<"coco">>}, {<<"age">>, 1}, {<<"body_size">>, [3,4,5]}]]}, {<<"attributes">>, [{<<"ferocious">>, false}]} ], {ok, Port} = pact:interaction(PactRef, From 2ea5fc86f7e06ddee4dc6d7f5b256a59710462d6 Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Fri, 8 Mar 2024 12:52:31 +0530 Subject: [PATCH 24/34] using regex match instead of like --- test/pact_end_to_end_SUITE.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/pact_end_to_end_SUITE.erl b/test/pact_end_to_end_SUITE.erl index 7338c61..5bff33b 100644 --- a/test/pact_end_to_end_SUITE.erl +++ b/test/pact_end_to_end_SUITE.erl @@ -93,7 +93,7 @@ get_animal_failure(Config) -> will_respond_with => #{ status => 404, headers => #{ - <<"error_details">> => pact:like(<<"animal not found">>), + <<"error_details">> => pact:regex_match(<<"animal not found">>, <<".+">>), <<"Content-Type">> => <<"application/json">> }, body => #{error => not_found} From 5062768fd0bd12466fafbfe50439c04edd18b23f Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Fri, 8 Mar 2024 12:56:12 +0530 Subject: [PATCH 25/34] fixed test cases --- src/pact_consumer_http.erl | 8 ++++++-- test/animal_service.erl | 7 +------ test/pact_end_to_end_SUITE.erl | 1 - 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/pact_consumer_http.erl b/src/pact_consumer_http.erl index 1f93c29..e0a1f5a 100644 --- a/src/pact_consumer_http.erl +++ b/src/pact_consumer_http.erl @@ -107,7 +107,9 @@ insert_request_details(InteractionRef, RequestDetails) -> ReqBody = maps:get(body, RequestDetails, undefined), case ReqBody of undefined -> ok; - _ -> pactffi_nif:with_body(InteractionRef, 0, ContentType, thoas:encode(ReqBody)) + _ -> + NewReqBody = CheckIfMap(ReqBody), + pactffi_nif:with_body(InteractionRef, 0, ContentType, NewReqBody) end, ReqQueryParams = maps:get(query_params, RequestDetails, undefined), case ReqQueryParams of @@ -157,7 +159,9 @@ insert_response_details(InteractionRef, ResponseDetails) -> ResBody = maps:get(body, ResponseDetails, undefined), case ResBody of undefined -> ok; - _ -> pactffi_nif:with_body(InteractionRef, 1, ContentType, thoas:encode(ResBody)) + _ -> + NewResBody = CheckIfMap(ResBody), + pactffi_nif:with_body(InteractionRef, 1, ContentType, NewResBody) end, ok. diff --git a/test/animal_service.erl b/test/animal_service.erl index 4a5a6e0..7410b2a 100644 --- a/test/animal_service.erl +++ b/test/animal_service.erl @@ -122,10 +122,5 @@ make_json_response(Code, Body) -> Length = io_lib:format("~w", [io_lib:chars_length(BodyJson)]), {proceed, [{response, {response, [{code, Code}, {content_length, Length}, {content_type, "application/json"}], BodyJson}}]}. -make_json_response(Code, Body, ExtraHeaders) -> - BodyJson = erlang:binary_to_list(thoas:encode(Body)), - Length = io_lib:format("~w", [io_lib:chars_length(BodyJson)]), - {proceed, [{response, {response, ExtraHeaders ++ [{code, Code}, {content_length, Length}, {content_type, "application/json"}], BodyJson}}]}. - make_404_response() -> - make_json_response(404, #{error => not_found}, [{error_details, "not found"}]). + make_json_response(404, #{error => not_found}). diff --git a/test/pact_end_to_end_SUITE.erl b/test/pact_end_to_end_SUITE.erl index 5bff33b..4f438bc 100644 --- a/test/pact_end_to_end_SUITE.erl +++ b/test/pact_end_to_end_SUITE.erl @@ -93,7 +93,6 @@ get_animal_failure(Config) -> will_respond_with => #{ status => 404, headers => #{ - <<"error_details">> => pact:regex_match(<<"animal not found">>, <<".+">>), <<"Content-Type">> => <<"application/json">> }, body => #{error => not_found} From 1143655b1114fd3798738a17a72ee4bee5c5faf4 Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Fri, 8 Mar 2024 13:00:25 +0530 Subject: [PATCH 26/34] fixed formatting --- src/pact_consumer_http.erl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pact_consumer_http.erl b/src/pact_consumer_http.erl index e0a1f5a..6957e89 100644 --- a/src/pact_consumer_http.erl +++ b/src/pact_consumer_http.erl @@ -106,7 +106,8 @@ insert_request_details(InteractionRef, RequestDetails) -> ), ReqBody = maps:get(body, RequestDetails, undefined), case ReqBody of - undefined -> ok; + undefined -> + ok; _ -> NewReqBody = CheckIfMap(ReqBody), pactffi_nif:with_body(InteractionRef, 0, ContentType, NewReqBody) @@ -158,7 +159,8 @@ insert_response_details(InteractionRef, ResponseDetails) -> ), ResBody = maps:get(body, ResponseDetails, undefined), case ResBody of - undefined -> ok; + undefined -> + ok; _ -> NewResBody = CheckIfMap(ResBody), pactffi_nif:with_body(InteractionRef, 1, ContentType, NewResBody) From d6c1311841f63d0cb45ce5af2d401680bae51b96 Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Fri, 8 Mar 2024 13:42:05 +0530 Subject: [PATCH 27/34] fix tests --- src/pact_matchers.erl | 45 ++++++++++++++++++++++++---------- test/pact_end_to_end_SUITE.erl | 1 + 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/pact_matchers.erl b/src/pact_matchers.erl index 42585d5..3c87296 100644 --- a/src/pact_matchers.erl +++ b/src/pact_matchers.erl @@ -23,17 +23,17 @@ like(Term) when (is_list(Term)) -> Term ); like(Term) when (is_map(Term)) -> - Keys = maps:keys(Term), - case lists:member(<<"pact:matcher:type">>, Keys) of - true -> - Term; - false -> + KeyPresent = maps:get(<<"pact:matcher:type">>, Term, undefined), + case KeyPresent of + undefined -> maps:map( fun(_Key, InitValue) -> ?MODULE:like(InitValue) end, Term - ) + ); + _ -> + Term end. %% @doc Function for matching each entity inside a list with type of given term @@ -44,23 +44,42 @@ each_like(Term) when (is_number(Term) orelse is_binary(Term) orelse is_boolean(T <<"pact:matcher:type">> => <<"type">> }; each_like(Term) when (is_list(Term)) -> + List = + lists:foldr( + fun(Elem, Acc) -> + case is_map(Elem) of + true -> + KeyPresent = maps:get(<<"pact:matcher:type">>, Elem, undefined), + case KeyPresent of + undefined -> + [?MODULE:like(Elem) | Acc]; + _ -> + Elem + end; + false -> + Elem + end + end, + [], + Term + ), #{ - <<"value">> => Term, + <<"value">> => [List], <<"pact:matcher:type">> => <<"type">> }; each_like(Term) when (is_map(Term)) -> - Keys = maps:keys(Term), + KeyPresent = maps:get(<<"pact:matcher:type">>, Term, undefined), Map = - case lists:member(<<"pact:matcher:type">>, Keys) of - true -> - Term; - false -> + case KeyPresent of + undefined -> maps:map( fun(_Key, InitValue) -> ?MODULE:like(InitValue) end, Term - ) + ); + _ -> + Term end, #{ <<"value">> => [Map], diff --git a/test/pact_end_to_end_SUITE.erl b/test/pact_end_to_end_SUITE.erl index 4f438bc..928da01 100644 --- a/test/pact_end_to_end_SUITE.erl +++ b/test/pact_end_to_end_SUITE.erl @@ -113,6 +113,7 @@ create_animal(Config) -> <<"gender">> => pact:regex_match(<<"male">>, <<"(male|female)">>), <<"carnivorous">> => true, <<"siblings">> => pact:each_like(<<"lola">>), + <<"list_att">> => pact:each_like([1,pact:like(<<"head">>)]), <<"children">> => [<<"coco">>], <<"children_details">> => pact:each_like(#{<<"name">> => <<"coco">>, <<"age">> => 1, <<"body_size">> => [3,4,5]}), <<"attributes">> => pact:each_key(#{<<"happy">> => true}, <<"(happy|ferocious)">>) From c10b60fee2f73d2ea8745766d8f3aac659f7f5e1 Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Fri, 8 Mar 2024 13:43:03 +0530 Subject: [PATCH 28/34] fix tests --- test/pact_end_to_end_SUITE.erl | 1 + 1 file changed, 1 insertion(+) diff --git a/test/pact_end_to_end_SUITE.erl b/test/pact_end_to_end_SUITE.erl index 928da01..9ef9863 100644 --- a/test/pact_end_to_end_SUITE.erl +++ b/test/pact_end_to_end_SUITE.erl @@ -138,6 +138,7 @@ create_animal(Config) -> {<<"gender">>, <<"male">>}, {<<"carnivorous">>, true}, {<<"siblings">>, [<<"lola">>, <<"mary">>]}, + {<<"list_att">>, [[2, <<"legs">>]]}, {<<"children">>, [<<"coco">>]}, {<<"children_details">>, [[{<<"name">>, <<"coco">>}, {<<"age">>, 1}, {<<"body_size">>, [3,4,5]}]]}, {<<"attributes">>, [{<<"ferocious">>, false}]} From e742b2163b032d59e0666f4dd418ea92529e0ddd Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Fri, 8 Mar 2024 13:53:08 +0530 Subject: [PATCH 29/34] fix minor issue --- src/pact_matchers.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pact_matchers.erl b/src/pact_matchers.erl index 3c87296..b97d6fb 100644 --- a/src/pact_matchers.erl +++ b/src/pact_matchers.erl @@ -57,7 +57,7 @@ each_like(Term) when (is_list(Term)) -> Elem end; false -> - Elem + [?MODULE:like(Elem) | Acc] end end, [], From 55dbd3522c4470876536a4c7411a4f89d8623e60 Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Fri, 8 Mar 2024 13:55:57 +0530 Subject: [PATCH 30/34] fix minor issue --- src/pact_matchers.erl | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/pact_matchers.erl b/src/pact_matchers.erl index b97d6fb..9892ef4 100644 --- a/src/pact_matchers.erl +++ b/src/pact_matchers.erl @@ -47,18 +47,7 @@ each_like(Term) when (is_list(Term)) -> List = lists:foldr( fun(Elem, Acc) -> - case is_map(Elem) of - true -> - KeyPresent = maps:get(<<"pact:matcher:type">>, Elem, undefined), - case KeyPresent of - undefined -> - [?MODULE:like(Elem) | Acc]; - _ -> - Elem - end; - false -> - [?MODULE:like(Elem) | Acc] - end + [?MODULE:like(Elem) | Acc] end, [], Term From 30991821b52e67756ecd19672d9692f8aaef7ac8 Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Fri, 8 Mar 2024 14:00:10 +0530 Subject: [PATCH 31/34] remove repeated code block --- src/pact_matchers.erl | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/pact_matchers.erl b/src/pact_matchers.erl index 9892ef4..f8ae08c 100644 --- a/src/pact_matchers.erl +++ b/src/pact_matchers.erl @@ -57,19 +57,7 @@ each_like(Term) when (is_list(Term)) -> <<"pact:matcher:type">> => <<"type">> }; each_like(Term) when (is_map(Term)) -> - KeyPresent = maps:get(<<"pact:matcher:type">>, Term, undefined), - Map = - case KeyPresent of - undefined -> - maps:map( - fun(_Key, InitValue) -> - ?MODULE:like(InitValue) - end, - Term - ); - _ -> - Term - end, + Map = ?MODULE:like(Term), #{ <<"value">> => [Map], <<"pact:matcher:type">> => <<"type">> From 7452f021ec9028801ed426959d38bad24498ab20 Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Fri, 8 Mar 2024 19:13:59 +0530 Subject: [PATCH 32/34] Updated readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3ad45c3..e3b15cf 100644 --- a/README.md +++ b/README.md @@ -92,10 +92,10 @@ pact:interaction(PactRef, headers => #{ <<"Content-Type">> => <<"application/json">> }, - body => thoas:encode( - {<<"name">>, pact_matchers:string(<<"Lazgo">>)}, - {<<"type">>, pact_matchers:string(<<"dog">>)} - ) + body => #{ + <<"name">> => pact:like(<<"Lazgo">>), + <<"type">> => pact:like(<<"dog">>) + } }, will_respond_with => #{ status => 201 From 4af6cdc07e2b0df9a4a5ff57cc40f1f1dd498c55 Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Fri, 8 Mar 2024 19:15:20 +0530 Subject: [PATCH 33/34] Updated readme again --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e3b15cf..69d75a6 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ PactRef = pact:v4(<<"consumer">>, <<"producer">>). headers => #{ <<"Content-Type">> => <<"application/json">> }, - body => thoas:encode(#{users => [#{user_id => 1, user_name => <<"ranjan">>, age => 26}]}) + body => #{users => [#{user_id => 1, user_name => <<"ranjan">>, age => 26}]} } }). From fb4dafd27a9ab496f5669e96329d361c2eceaea1 Mon Sep 17 00:00:00 2001 From: Priyaranjan Mudliar Date: Fri, 8 Mar 2024 19:24:30 +0530 Subject: [PATCH 34/34] Removed comments --- test/pact_end_to_end_SUITE.erl | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/test/pact_end_to_end_SUITE.erl b/test/pact_end_to_end_SUITE.erl index 9ef9863..67dc175 100644 --- a/test/pact_end_to_end_SUITE.erl +++ b/test/pact_end_to_end_SUITE.erl @@ -118,17 +118,6 @@ create_animal(Config) -> <<"children_details">> => pact:each_like(#{<<"name">> => <<"coco">>, <<"age">> => 1, <<"body_size">> => [3,4,5]}), <<"attributes">> => pact:each_key(#{<<"happy">> => true}, <<"(happy|ferocious)">>) }), - % AnimalPactObject = #{ - % <<"name">> => <<"Max">>, - % <<"type">> => <<"dog">>, - % <<"age">> => 3, - % <<"nickname">> => <<"lazgo">>, - % <<"weight_kg">> => 10.0, - % <<"gender">> => pact_matchers:regex_match(<<"male">>, <<"(male|female)">>), - % <<"carnivorous">> => true, - % <<"siblings">> => pact_matchers:each_like(<<"lola">>), - % <<"attributes">> => pact_matchers:each_key(#{<<"happy">> => true}, <<"(happy|ferocious)">>) - % }, AnimalObject = [ {<<"name">>, <<"Max">>}, {<<"type">>, <<"dog">>},