30
30
-include("eunit_internal.hrl").
33
-export([dlist_next/1, uniq/1, fun_parent/1, is_string/1, browse_fun/1,
34
command/1, command/2, command/3, trie_new/0, trie_store/2,
35
trie_match/2, split_node/1, consult_file/1, list_dir/1,
36
format_exit_term/1, format_exception/1, format_error/1]).
33
-export([dlist_next/1, uniq/1, fun_parent/1, is_string/1, command/1,
34
command/2, command/3, trie_new/0, trie_store/2, trie_match/2,
35
split_node/1, consult_file/1, list_dir/1, format_exit_term/1,
36
format_exception/1, format_error/1]).
39
39
%% Type definitions for describing exceptions
153
153
error_msg("application not found", "~w", [A]);
154
154
format_error({file_read_error, {_R, Msg, F}}) ->
155
155
error_msg("error reading file", "~s: ~s", [Msg, F]);
156
format_error({context_error, setup_failed, Exception}) ->
156
format_error({setup_failed, Exception}) ->
157
157
error_msg("context setup failed", "~s",
158
158
[format_exception(Exception)]);
159
format_error({context_error, cleanup_failed, Exception}) ->
159
format_error({cleanup_failed, Exception}) ->
160
160
error_msg("context cleanup failed", "~s",
161
161
[format_exception(Exception)]);
162
format_error({context_error, instantiation_failed, Exception}) ->
162
format_error({instantiation_failed, Exception}) ->
163
163
error_msg("instantiation of subtests failed", "~s",
164
164
[format_exception(Exception)]).
310
310
%% ---------------------------------------------------------------------
311
311
%% Get the name of the containing function for a fun. (This is encoded
312
312
%% in the name of the generated function that implements the fun.)
314
{module, M} = erlang:fun_info(F, module),
315
315
{name, N} = erlang:fun_info(F, name),
316
316
case erlang:fun_info(F, type) of
317
317
{type, external} ->
318
{arity, A} = erlang:fun_info(F, arity),
321
list_to_atom(string:sub_string(S, 2, string:chr(S, $/) - 1))
321
[$-|S] = atom_to_list(N),
322
C1 = string:chr(S, $/),
323
C2 = string:chr(S, $-),
324
{M, list_to_atom(string:sub_string(S, 1, C1 - 1)),
325
list_to_integer(string:sub_string(S, C1 + 1, C2 - 1))}
325
329
fun_parent_test() ->
326
fun_parent_test = fun_parent(fun () -> ok end).
330
{?MODULE,fun_parent_test,0} = fun_parent(fun () -> ok end).
330
333
%% ---------------------------------------------------------------------
331
334
%% Ye olde uniq function
352
%% ---------------------------------------------------------------------
353
%% Apply arbitrary unary function F with dummy arguments "until it
354
%% works". (F must be side effect free! It will be called repeatedly.)
355
%% No exceptions will be thrown unless the function actually crashes for
356
%% some other reason than being unable to match the argument.
358
%% @spec (F::(any()) -> any()) -> {Value::any(), Result::any()}
361
browse_fun(F, arg_values()).
363
browse_fun(F, Next) ->
366
case try_apply(F, V) of
369
{error, function_clause} ->
370
browse_fun(F, Next1);
372
erlang:error({badarity, {F, 1}});
373
{error, {Class, Reason, Trace}} ->
374
erlang:raise(Class, Reason, Trace)
377
%% tried everything - this ought to provoke an error
381
%% Apply argument to function and report whether it succeeded (and with
382
%% what return value), or failed due to bad arity or a simple top-level
383
%% function_clause error, or if it crashed in some other way.
385
%% @spec (F::(any()) -> any(), V::any()) ->
386
%% {ok, Result::any()}
387
%% | {error, function_clause | badarity | eunit_test:exception()}
390
case erlang:fun_info(F, arity) of
392
{module, M} = erlang:fun_info(F, module),
393
{name, N} = erlang:fun_info(F, name),
394
try_apply(F, Arg, M, N);
399
try_apply(F, Arg, M, N) ->
403
error:function_clause ->
404
case erlang:get_stacktrace() of
405
[{M, N, _Args} | _] ->
406
{error, function_clause};
408
{error, {error, function_clause, Trace}}
411
{error, {Class, Reason, erlang:get_stacktrace()}}
414
%% test value producers for function browsing
417
Vs = [undefined, ok, true, false, 0, 1],
418
fun () -> arg_values(Vs) end.
420
arg_values([V | Vs]) ->
421
[V | fun () -> arg_values(Vs) end];
426
fun () -> arg_tuples(0) end.
428
arg_tuples(N) when N >= 0, N =< 12 ->
429
[erlang:make_tuple(N, undefined) | fun () -> arg_tuples(N + 1) end];
434
fun () -> arg_lists(0) end.
436
arg_lists(N) when N >= 0, N =< 12 ->
437
[lists:duplicate(N, undefined) | fun () -> arg_lists(N + 1) end];
442
browse_fun_test_() ->
444
[?_assertError({badarity, {_, 1}}, browse_fun(fun () -> ok end)),
445
?_assertError({badarity, {_, 1}}, browse_fun(fun (_,_) -> ok end)),
446
?_assertError(function_clause, browse_fun(fun (42) -> ok end)),
447
?_test({_, 17} = browse_fun(fun (_) -> 17 end)),
448
?_test({_, 17} = browse_fun(fun (undefined) -> 17 end)),
449
?_test({_, 17} = browse_fun(fun (ok) -> 17 end)),
450
?_test({_, 17} = browse_fun(fun (true) -> 17 end)),
451
?_test({_, 17} = browse_fun(fun ({}) -> 17 end)),
452
?_test({_, 17} = browse_fun(fun ({_}) -> 17 end)),
453
?_test({_, 17} = browse_fun(fun ({_,_}) -> 17 end)),
454
?_test({_, 17} = browse_fun(fun ({_,_,_}) -> 17 end)),
455
?_test({_, 17} = browse_fun(fun ([]) -> 17 end)),
456
?_test({_, 17} = browse_fun(fun ([_]) -> 17 end)),
457
?_test({_, 17} = browse_fun(fun ([_,_]) -> 17 end)),
458
?_test({_, 17} = browse_fun(fun ([_,_,_]) -> 17 end))
463
354
%% ---------------------------------------------------------------------
464
355
%% Replacement for os:cmd
357
%% TODO: Better cmd support, especially on Windows (not much tested)
358
%% TODO: Can we capture stderr separately somehow?
467
361
command(Cmd, "").
625
519
[{"basic representation",
626
[?_assert(trie_new() == gb_trees:empty()),
520
[?_assert(trie_new() =:= gb_trees:empty()),
627
521
?_assert(trie_store([1], trie_new())
628
== gb_trees:insert(1, [], gb_trees:empty())),
522
=:= gb_trees:insert(1, [], gb_trees:empty())),
629
523
?_assert(trie_store([1,2], trie_new())
630
== gb_trees:insert(1,
631
gb_trees:insert(2, [],
634
?_assert([] == trie_store([1], [])),
635
?_assert([] == trie_store([], gb_trees:empty()))
524
=:= gb_trees:insert(1,
525
gb_trees:insert(2, [],
528
?_assert([] =:= trie_store([1], [])),
529
?_assert([] =:= trie_store([], gb_trees:empty()))
637
531
{"basic storing and matching",
638
532
[?_test(no = trie_match([], trie_new())),