Fosi Fossil Service
Small teams. Open source. Built on Fossil.

CaaS / Lamina

Unified Management for Fossil Repositories

Public | Owner: CaaS | Default branch: trunk | Last update: 2026-10-25 00:41

Artifact 054a1e45a78cb0d97b3e58a7dd71d4cf3b45902e887bfef4e4bcf4b7aff20941:


-module(nova_basic_handler_prop_tests).
-include_lib("proper/include/proper.hrl").
-include_lib("eunit/include/eunit.hrl").

-define(CALLBACK, fun dummy_mod:dummy_fun/1).

%%====================================================================
%% Generators
%%====================================================================

non_post_method() ->
    oneof([<<"GET">>, <<"PUT">>, <<"DELETE">>, <<"PATCH">>, <<"HEAD">>]).

json_value() ->
    oneof([#{}, #{<<"k">> => <<"v">>}, #{<<"n">> => 1}]).

ws_controller_data() ->
    oneof([#{}, #{data => value}, #{x => 1, y => 2}]).

ws_frame() ->
    oneof([{text, <<"hello">>}, {binary, <<1,2,3>>}, {text, <<>>}]).

%%====================================================================
%% Properties
%%====================================================================

prop_json_post_201() ->
    ?FORALL(JSON, json_value(),
            begin
                Req = nova_test_helper:mock_req(<<"POST">>, <<"/">>),
                {ok, Req1} = nova_basic_handler:handle_json({json, JSON}, ?CALLBACK, Req),
                maps:get(resp_status_code, Req1) =:= 201
            end).

prop_json_non_post_200() ->
    ?FORALL({Method, JSON}, {non_post_method(), json_value()},
            begin
                Req = nova_test_helper:mock_req(Method, <<"/">>),
                {ok, Req1} = nova_basic_handler:handle_json({json, JSON}, ?CALLBACK, Req),
                maps:get(resp_status_code, Req1) =:= 200
            end).

prop_redirect_always_302() ->
    ?FORALL(Route, binary(),
            begin
                Req = nova_test_helper:mock_req(<<"GET">>, <<"/">>),
                {ok, Req1} = nova_basic_handler:handle_redirect({redirect, Route}, ?CALLBACK, Req),
                maps:get(resp_status_code, Req1) =:= 302 andalso
                maps:get(<<"location">>, maps:get(resp_headers, Req1)) =:= Route
            end).

prop_ws_ok_preserves_data() ->
    ?FORALL(Data, ws_controller_data(),
            begin
                State = #{controller_data => #{}, commands => []},
                Result = nova_basic_handler:handle_ws({ok, Data}, State),
                maps:get(controller_data, Result) =:= Data
            end).

prop_ws_reply_appends_command() ->
    ?FORALL({Frame, Data}, {ws_frame(), ws_controller_data()},
            begin
                State = #{controller_data => #{}, commands => []},
                Result = nova_basic_handler:handle_ws({reply, Frame, Data}, State),
                maps:get(commands, Result) =:= [Frame] andalso
                maps:get(controller_data, Result) =:= Data
            end).

%%====================================================================
%% EUnit wrappers — setup/cleanup nova env once for the whole suite
%%====================================================================

proper_test_() ->
    Opts = [{numtests, 100}, {to_file, user}],
    {setup,
     fun() -> nova_test_helper:setup_nova_env() end,
     fun(Prev) -> nova_test_helper:cleanup_nova_env(Prev) end,
     [
      {"json POST always 201",
       ?_assert(proper:quickcheck(prop_json_post_201(), Opts))},
      {"json non-POST always 200",
       ?_assert(proper:quickcheck(prop_json_non_post_200(), Opts))},
      {"redirect always 302 with location",
       ?_assert(proper:quickcheck(prop_redirect_always_302(), Opts))},
      {"ws ok preserves controller_data",
       ?_assert(proper:quickcheck(prop_ws_ok_preserves_data(), Opts))},
      {"ws reply appends frame to commands",
       ?_assert(proper:quickcheck(prop_ws_reply_appends_command(), Opts))}
     ]}.

Clone

You can clone this repository with the following command:

fossil clone https://fosi.dev/CaaS/Lamina

Contribute

The best way to contribute is through e-mail. See the project documentation for more details.