Files
zeekay 9ad5515323 ci: add rebar3 build/test CI, fix OTP 29 + test isolation
Build the ezap Erlang binding with rebar3 and run it green on modern OTP.

rebar.config: test-profile deps proper 1.5.0 + meck 1.2.0 (meck 1.0.0 fails
to compile on OTP 29 — legacy `catch` is now an error), CT dir test/.

.github/workflows/ci.yml: push-to-main + PR + workflow_dispatch, OTP 26/27
matrix via erlef/setup-beam, runs `rebar3 compile/eunit/ct`.

src/schema_zap.erl, test/test_zap.erl: strip fossil `-type({{record,_},...})`
attributes. Pre-OTP-27 epp split typed records into a separate record-type
attr with bare-integer annotations; OTP 29 erl_lint crashes on these
(erl_anno violation). Modern epp emits typed -record forms directly, so these
attrs are dead weight; the -record decls already carry the fields.

test isolation: ezap_promise_sup / ezap_capability_sup are locally registered,
but teardown used exit(Pid, normal) — a no-op against an exit-trapping
supervisor — leaking the registered name and failing the next test with
{already_started,_}. Add ezap_test_utils:stop_sup/1 (unlink+monitor+kill+wait)
and use it everywhere; thirdCap_test_/basicCap_test_ now start and stop their
own promise supervisor instead of relying on a leak from a prior test.

bin/run_test: erlang:get_stacktrace/0 (removed in OTP 24) -> Class:Error:Stack.
2026-06-20 21:33:37 -07:00

87 lines
2.4 KiB
Erlang
Executable File

#!/usr/bin/env escript
%% -*- mode: erlang -*-
%%! -pa /usr/local/include
-include("test.zap.hrl").
-define(SKIP, 127).
main([File, Case, Test]) ->
{ok, Message} = ezap_message:read_file(File),
run_test(Case, Test, Message);
main([Case, Test]) ->
run_test(Case, Test, undefined);
main(Args) ->
io:format(standard_error, "ezap_test unknown args: ~p~n", [Args]),
halt(?SKIP).
run_test(Case, Test, Message) when is_list(Case) ->
try
run_test(list_to_atom(Case), list_to_atom(Test), Message)
catch
Class:Error:Stack ->
io:format(standard_error, "ezap_test error: ~p:~p ~p~n", [Class, Error, Stack])
end;
run_test(decode, Test, Message) ->
decode(Test, Message);
run_test(encode, Test, undefined) ->
io:setopts([{encoding, unicode}]),
io:put_chars( ezap_message:write(encode(Test)) );
run_test(Action, Test, _) ->
not_implemented(Action, Test).
not_implemented(Action, Test) ->
io:format(standard_error, "Unknown test: ~p ~p.~n", [Action, Test]),
halt(?SKIP).
decode(simpleTest, Msg) ->
{ok, Root} = test(root, 'SimpleTest', Msg),
io:format("(int = ~b, msg = \"~s\")~n",
[test(get, int, Root), test(get, msg, Root)]);
decode(textListTypeTest, Msg) ->
{ok, Root} = test(root, 'ListTest', Msg),
io:format("(textList = [~s])~n",
[string:join(
[io_lib:format("\"~s\"", [S])
|| S <- test(get, textList, Root)],
", ")]
);
decode(uInt8DefaultValueTest, Msg) ->
{ok, Root} = test(root, 'TestDefaults', Msg),
io:format("(uInt8Field = ~b)~n",
[test(get, uInt8Field, Root)]);
decode(constTest, _Msg) ->
io:format("(msg = \"~s\")~n", [test(const, constTestValue)]);
decode(Test, _) ->
not_implemented(decode, Test).
encode(simpleTest) ->
{ok, Root} = test(root, 'SimpleTest'),
ok = test(set, int, 1234567890, Root),
ok = test(set, msg, <<"a short message...">>, Root),
Root;
encode(textListTypeTest) ->
{ok, Root} = test(root, 'ListTest'),
ok = test(set, textList, [<<"foo">>, <<"bar">>, <<"baz">>], Root),
Root;
encode(uInt8DefaultValueTest) ->
{ok, Root} = test(root, 'TestDefaults'),
ok = test(set, uInt8Field, 0, Root),
Root;
encode(constTest) ->
{ok, Root} = test(root, 'SimpleTest'),
ok = test(set, msg, test(const, constTestValue), Root),
Root;
encode(Test) ->
not_implemented(encode, Test).