-module(dream_test@unit). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/dream_test/unit.gleam"). -export([describe/2, group/2, it/2, skip/2, before_all/1, before_each/1, after_each/1, after_all/1, with_tags/2]). -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( " Unit test DSL (no explicit context).\n" "\n" " This is the default DSL for most users: `describe` + `it` with **0‑argument**\n" " test bodies.\n" "\n" " - Tests are written as `it(\"does something\", fn() { ... })`\n" " - Hooks are also **0‑argument** functions (`before_each(fn() { ... })`)\n" " - All hooks/tests return `Result(AssertionResult, String)` so you can abort\n" " early with `Error(\"message\")` when prerequisites fail.\n" "\n" " This module builds a `dream_test/types.TestSuite(Nil)` under the hood.\n" "\n" " ## When should I use this module?\n" "\n" " - Use `dream_test/unit` for most unit tests.\n" " - Use `dream_test/unit_context` only when you want a **real context value**\n" " threaded through hooks and test bodies.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " import dream_test/matchers.{be_equal, or_fail_with, should}\n" " import dream_test/reporters/bdd\n" " import dream_test/reporters/progress\n" " import dream_test/runner\n" " import dream_test/unit.{describe, it}\n" " import gleam/string\n" "\n" " pub fn tests() {\n" " describe(\"String utilities\", [\n" " it(\"trims whitespace\", fn() {\n" " \" hello \"\n" " |> string.trim()\n" " |> should\n" " |> be_equal(\"hello\")\n" " |> or_fail_with(\"Should remove surrounding whitespace\")\n" " }),\n" " it(\"finds substrings\", fn() {\n" " \"hello world\"\n" " |> string.contains(\"world\")\n" " |> should\n" " |> be_equal(True)\n" " |> or_fail_with(\"Should find 'world' in string\")\n" " }),\n" " ])\n" " }\n" "\n" " pub fn main() {\n" " runner.new([tests()])\n" " |> runner.progress_reporter(progress.new())\n" " |> runner.results_reporters([bdd.new()])\n" " |> runner.exit_on_failure()\n" " |> runner.run()\n" " }\n" " ```\n" ). -file("src/dream_test/unit.gleam", 125). ?DOC( " Create a top-level test suite.\n" "\n" " The returned value is what you pass to `runner.new([ ... ])`.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " import dream_test/matchers.{be_equal, or_fail_with, should}\n" " import dream_test/reporters/bdd\n" " import dream_test/reporters/progress\n" " import dream_test/runner\n" " import dream_test/unit.{describe, it}\n" " import gleam/string\n" "\n" " pub fn tests() {\n" " describe(\"String utilities\", [\n" " it(\"trims whitespace\", fn() {\n" " \" hello \"\n" " |> string.trim()\n" " |> should\n" " |> be_equal(\"hello\")\n" " |> or_fail_with(\"Should remove surrounding whitespace\")\n" " }),\n" " it(\"finds substrings\", fn() {\n" " \"hello world\"\n" " |> string.contains(\"world\")\n" " |> should\n" " |> be_equal(True)\n" " |> or_fail_with(\"Should find 'world' in string\")\n" " }),\n" " ])\n" " }\n" "\n" " pub fn main() {\n" " runner.new([tests()])\n" " |> runner.progress_reporter(progress.new())\n" " |> runner.results_reporters([bdd.new()])\n" " |> runner.exit_on_failure()\n" " |> runner.run()\n" " }\n" " ```\n" "\n" " ## Parameters\n" "\n" " - `name`: the suite name (shown in reports)\n" " - `children`: the suite contents (tests, groups, and hooks)\n" "\n" " ## Returns\n" "\n" " A `TestSuite(Nil)` you can pass to `runner.new([ ... ])`.\n" ). -spec describe(binary(), list(dream_test@types:node_(nil))) -> dream_test@types:root(nil). describe(Name, Children) -> {root, nil, {group, Name, [], Children}}. -file("src/dream_test/unit.gleam", 191). ?DOC( " Create a nested group inside a suite.\n" "\n" " Groups provide structure (and hook scoping). Hooks declared in an outer group\n" " apply to tests in inner groups.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " import dream_test/matchers.{be_equal, or_fail_with, should}\n" " import dream_test/reporters/bdd\n" " import dream_test/reporters/progress\n" " import dream_test/runner\n" " import dream_test/unit.{describe, group, it}\n" " import gleam/io\n" "\n" " pub fn tests() {\n" " describe(\"Calculator\", [\n" " group(\"addition\", [\n" " it(\"adds small numbers\", fn() {\n" " 2 + 3\n" " |> should\n" " |> be_equal(5)\n" " |> or_fail_with(\"2 + 3 should equal 5\")\n" " }),\n" " it(\"adds negative numbers\", fn() {\n" " -2 + -3\n" " |> should\n" " |> be_equal(-5)\n" " |> or_fail_with(\"-2 + -3 should equal -5\")\n" " }),\n" " ]),\n" " group(\"division\", [\n" " it(\"integer division rounds toward zero\", fn() {\n" " 7 / 2\n" " |> should\n" " |> be_equal(3)\n" " |> or_fail_with(\"7 / 2 should equal 3\")\n" " }),\n" " ]),\n" " ])\n" " }\n" "\n" " pub fn main() {\n" " runner.new([tests()])\n" " |> runner.progress_reporter(progress.new())\n" " |> runner.results_reporters([bdd.new()])\n" " |> runner.exit_on_failure()\n" " |> runner.run()\n" " }\n" " ```\n" "\n" " ## Parameters\n" "\n" " - `name`: the group name (shown in reports and in `runner.TestInfo.full_name`)\n" " - `children`: nested tests/groups/hooks under this group\n" "\n" " ## Returns\n" "\n" " A `UnitNode` you include in a parent `describe`/`group` children list.\n" ). -spec group(binary(), list(dream_test@types:node_(nil))) -> dream_test@types:node_(nil). group(Name, Children) -> {group, Name, [], Children}. -file("src/dream_test/unit.gleam", 248). ?DOC( " Define a single test case.\n" "\n" " - The body is **0-arg** (`fn() { ... }`)\n" " - Return `Ok(...)` to indicate an assertion result\n" " - Return `Error(\"message\")` to abort the test with a message\n" "\n" " ## Example\n" "\n" " ```gleam\n" " import dream_test/matchers.{be_equal, or_fail_with, should}\n" " import dream_test/reporters/bdd\n" " import dream_test/reporters/progress\n" " import dream_test/runner\n" " import dream_test/unit.{describe, it}\n" " import gleam/io\n" " import gleam/string\n" "\n" " pub fn tests() {\n" " describe(\"String utilities\", [\n" " it(\"trims whitespace\", fn() {\n" " \" hello \"\n" " |> string.trim()\n" " |> should\n" " |> be_equal(\"hello\")\n" " |> or_fail_with(\"Should remove surrounding whitespace\")\n" " }),\n" " it(\"finds substrings\", fn() {\n" " \"hello world\"\n" " |> string.contains(\"world\")\n" " |> should\n" " |> be_equal(True)\n" " |> or_fail_with(\"Should find 'world' in string\")\n" " }),\n" " ])\n" " }\n" "\n" " pub fn main() {\n" " runner.new([tests()])\n" " |> runner.progress_reporter(progress.new())\n" " |> runner.results_reporters([bdd.new()])\n" " |> runner.exit_on_failure()\n" " |> runner.run()\n" " }\n" " ```\n" "\n" " ## Parameters\n" "\n" " - `name`: the test name (shown in reports)\n" " - `run`: a **0-argument** test body that returns `Result(AssertionResult, String)`\n" "\n" " ## Returns\n" "\n" " A `UnitNode` representing the test.\n" ). -spec it( binary(), fun(() -> {ok, dream_test@types:assertion_result()} | {error, binary()}) ) -> dream_test@types:node_(nil). it(Name, Run) -> {test, Name, [], unit, fun(_) -> Run() end, none}. -file("src/dream_test/unit.gleam", 261). -spec skipped_test_run(nil) -> {ok, dream_test@types:assertion_result()} | {error, binary()}. skipped_test_run(_) -> {ok, assertion_skipped}. -file("src/dream_test/unit.gleam", 324). ?DOC( " Define a skipped test.\n" "\n" " `skip` has the same shape as `it` so you can easily switch a test between\n" " running and skipped without rewriting the test body.\n" "\n" " The provided test body is preserved for that purpose, but it is **not\n" " executed** while the test is skipped.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " import dream_test/matchers.{be_equal, or_fail_with, should}\n" " import dream_test/reporters/bdd\n" " import dream_test/reporters/progress\n" " import dream_test/runner\n" " import dream_test/unit.{describe, it, skip}\n" " import gleam/io\n" "\n" " pub fn tests() {\n" " describe(\"Skipping tests\", [\n" " it(\"runs normally\", fn() {\n" " 2 + 3\n" " |> should\n" " |> be_equal(5)\n" " |> or_fail_with(\"2 + 3 should equal 5\")\n" " }),\n" " skip(\"not implemented yet\", fn() {\n" " // This test is skipped - the body is preserved but not executed\n" " 100 + 200\n" " |> should\n" " |> be_equal(300)\n" " |> or_fail_with(\"Should add large numbers\")\n" " }),\n" " it(\"also runs normally\", fn() {\n" " 0 + 0\n" " |> should\n" " |> be_equal(0)\n" " |> or_fail_with(\"0 + 0 should equal 0\")\n" " }),\n" " ])\n" " }\n" "\n" " pub fn main() {\n" " runner.new([tests()])\n" " |> runner.progress_reporter(progress.new())\n" " |> runner.results_reporters([bdd.new()])\n" " |> runner.exit_on_failure()\n" " |> runner.run()\n" " }\n" " ```\n" "\n" " ## Parameters\n" "\n" " - `name`: the test name\n" " - `run`: a **0-argument** function (accepted but never executed)\n" "\n" " ## Returns\n" "\n" " A `UnitNode` representing a skipped test (`AssertionSkipped`).\n" ). -spec skip( binary(), fun(() -> {ok, dream_test@types:assertion_result()} | {error, binary()}) ) -> dream_test@types:node_(nil). skip(Name, Run) -> Node = it(Name, Run), case Node of {test, Name@1, Tags, Kind, _, Timeout_ms} -> {test, Name@1, Tags, Kind, fun skipped_test_run/1, Timeout_ms}; Other -> Other end. -file("src/dream_test/unit.gleam", 425). ?DOC( " Run once before any tests in the current suite/group.\n" "\n" " - Runs in a sandboxed process.\n" " - If it returns `Error(\"message\")`, all tests under this scope become\n" " `SetupFailed`.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " import dream_test/matchers.{be_empty, or_fail_with, should}\n" " import dream_test/reporters/bdd\n" " import dream_test/reporters/progress\n" " import dream_test/runner\n" " import dream_test/unit.{\n" " after_all, after_each, before_all, before_each, describe, it,\n" " }\n" " import gleam/io\n" "\n" " pub fn tests() {\n" " describe(\"Database tests\", [\n" " before_all(fn() {\n" " // Start database once for all tests\n" " start_database()\n" " }),\n" " before_each(fn() {\n" " // Begin transaction before each test\n" " begin_transaction()\n" " }),\n" " it(\"creates a record\", fn() {\n" " []\n" " |> should\n" " |> be_empty()\n" " |> or_fail_with(\"Placeholder test\")\n" " }),\n" " it(\"queries records\", fn() {\n" " []\n" " |> should\n" " |> be_empty()\n" " |> or_fail_with(\"Placeholder test\")\n" " }),\n" " after_each(fn() {\n" " // Rollback transaction after each test\n" " rollback_transaction()\n" " }),\n" " after_all(fn() {\n" " // Stop database after all tests\n" " stop_database()\n" " }),\n" " ])\n" " }\n" "\n" " fn start_database() {\n" " Ok(Nil)\n" " }\n" "\n" " fn stop_database() {\n" " Ok(Nil)\n" " }\n" "\n" " fn begin_transaction() {\n" " Ok(Nil)\n" " }\n" "\n" " fn rollback_transaction() {\n" " Ok(Nil)\n" " }\n" "\n" " pub fn main() {\n" " runner.new([tests()])\n" " |> runner.progress_reporter(progress.new())\n" " |> runner.results_reporters([bdd.new()])\n" " |> runner.exit_on_failure()\n" " |> runner.run()\n" " }\n" " ```\n" "\n" " ## Parameters\n" "\n" " - `setup`: a **0-argument** function that returns `Ok(Nil)` on success or `Error(message)` on failure\n" "\n" " ## Returns\n" "\n" " A `UnitNode` representing a `before_all` hook.\n" ). -spec before_all(fun(() -> {ok, nil} | {error, binary()})) -> dream_test@types:node_(nil). before_all(Setup) -> {before_all, fun(_) -> case Setup() of {ok, _} -> {ok, nil}; {error, Message} -> {error, Message} end end}. -file("src/dream_test/unit.gleam", 517). ?DOC( " Run before each test in the current scope.\n" "\n" " - Runs in a sandboxed process.\n" " - If it returns `Error(\"message\")`, that test becomes `SetupFailed` and the\n" " body does not run.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " import dream_test/matchers.{be_empty, or_fail_with, should}\n" " import dream_test/reporters/bdd\n" " import dream_test/reporters/progress\n" " import dream_test/runner\n" " import dream_test/unit.{\n" " after_all, after_each, before_all, before_each, describe, it,\n" " }\n" " import gleam/io\n" "\n" " pub fn tests() {\n" " describe(\"Database tests\", [\n" " before_all(fn() {\n" " // Start database once for all tests\n" " start_database()\n" " }),\n" " before_each(fn() {\n" " // Begin transaction before each test\n" " begin_transaction()\n" " }),\n" " it(\"creates a record\", fn() {\n" " []\n" " |> should\n" " |> be_empty()\n" " |> or_fail_with(\"Placeholder test\")\n" " }),\n" " it(\"queries records\", fn() {\n" " []\n" " |> should\n" " |> be_empty()\n" " |> or_fail_with(\"Placeholder test\")\n" " }),\n" " after_each(fn() {\n" " // Rollback transaction after each test\n" " rollback_transaction()\n" " }),\n" " after_all(fn() {\n" " // Stop database after all tests\n" " stop_database()\n" " }),\n" " ])\n" " }\n" "\n" " fn start_database() {\n" " Ok(Nil)\n" " }\n" "\n" " fn stop_database() {\n" " Ok(Nil)\n" " }\n" "\n" " fn begin_transaction() {\n" " Ok(Nil)\n" " }\n" "\n" " fn rollback_transaction() {\n" " Ok(Nil)\n" " }\n" "\n" " pub fn main() {\n" " runner.new([tests()])\n" " |> runner.progress_reporter(progress.new())\n" " |> runner.results_reporters([bdd.new()])\n" " |> runner.exit_on_failure()\n" " |> runner.run()\n" " }\n" " ```\n" "\n" " ## Parameters\n" "\n" " - `setup`: a **0-argument** function that returns `Ok(Nil)` on success or `Error(message)` on failure\n" "\n" " ## Returns\n" "\n" " A `UnitNode` representing a `before_each` hook.\n" ). -spec before_each(fun(() -> {ok, nil} | {error, binary()})) -> dream_test@types:node_(nil). before_each(Setup) -> {before_each, fun(_) -> case Setup() of {ok, _} -> {ok, nil}; {error, Message} -> {error, Message} end end}. -file("src/dream_test/unit.gleam", 608). ?DOC( " Run after each test in the current scope.\n" "\n" " This is useful for cleanup that must always run (even after assertion\n" " failures).\n" "\n" " ## Example\n" "\n" " ```gleam\n" " import dream_test/matchers.{be_empty, or_fail_with, should}\n" " import dream_test/reporters/bdd\n" " import dream_test/reporters/progress\n" " import dream_test/runner\n" " import dream_test/unit.{\n" " after_all, after_each, before_all, before_each, describe, it,\n" " }\n" " import gleam/io\n" "\n" " pub fn tests() {\n" " describe(\"Database tests\", [\n" " before_all(fn() {\n" " // Start database once for all tests\n" " start_database()\n" " }),\n" " before_each(fn() {\n" " // Begin transaction before each test\n" " begin_transaction()\n" " }),\n" " it(\"creates a record\", fn() {\n" " []\n" " |> should\n" " |> be_empty()\n" " |> or_fail_with(\"Placeholder test\")\n" " }),\n" " it(\"queries records\", fn() {\n" " []\n" " |> should\n" " |> be_empty()\n" " |> or_fail_with(\"Placeholder test\")\n" " }),\n" " after_each(fn() {\n" " // Rollback transaction after each test\n" " rollback_transaction()\n" " }),\n" " after_all(fn() {\n" " // Stop database after all tests\n" " stop_database()\n" " }),\n" " ])\n" " }\n" "\n" " fn start_database() {\n" " Ok(Nil)\n" " }\n" "\n" " fn stop_database() {\n" " Ok(Nil)\n" " }\n" "\n" " fn begin_transaction() {\n" " Ok(Nil)\n" " }\n" "\n" " fn rollback_transaction() {\n" " Ok(Nil)\n" " }\n" "\n" " pub fn main() {\n" " runner.new([tests()])\n" " |> runner.progress_reporter(progress.new())\n" " |> runner.results_reporters([bdd.new()])\n" " |> runner.exit_on_failure()\n" " |> runner.run()\n" " }\n" " ```\n" "\n" " ## Parameters\n" "\n" " - `teardown`: a **0-argument** function that returns `Ok(Nil)` or `Error(message)`\n" "\n" " ## Returns\n" "\n" " A `UnitNode` representing an `after_each` hook.\n" ). -spec after_each(fun(() -> {ok, nil} | {error, binary()})) -> dream_test@types:node_(nil). after_each(Teardown) -> {after_each, fun(_) -> Teardown() end}. -file("src/dream_test/unit.gleam", 691). ?DOC( " Run once after all tests in the current scope.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " import dream_test/matchers.{be_empty, or_fail_with, should}\n" " import dream_test/reporters/bdd\n" " import dream_test/reporters/progress\n" " import dream_test/runner\n" " import dream_test/unit.{\n" " after_all, after_each, before_all, before_each, describe, it,\n" " }\n" " import gleam/io\n" "\n" " pub fn tests() {\n" " describe(\"Database tests\", [\n" " before_all(fn() {\n" " // Start database once for all tests\n" " start_database()\n" " }),\n" " before_each(fn() {\n" " // Begin transaction before each test\n" " begin_transaction()\n" " }),\n" " it(\"creates a record\", fn() {\n" " []\n" " |> should\n" " |> be_empty()\n" " |> or_fail_with(\"Placeholder test\")\n" " }),\n" " it(\"queries records\", fn() {\n" " []\n" " |> should\n" " |> be_empty()\n" " |> or_fail_with(\"Placeholder test\")\n" " }),\n" " after_each(fn() {\n" " // Rollback transaction after each test\n" " rollback_transaction()\n" " }),\n" " after_all(fn() {\n" " // Stop database after all tests\n" " stop_database()\n" " }),\n" " ])\n" " }\n" "\n" " fn start_database() {\n" " Ok(Nil)\n" " }\n" "\n" " fn stop_database() {\n" " Ok(Nil)\n" " }\n" "\n" " fn begin_transaction() {\n" " Ok(Nil)\n" " }\n" "\n" " fn rollback_transaction() {\n" " Ok(Nil)\n" " }\n" "\n" " pub fn main() {\n" " runner.new([tests()])\n" " |> runner.progress_reporter(progress.new())\n" " |> runner.results_reporters([bdd.new()])\n" " |> runner.exit_on_failure()\n" " |> runner.run()\n" " }\n" " ```\n" "\n" " ## Parameters\n" "\n" " - `teardown`: a **0-argument** function that returns `Ok(Nil)` or `Error(message)`\n" "\n" " ## Returns\n" "\n" " A `UnitNode` representing an `after_all` hook.\n" ). -spec after_all(fun(() -> {ok, nil} | {error, binary()})) -> dream_test@types:node_(nil). after_all(Teardown) -> {after_all, fun(_) -> Teardown() end}. -file("src/dream_test/unit.gleam", 736). ?DOC( " Attach tags to a node.\n" "\n" " Tags propagate to descendant tests and are included in `TestResult.tags`.\n" " Use tags to filter executed tests (e.g. in CI) with `runner.filter_tests`.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " import dream_test/matchers.{succeed}\n" " import dream_test/reporters/bdd\n" " import dream_test/reporters/progress\n" " import dream_test/runner\n" " import dream_test/unit.{describe, it, with_tags}\n" " import gleam/io\n" "\n" " pub fn tests() {\n" " describe(\"Tagged tests\", [\n" " it(\"fast\", fn() { Ok(succeed()) })\n" " |> with_tags([\"unit\", \"fast\"]),\n" " it(\"slow\", fn() { Ok(succeed()) })\n" " |> with_tags([\"integration\", \"slow\"]),\n" " ])\n" " }\n" "\n" " pub fn main() {\n" " runner.new([tests()])\n" " |> runner.progress_reporter(progress.new())\n" " |> runner.results_reporters([bdd.new()])\n" " |> runner.exit_on_failure()\n" " |> runner.run()\n" " }\n" " ```\n" "\n" " ## Parameters\n" "\n" " - `node`: a test or group node to tag (tags do not apply to hooks)\n" " - `tags`: tags to attach; group tags are inherited by descendant tests\n" "\n" " ## Returns\n" "\n" " The updated `UnitNode` with tags set.\n" ). -spec with_tags(dream_test@types:node_(nil), list(binary())) -> dream_test@types:node_(nil). with_tags(Node, Tags) -> case Node of {group, Name, _, Children} -> {group, Name, Tags, Children}; {test, Name@1, _, Kind, Run, Timeout_ms} -> {test, Name@1, Tags, Kind, Run, Timeout_ms}; Other -> Other end.