
do(["test"]) ->
    do_tests();
do(["test" | Tests]) ->
    do_tests(Tests);
do(["tests"]) ->
    do_tests();

do_runall_tests() ->
    lists:foreach(fun run_mod_main/1, test_mods()).


do_tests(List) ->
    lists:foreach(fun run_test/1, List).

% n
run_test(TestName) ->
    % we have two candidate atoms
    C1 = list_to_atom(TestName),
    C2 = list_to_atom("gsc_test_" ++ TestName),
    KnownMods = test_mods(),
    IsC1 = lists:member(C1, KnownMods),
    IsC2 = lists:member(C2, KnownMods),
    if
        IsC1 -> rmm(C1);
        IsC2 -> rmm(C2);
        true -> error({no_such_test, TestName})
    end.


rmm(X) -> run_mod_main(X).

% KnownTests = test_mods(),
% TestMods = ensure_all_known([], List, KnownTests),
% lists:foreach(fun run_mod_main/1, TestMods).


%ensure_all_known(Acc, [], _) ->
%    lists:sort(Acc);
%ensure_all_known(Acc, [T | Ts], Knowns) ->
%    case lists:member(T, Knowns) of
%
%    end.


test_mods() ->
    known_modules_with_prefix("gsc_test").

known_modules_with_prefix(Pfx) ->
    ModsZipBeamsZipLoaded = code:all_available(),
    kmp(Pfx, ModsZipBeamsZipLoaded, []).

kmp(_Pfx, [], Acc) ->
    lists:sort(Acc);
kmp(Pfx, [{ModStr, _BeamPath, _Loaded} | Rest], Acc) ->
    case lists:prefix(Pfx, ModStr) of
        false -> kmp(Pfx, Rest, Acc);
        true  -> kmp(Pfx, Rest, [list_to_atom(ModStr) | Acc])
    end.

run_mod_main(Mod) ->
    io:format("========================================\n"
              "~p:main()\n"
              "========================================\n",
              [Mod]),
    try
        Mod:main()
    catch
        Err:ErrType:Trace ->
            io:format("~p: ~p~n", [Err, ErrType]),
            io:format("Trace:~n~p~n", [Trace])
    end.

do_tlist() ->
    lists:foreach(
        fun(ModName) ->
            io:format("~s~n", [ModName])
        end,
        test_mods()
    ).


tokenizers_agree(File) ->
    gso_tokens(File) =:= so_tokens(File).
