(defmodule lamina_db_tests
(export all)
(include-lib "eunit/include/eunit.hrl"))
;; 每个测试用独立的内存库/临时文件库
(defun with-db (f)
(let ((path (filename:join (tmpdir) "test.db")))
(case (lamina_db:open path)
(`#(ok ,_)
(let ((result (catch (funcall f))))
(lamina_db:close)
(file:del_dir_r (filename:dirname path))
(case result
('ok 'ok)
(other (erlang:error other)))))
(other (erlang:error other)))))
(defun open_creates_schema_test ()
(with-db
(lambda ()
(let ((rows (lamina_db:q "SELECT value FROM meta WHERE key='schema_version'")))
(let ((v (hd (hd rows))))
(let ((n (binary_to_integer v)))
(if (=:= 2 n)
'ok
(erlang:error "schema_version != 2"))))))))
(defun reopen_idempotent_test ()
(let ((path (filename:join (tmpdir) "re.db")))
(lamina_db:open path)
(lamina_db:close)
(let ((result (lamina_db:open path)))
(lamina_db:close)
(file:del_dir_r (filename:dirname path))
(case result
(`#(ok ,_) 'ok)
(other (erlang:error other))))))
(defun insert_org_and_repo_test ()
(with-db
(lambda ()
(lamina_db:exec "INSERT INTO organizations(name,description,created_at) VALUES('myorg','desc','2026-01-01');")
(let ((org-id (lamina_db:last-rowid)))
(lamina_db:q "INSERT INTO repositories(name,organization_id,source,setup_username,setup_password_enc,fossil_path,created_at,updated_at) VALUES('repo1',?, 'local','admin',x'00','/tmp/repo1.fossil','2026-01-01','2026-01-01');" (list org-id))
(let ((rows (lamina_db:q "SELECT r.name, o.name FROM repositories r JOIN organizations o ON r.organization_id=o.id;")))
(if (=:= '(#"repo1" #"myorg") (hd rows))
'ok
(erlang:error (lists:flatten (io_lib:format "bad row: ~p" (list rows))))))))))
(defun unique_constraint_test ()
(with-db
(lambda ()
(lamina_db:exec "INSERT INTO organizations(name,description,created_at) VALUES('o1','','2026-01-01');")
(let ((dup (catch (lamina_db:exec "INSERT INTO organizations(name,description,created_at) VALUES('o1','','2026-01-01');"))))
(if (is_tuple dup)
'ok
(erlang:error "duplicate org name allowed"))))))
;;---- helpers ----
(defun tmpdir ()
(let* ((cwd (element 2 (file:get_cwd)))
(base (filename:join cwd "_build/tmp")))
(filelib:ensure_dir (filename:join base "x"))
(let* ((name (integer_to_list (element 3 (os:timestamp))))
(dir (filename:join base name)))
(file:make_dir dir)
dir)))