-module(cquill@testing). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/cquill/testing.gleam"). -export([new_context/0, with_memory_store/1, with_context/1, get_store/1, set_store/2, reset/1, next_id/1, unique_string/3, unique_email/1, unique_username/1, track_insert/3, get_tracked/2, tracked_count/2, create_tables/2, next_ids/2]). -export_type([test_context/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. -type test_context() :: {test_context, cquill@adapter@memory:memory_store(), integer(), gleam@dict:dict(binary(), list(binary()))}. -file("src/cquill/testing.gleam", 68). ?DOC( " Create a new test context with a fresh memory store.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " let ctx = new_context()\n" " // ctx.id_counter starts at 1\n" " ```\n" ). -spec new_context() -> test_context(). new_context() -> {test_context, cquill@adapter@memory:new_store(), 1, maps:new()}. -file("src/cquill/testing.gleam", 87). ?DOC( " Run a test function with a fresh memory store.\n" "\n" " This is the recommended way to write tests that need a memory store.\n" " Each test gets a completely fresh store, ensuring test isolation.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " pub fn insert_user_test() {\n" " use store <- with_memory_store()\n" "\n" " let assert Ok(store) = memory.create_table(store, \"users\", [])\n" " // ... test code\n" " }\n" " ```\n" ). -spec with_memory_store(fun((cquill@adapter@memory:memory_store()) -> TSZ)) -> TSZ. with_memory_store(Test_fn) -> Store = cquill@adapter@memory:new_store(), Test_fn(Store). -file("src/cquill/testing.gleam", 108). ?DOC( " Run a test function with a fresh test context.\n" "\n" " The context provides additional utilities like ID generation and\n" " entity tracking beyond what the raw memory store provides.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " pub fn multi_entity_test() {\n" " use ctx <- with_context()\n" "\n" " let #(ctx, user_id) = next_id(ctx)\n" " let #(ctx, email) = unique_email(ctx)\n" " // ... test code using the context\n" " }\n" " ```\n" ). -spec with_context(fun((test_context()) -> TTA)) -> TTA. with_context(Test_fn) -> Ctx = new_context(), Test_fn(Ctx). -file("src/cquill/testing.gleam", 121). ?DOC( " Get the memory store from a test context.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " let store = get_store(ctx)\n" " let result = memory.get_row(store, \"users\", \"1\")\n" " ```\n" ). -spec get_store(test_context()) -> cquill@adapter@memory:memory_store(). get_store(Ctx) -> erlang:element(2, Ctx). -file("src/cquill/testing.gleam", 135). ?DOC( " Update the memory store in a test context.\n" "\n" " Use this after performing operations that return a new store.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " let assert Ok(new_store) = memory.create_table(ctx.store, \"users\", [])\n" " let ctx = set_store(ctx, new_store)\n" " ```\n" ). -spec set_store(test_context(), cquill@adapter@memory:memory_store()) -> test_context(). set_store(Ctx, Store) -> {test_context, Store, erlang:element(3, Ctx), erlang:element(4, Ctx)}. -file("src/cquill/testing.gleam", 150). ?DOC( " Reset a test context, clearing all data but preserving table structure.\n" "\n" " Useful for running multiple scenarios within the same test.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " // After first scenario\n" " let ctx = reset(ctx)\n" " // Tables still exist but are empty, ID counter resets to 1\n" " ```\n" ). -spec reset(test_context()) -> test_context(). reset(Ctx) -> {test_context, cquill@adapter@memory:reset(erlang:element(2, Ctx)), 1, maps:new()}. -file("src/cquill/testing.gleam", 174). ?DOC( " Generate the next unique ID for test data.\n" " Returns the updated context and the new ID.\n" "\n" " IDs start at 1 and increment with each call.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " let #(ctx, id1) = next_id(ctx)\n" " let #(ctx, id2) = next_id(ctx)\n" " // id1 = 1, id2 = 2\n" " ```\n" ). -spec next_id(test_context()) -> {test_context(), integer()}. next_id(Ctx) -> Id = erlang:element(3, Ctx), New_ctx = {test_context, erlang:element(2, Ctx), Id + 1, erlang:element(4, Ctx)}, {New_ctx, Id}. -file("src/cquill/testing.gleam", 193). ?DOC( " Generate a unique string for test data (useful for emails, usernames, etc.)\n" "\n" " Combines prefix, unique ID, and suffix to create unique values.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " let #(ctx, email) = unique_string(ctx, \"user\", \"@example.com\")\n" " // email = \"user_1@example.com\"\n" "\n" " let #(ctx, username) = unique_string(ctx, \"testuser\", \"\")\n" " // username = \"testuser_2\"\n" " ```\n" ). -spec unique_string(test_context(), binary(), binary()) -> {test_context(), binary()}. unique_string(Ctx, Prefix, Suffix) -> {New_ctx, Id} = next_id(Ctx), Value = <<<<<>/binary, (erlang:integer_to_binary(Id))/binary>>/binary, Suffix/binary>>, {New_ctx, Value}. -file("src/cquill/testing.gleam", 215). ?DOC( " Generate a unique email for test data.\n" "\n" " Convenience function that generates emails like \"test_1@example.com\".\n" "\n" " ## Example\n" "\n" " ```gleam\n" " let #(ctx, email1) = unique_email(ctx)\n" " let #(ctx, email2) = unique_email(ctx)\n" " // email1 = \"test_1@example.com\"\n" " // email2 = \"test_2@example.com\"\n" " ```\n" ). -spec unique_email(test_context()) -> {test_context(), binary()}. unique_email(Ctx) -> unique_string(Ctx, <<"test"/utf8>>, <<"@example.com"/utf8>>). -file("src/cquill/testing.gleam", 227). ?DOC( " Generate a unique username for test data.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " let #(ctx, username) = unique_username(ctx)\n" " // username = \"user_1\"\n" " ```\n" ). -spec unique_username(test_context()) -> {test_context(), binary()}. unique_username(Ctx) -> unique_string(Ctx, <<"user"/utf8>>, <<""/utf8>>). -file("src/cquill/testing.gleam", 247). ?DOC( " Track an inserted entity key for later verification or cleanup.\n" "\n" " This is useful for tracking what entities were created during a test\n" " so you can verify they exist or clean them up.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " let ctx = track_insert(ctx, \"users\", \"1\")\n" " let ctx = track_insert(ctx, \"users\", \"2\")\n" " tracked_count(ctx, \"users\") // Returns 2\n" " ```\n" ). -spec track_insert(test_context(), binary(), binary()) -> test_context(). track_insert(Ctx, Table, Key) -> Existing = case gleam_stdlib:map_get(erlang:element(4, Ctx), Table) of {ok, Keys} -> Keys; {error, _} -> [] end, Updated = gleam@dict:insert(erlang:element(4, Ctx), Table, [Key | Existing]), {test_context, erlang:element(2, Ctx), erlang:element(3, Ctx), Updated}. -file("src/cquill/testing.gleam", 264). ?DOC( " Get all tracked entity keys for a table.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " let keys = get_tracked(ctx, \"users\")\n" " // Returns [\"2\", \"1\"] (most recent first)\n" " ```\n" ). -spec get_tracked(test_context(), binary()) -> list(binary()). get_tracked(Ctx, Table) -> case gleam_stdlib:map_get(erlang:element(4, Ctx), Table) of {ok, Keys} -> Keys; {error, _} -> [] end. -file("src/cquill/testing.gleam", 279). ?DOC( " Get the count of tracked entities for a table.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " let count = tracked_count(ctx, \"users\")\n" " // Returns number of entities tracked for \"users\" table\n" " ```\n" ). -spec tracked_count(test_context(), binary()) -> integer(). tracked_count(Ctx, Table) -> erlang:length(get_tracked(Ctx, Table)). -file("src/cquill/testing.gleam", 301). ?DOC( " Create multiple tables in the memory store.\n" "\n" " Each table is specified as a tuple of (table_name, primary_key_column).\n" " This is a convenience function for setting up test fixtures.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " let store = create_tables(store, [\n" " #(\"users\", \"id\"),\n" " #(\"posts\", \"id\"),\n" " #(\"comments\", \"id\"),\n" " ])\n" " ```\n" ). -spec create_tables( cquill@adapter@memory:memory_store(), list({binary(), binary()}) ) -> cquill@adapter@memory:memory_store(). create_tables(Store, Tables) -> gleam@list:fold( Tables, Store, fun(Acc_store, Table_def) -> {Name, Primary_key} = Table_def, cquill@adapter@memory:create_table(Acc_store, Name, Primary_key) end ). -file("src/cquill/testing.gleam", 319). ?DOC( " Batch generate unique IDs.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " let #(ctx, ids) = next_ids(ctx, 3)\n" " // ids = [1, 2, 3]\n" " ```\n" ). -spec next_ids(test_context(), integer()) -> {test_context(), list(integer())}. next_ids(Ctx, Count) -> _pipe = gleam@list:range(1, Count), gleam@list:fold( _pipe, {Ctx, []}, fun(Acc, _) -> {Current_ctx, Ids} = Acc, {New_ctx, Id} = next_id(Current_ctx), {New_ctx, lists:append(Ids, [Id])} end ).