-module(dream_test@gherkin@discover). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/dream_test/gherkin/discover.gleam"). -export([features/1, with_registry/2, to_suite/2, load/1, list_files/1]). -export_type([feature_discovery/0, load_result/0]). -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( " Feature discovery and loading for Gherkin tests.\n" "\n" " Provides a builder pattern for discovering `.feature` files and\n" " converting them to TestSuites without manual file parsing.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " import dream_test/gherkin/discover\n" " import dream_test/gherkin/steps.{new_registry, step}\n" " import dream_test/runner\n" "\n" " pub fn main() {\n" " let steps = new_registry()\n" " |> step(\"I have {int} items\", have_items)\n" " |> step(\"I add {int} items\", add_items)\n" "\n" " discover.features(\"features/*.feature\")\n" " |> discover.with_registry(steps)\n" " |> discover.to_suite(\"my_features\")\n" " |> runner.run_suite()\n" " }\n" " ```\n" "\n" " ## Glob Patterns\n" "\n" " Uses Erlang's `filelib:wildcard/1` for pattern matching:\n" "\n" " - `features/*.feature` — all `.feature` files in `features/`\n" " - `test/**/*.feature` — recursive search in `test/`\n" " - `*.feature` — all `.feature` files in current directory\n" "\n" ). -opaque feature_discovery() :: {feature_discovery, binary(), gleam@option:option(dream_test@gherkin@steps:step_registry()), list(dream_test@gherkin@types:feature()), list(binary())}. -type load_result() :: {load_result, list(dream_test@gherkin@types:feature()), list(binary())}. -file("src/dream_test/gherkin/discover.gleam", 98). ?DOC( " Start discovering features matching a glob pattern.\n" "\n" " ## Parameters\n" "\n" " - `pattern`: Glob pattern for `.feature` files\n" "\n" " ## Example\n" "\n" " ```gleam\n" " discover.features(\"features/**/*.feature\")\n" " |> discover.with_registry(steps)\n" " |> discover.to_suite(\"my_tests\")\n" " ```\n" ). -spec features(binary()) -> feature_discovery(). features(Pattern) -> {feature_discovery, Pattern, none, [], []}. -file("src/dream_test/gherkin/discover.gleam", 111). ?DOC( " Attach a step registry to the discovery.\n" "\n" " The registry contains all step definitions needed to execute the features.\n" "\n" " ## Parameters\n" "\n" " - `discovery`: The feature discovery builder\n" " - `registry`: Step registry with step definitions\n" ). -spec with_registry( feature_discovery(), dream_test@gherkin@steps:step_registry() ) -> feature_discovery(). with_registry(Discovery, Registry) -> {feature_discovery, erlang:element(2, Discovery), {some, Registry}, erlang:element(4, Discovery), erlang:element(5, Discovery)}. -file("src/dream_test/gherkin/discover.gleam", 223). -spec parse_feature_file(binary()) -> {ok, dream_test@gherkin@types:feature()} | {error, binary()}. parse_feature_file(Path) -> _pipe = dream_test@gherkin@parser:parse_file(Path), gleam@result:map_error( _pipe, fun(E) -> <<<>/binary, E/binary>> end ). -file("src/dream_test/gherkin/discover.gleam", 202). -spec load_all_features(list(binary())) -> load_result(). load_all_features(Files) -> Results = gleam@list:map(Files, fun parse_feature_file/1), Features = begin _pipe = Results, gleam@list:filter_map(_pipe, fun(R) -> case R of {ok, F} -> {ok, F}; {error, _} -> {error, nil} end end) end, Errors = begin _pipe@1 = Results, gleam@list:filter_map(_pipe@1, fun(R@1) -> case R@1 of {ok, _} -> {error, nil}; {error, E} -> {ok, E} end end) end, {load_result, Features, Errors}. -file("src/dream_test/gherkin/discover.gleam", 247). -spec parse_error_runner() -> dream_test@types:assertion_result(). parse_error_runner() -> {assertion_failed, {assertion_failure, <<"parse"/utf8>>, <<"Failed to parse feature file (see test name for details)"/utf8>>, none}}. -file("src/dream_test/gherkin/discover.gleam", 228). -spec error_to_suite_item(binary()) -> dream_test@types:test_suite_item(). error_to_suite_item(Error) -> Error_test = {test_case, {single_test_config, <<"Parse Error: "/utf8, Error/binary>>, [<<"Parse Error"/utf8>>, Error], [<<"parse-error"/utf8>>], unit, fun parse_error_runner/0, none, [], []}}, {suite_test, Error_test}. -file("src/dream_test/gherkin/discover.gleam", 198). -spec discover_files(binary()) -> list(binary()). discover_files(Pattern) -> dream_test_gherkin_discover_ffi:wildcard(Pattern). -file("src/dream_test/gherkin/discover.gleam", 137). ?DOC( " Build a TestSuite from discovered features.\n" "\n" " Discovers all matching files, parses them, and creates a combined TestSuite.\n" " Parse errors are collected but don't prevent other features from running.\n" "\n" " ## Parameters\n" "\n" " - `discovery`: The configured feature discovery\n" " - `suite_name`: Name for the combined test suite\n" "\n" " ## Returns\n" "\n" " A TestSuite containing all successfully parsed features.\n" " If there are parse errors, they're reported as failed tests.\n" "\n" " ## Panics\n" "\n" " Panics if `with_registry()` was not called.\n" ). -spec to_suite(feature_discovery(), binary()) -> dream_test@types:test_suite(). to_suite(Discovery, Suite_name) -> Registry = case erlang:element(3, Discovery) of {some, R} -> R; none -> erlang:error(#{gleam_error => panic, message => <<"FeatureDiscovery requires a registry. Call with_registry() first."/utf8>>, file => <>, module => <<"dream_test/gherkin/discover"/utf8>>, function => <<"to_suite"/utf8>>, line => 141}) end, Files = discover_files(erlang:element(2, Discovery)), Load_result = load_all_features(Files), Suite_items = gleam@list:map( erlang:element(2, Load_result), fun(Feature) -> Config = {feature_config, Feature, Registry}, Feature_suite = dream_test@gherkin@feature:to_test_suite( Suite_name, Config ), {suite_group, Feature_suite} end ), Error_items = gleam@list:map( erlang:element(3, Load_result), fun error_to_suite_item/1 ), All_items = lists:append(Suite_items, Error_items), {test_suite, Suite_name, [Suite_name], [], [], All_items}. -file("src/dream_test/gherkin/discover.gleam", 181). ?DOC( " Load features and return detailed results.\n" "\n" " Use this when you need access to parse errors for custom handling.\n" "\n" " ## Parameters\n" "\n" " - `discovery`: The feature discovery builder\n" "\n" " ## Returns\n" "\n" " LoadResult with lists of successfully parsed features and errors.\n" ). -spec load(feature_discovery()) -> load_result(). load(Discovery) -> Files = discover_files(erlang:element(2, Discovery)), load_all_features(Files). -file("src/dream_test/gherkin/discover.gleam", 190). ?DOC( " Get the list of files matching the discovery pattern.\n" "\n" " Useful for debugging or custom file handling.\n" ). -spec list_files(feature_discovery()) -> list(binary()). list_files(Discovery) -> discover_files(erlang:element(2, Discovery)).