-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 => <>, 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 => <>, 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 => <>, 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 => <>, 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)}.