Packages

A compile-time safe database library for Gleam - Ecto-inspired schemas, composable queries, and adapter-based persistence

Current section

Files

Jump to
cquill src cquill@testing.erl
Raw

src/cquill@testing.erl

-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 = <<<<<<Prefix/binary, "_"/utf8>>/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
).