-module(http_server_mock@stub_builder).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/http_server_mock/stub_builder.gleam").
-export([new/0, matching/2, responding_with/2, with_id/2, with_priority/2, in_scenario/2, when_state_is/2, then_transition_to/2, build/1]).
-export_type([with_matcher/0, without_matcher/0, with_response/0, without_response/0, with_scenario/0, without_scenario/0, stub_builder/3]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" Builder for `Stub` — pairs a request matcher with a response definition.\n"
"\n"
" Start with `new()`, set a matcher via `matching()` and a response via\n"
" `responding_with()`, then call `build()` to produce a `Stub` you can\n"
" register with the server.\n"
"\n"
" Phantom types enforce that both `matching` and `responding_with` have been\n"
" called: passing a partially-configured builder to `build` is a compile error.\n"
"\n"
" For stateful sequences, call `in_scenario` first, then optionally\n"
" `when_state_is` and `then_transition_to` — calling the latter two without\n"
" `in_scenario` is a compile error enforced by the `WithScenario` phantom type.\n"
"\n"
" ```gleam\n"
" import gleam/http\n"
" import http_server_mock/matcher\n"
" import http_server_mock/response\n"
" import http_server_mock/stub_builder\n"
"\n"
" let stub =\n"
" stub_builder.new()\n"
" |> stub_builder.matching(matcher.new() |> matcher.method(http.Post) |> matcher.path(\"/users\"))\n"
" |> stub_builder.responding_with(response.created())\n"
" |> stub_builder.build()\n"
" ```\n"
).
-type with_matcher() :: any().
-type without_matcher() :: any().
-type with_response() :: any().
-type without_response() :: any().
-type with_scenario() :: any().
-type without_scenario() :: any().
-opaque stub_builder(FPG, FPH, FPI) :: {stub_builder,
gleam@option:option(http_server_mock@types:request_matcher()),
gleam@option:option(http_server_mock@types:response_definition()),
gleam@option:option(binary()),
integer(),
gleam@option:option(http_server_mock@types:scenario_state())} |
{gleam_phantom, FPG, FPH, FPI}.
-file("src/http_server_mock/stub_builder.gleam", 74).
?DOC(" Creates an empty stub builder with no matcher, response, or scenario set.\n").
-spec new() -> stub_builder(without_matcher(), without_response(), without_scenario()).
new() ->
{stub_builder, none, none, none, 5, none}.
-file("src/http_server_mock/stub_builder.gleam", 85).
?DOC(" Sets the request matcher, transitioning the builder to `WithMatcher`.\n").
-spec matching(
stub_builder(any(), FPN, FPO),
http_server_mock@types:request_matcher()
) -> stub_builder(with_matcher(), FPN, FPO).
matching(Builder, Request_matcher) ->
{stub_builder,
{some, Request_matcher},
erlang:element(3, Builder),
erlang:element(4, Builder),
erlang:element(5, Builder),
erlang:element(6, Builder)}.
-file("src/http_server_mock/stub_builder.gleam", 93).
?DOC(" Sets the response definition, transitioning the builder to `WithResponse`.\n").
-spec responding_with(
stub_builder(FPV, any(), FPX),
http_server_mock@types:response_definition()
) -> stub_builder(FPV, with_response(), FPX).
responding_with(Builder, Response_def) ->
{stub_builder,
erlang:element(2, Builder),
{some, Response_def},
erlang:element(4, Builder),
erlang:element(5, Builder),
erlang:element(6, Builder)}.
-file("src/http_server_mock/stub_builder.gleam", 104).
?DOC(
" Assigns a custom ID to this stub.\n"
"\n"
" IDs are used with `remove_stub` to unregister a specific stub. If not set,\n"
" a unique ID is generated automatically.\n"
).
-spec with_id(stub_builder(FQE, FQF, FQG), binary()) -> stub_builder(FQE, FQF, FQG).
with_id(Builder, Id) ->
{stub_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
{some, Id},
erlang:element(5, Builder),
erlang:element(6, Builder)}.
-file("src/http_server_mock/stub_builder.gleam", 114).
?DOC(
" Sets the priority for this stub.\n"
"\n"
" Lower values win when multiple stubs match a request. Defaults to `5`.\n"
).
-spec with_priority(stub_builder(FQN, FQO, FQP), integer()) -> stub_builder(FQN, FQO, FQP).
with_priority(Builder, Priority) ->
{stub_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
erlang:element(4, Builder),
Priority,
erlang:element(6, Builder)}.
-file("src/http_server_mock/stub_builder.gleam", 126).
?DOC(
" Places this stub inside the named scenario, transitioning the builder to `WithScenario`.\n"
"\n"
" Scenarios allow a sequence of stubs to fire in order: the first time the\n"
" matcher fires it transitions state; subsequent calls match the next stub.\n"
" Must be called before `when_state_is` or `then_transition_to`.\n"
).
-spec in_scenario(stub_builder(FQW, FQX, any()), binary()) -> stub_builder(FQW, FQX, with_scenario()).
in_scenario(Builder, Name) ->
Scenario = case erlang:element(6, Builder) of
none ->
{scenario_state, Name, none, none};
{some, Existing} ->
{scenario_state,
Name,
erlang:element(3, Existing),
erlang:element(4, Existing)}
end,
{stub_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
erlang:element(4, Builder),
erlang:element(5, Builder),
{some, Scenario}}.
-file("src/http_server_mock/stub_builder.gleam", 140).
?DOC(
" Makes this stub only fire when the scenario is in the given state.\n"
"\n"
" Requires `in_scenario` to have been called first — enforced at compile time.\n"
).
-spec when_state_is(stub_builder(FRF, FRG, with_scenario()), binary()) -> stub_builder(FRF, FRG, with_scenario()).
when_state_is(Builder, State) ->
Existing@1 = case erlang:element(6, Builder) of
{some, Existing} -> Existing;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"http_server_mock/stub_builder"/utf8>>,
function => <<"when_state_is"/utf8>>,
line => 144,
value => _assert_fail,
start => 5427,
'end' => 5471,
pattern_start => 5438,
pattern_end => 5452})
end,
{stub_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
erlang:element(4, Builder),
erlang:element(5, Builder),
{some,
{scenario_state,
erlang:element(2, Existing@1),
{some, State},
erlang:element(4, Existing@1)}}}.
-file("src/http_server_mock/stub_builder.gleam", 154).
?DOC(
" Transitions the scenario to the given state after this stub fires.\n"
"\n"
" Requires `in_scenario` to have been called first — enforced at compile time.\n"
).
-spec then_transition_to(stub_builder(FRN, FRO, with_scenario()), binary()) -> stub_builder(FRN, FRO, with_scenario()).
then_transition_to(Builder, New_state) ->
Existing@1 = case erlang:element(6, Builder) of
{some, Existing} -> Existing;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"http_server_mock/stub_builder"/utf8>>,
function => <<"then_transition_to"/utf8>>,
line => 158,
value => _assert_fail,
start => 5926,
'end' => 5970,
pattern_start => 5937,
pattern_end => 5951})
end,
{stub_builder,
erlang:element(2, Builder),
erlang:element(3, Builder),
erlang:element(4, Builder),
erlang:element(5, Builder),
{some,
{scenario_state,
erlang:element(2, Existing@1),
erlang:element(3, Existing@1),
{some, New_state}}}}.
-file("src/http_server_mock/stub_builder.gleam", 191).
-spec generate_id() -> binary().
generate_id() ->
<<"stub_"/utf8, (erlang:integer_to_binary(erlang:unique_integer()))/binary>>.
-file("src/http_server_mock/stub_builder.gleam", 171).
?DOC(
" Builds the concrete `Stub` from this builder.\n"
"\n"
" Only callable when both `matching` and `responding_with` have been called —\n"
" the phantom types enforce this at compile time.\n"
"\n"
" Pass the result to `http_server_mock.with_stub` or `http_server_mock.add_stub`.\n"
).
-spec build(stub_builder(with_matcher(), with_response(), any())) -> http_server_mock@types:stub().
build(Builder) ->
Matcher@1 = case erlang:element(2, Builder) of
{some, Matcher} -> Matcher;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"http_server_mock/stub_builder"/utf8>>,
function => <<"build"/utf8>>,
line => 174,
value => _assert_fail,
start => 6454,
'end' => 6496,
pattern_start => 6465,
pattern_end => 6478})
end,
Response@1 = case erlang:element(3, Builder) of
{some, Response} -> Response;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"http_server_mock/stub_builder"/utf8>>,
function => <<"build"/utf8>>,
line => 175,
value => _assert_fail@1,
start => 6499,
'end' => 6543,
pattern_start => 6510,
pattern_end => 6524})
end,
Id@1 = case erlang:element(4, Builder) of
{some, Id} ->
Id;
none ->
generate_id()
end,
{stub,
Id@1,
erlang:element(5, Builder),
Matcher@1,
Response@1,
erlang:element(6, Builder)}.