%% WARNING: THESE TESTS TAKE A LONG TIME TO RUN
-module(musicians_tests).
-include_lib("eunit/include/eunit.hrl").
-define(INSTRUMENTS, [a,b,c,d,e,f,g,h]).

rand_name_test_() ->
    {"Make sure that random names are generated",
     {setup,
      fun setup_many_good/0,
      fun teardown_many/1,
      fun test_names/1}}.

eventual_crash_test_() ->
    {"Checks that bad musicians die at some point, while"
     "good ones don't",
     {inparallel,
      [{timeout, 20000, crash()},
       {timeout, 20000, nocrash()}]}}.

crash() ->
    {ok, Pid} = musicians:start_link(drum, bad),
    Ref = erlang:monitor(process, Pid),
    unlink(Pid),
    Rec = receive
        {'DOWN', Ref, process, Pid, _R} -> ok
        after 19000 -> timeout
    end,
    ?_assertEqual(ok, Rec).

nocrash() ->
    {ok, Pid} = musicians:start_link(carhorn, good),
    Ref = erlang:monitor(process, Pid),
    unlink(Pid),
    Rec = receive
        {'DOWN', Ref, process, Pid, _R} -> ok
        after 19000 -> musicians:stop(carhorn), timeout
    end,
    ?_assertEqual(timeout, Rec).

setup_many_good() ->
    [element(2,musicians:start_link(X, good)) ||
        X <- ?INSTRUMENTS].

teardown_many(_) ->
    [musicians:stop(X) || X <- ?INSTRUMENTS].

test_names(Musicians) ->
    Names = [find_name(M) || M <- Musicians],
    SetNames = ordsets:to_list(ordsets:from_list(Names)),
    ?_assert(2 < length(SetNames)). % totally arbitrary ratio

find_name(Inst) ->
    {status, _Pid, _, [_Dict, _Status, _Ancestor, _,
     [_Header, _,
      {data, [{"State", {state, Name, _, _}}]}]]} = sys:get_status(Inst),
    Name.

 WARNING: THESE TESTS TAKE A LONG TIME TO RUN
 totally arbitrary ratio

-module(musicians_tests).
-include_lib("eunit/include/eunit.hrl").
-define(INSTRUMENTS, [a,b,c,d,e,f,g,h]).

rand_name_test_() ->
    {"Make sure that random names are generated",
     {setup,
      fun setup_many_good/0,
      fun teardown_many/1,
      fun test_names/1}}.

eventual_crash_test_() ->
    {"Checks that bad musicians die at some point, while"
     "good ones don't",
     {inparallel,
      [{timeout, 20000, crash()},
       {timeout, 20000, nocrash()}]}}.

crash() ->
    {ok, Pid} = musicians:start_link(drum, bad),
    Ref = erlang:monitor(process, Pid),
    unlink(Pid),
    Rec = receive
        {'DOWN', Ref, process, Pid, _R} -> ok
        after 19000 -> timeout
    end,
    ?_assertEqual(ok, Rec).

nocrash() ->
    {ok, Pid} = musicians:start_link(carhorn, good),
    Ref = erlang:monitor(process, Pid),
    unlink(Pid),
    Rec = receive
        {'DOWN', Ref, process, Pid, _R} -> ok
        after 19000 -> musicians:stop(carhorn), timeout
    end,
    ?_assertEqual(timeout, Rec).

setup_many_good() ->
    [element(2,musicians:start_link(X, good)) ||
        X <- ?INSTRUMENTS].

teardown_many(_) ->
    [musicians:stop(X) || X <- ?INSTRUMENTS].

test_names(Musicians) ->
    Names = [find_name(M) || M <- Musicians],
    SetNames = ordsets:to_list(ordsets:from_list(Names)),

find_name(Inst) ->
    {status, _Pid, _, [_Dict, _Status, _Ancestor, _,
     [_Header, _,
      {data, [{"State", {state, Name, _, _}}]}]]} = sys:get_status(Inst),
    Name.
