From 577da1828e1db26934ecc4e295a106b0b0f318fc Mon Sep 17 00:00:00 2001 From: Paul Guyot Date: Sun, 27 Aug 2023 09:47:11 +0200 Subject: [PATCH] Fix exception classes in estdlib Replace all erroneous uses of throw with calls to `error/1`. Also update etest to properly test for exception classes, thus asserting the compatibility with Erlang/OTP Also remove duplicate etest.hrl header Signed-off-by: Paul Guyot --- CHANGELOG.md | 1 + libs/estdlib/src/erlang.erl | 13 ++-- libs/estdlib/src/io_lib.erl | 16 ++--- libs/estdlib/src/lists.erl | 2 +- libs/estdlib/src/logger.erl | 4 +- libs/estdlib/src/maps.erl | 97 ++++++++++++------------------ libs/etest/src/etest.erl | 45 +++++++++----- libs/include/etest.hrl | 28 +++++++-- tests/libs/alisp/etest.hrl | 64 -------------------- tests/libs/estdlib/test_io_lib.erl | 14 ++--- tests/libs/estdlib/test_lists.erl | 30 ++++----- tests/libs/estdlib/test_logger.erl | 10 +-- tests/libs/estdlib/test_maps.erl | 32 +++++----- 13 files changed, 152 insertions(+), 204 deletions(-) delete mode 100644 tests/libs/alisp/etest.hrl diff --git a/CHANGELOG.md b/CHANGELOG.md index 750101e7c5..8c7a801b65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed support for big endian CPUs (such as some MIPS CPUs). - Fixed STM32 not aborting when `AVM_ABORT()` is used - Fixed a bug that would leave the STM32 trapped in a loop on hard faults, rather than aborting +- Fixed classes of exceptions in estdlib. ### Added diff --git a/libs/estdlib/src/erlang.erl b/libs/estdlib/src/erlang.erl index f9a3e97426..706232548f 100644 --- a/libs/estdlib/src/erlang.erl +++ b/libs/estdlib/src/erlang.erl @@ -338,7 +338,7 @@ apply(Module, Function, Args) -> [Arg1, Arg2, Arg3, Arg4, Arg5, Arg6] -> Module:Function(Arg1, Arg2, Arg3, Arg4, Arg5, Arg6); _ -> - throw(badarg) + error(badarg) end. %%----------------------------------------------------------------------------- @@ -356,10 +356,9 @@ is_map(_Map) -> %%----------------------------------------------------------------------------- %% @param Map the map %% @returns the size of the map -%% @throws {badmap, Map} %% @doc Returns the size of (i.e., the number of entries in) the map %% -%% This function throws a `{badmap, Map}' exception if `Map' is not a map. +%% This function raises a `{badmap, Map}' error if `Map' is not a map. %% %% This function may be used in a guard expression. %% @end @@ -372,11 +371,10 @@ map_size(_Map) -> %% @param Key the key to get %% @param Map the map from which to get the value %% @returns the value in `Map' associated with `Key', if it exists. -%% @throws {badkey, Key} | {badmap, Map} %% @doc Get the value in `Map' associated with `Key', if it exists. %% -%% This function throws a `{badkey, Key}' exception if 'Key' does not occur in `Map' or -%% a `{badmap, Map}' if `Map' is not a map. +%% This function raises a `{badkey, Key}' error if 'Key' does not occur in +%% `Map' or a `{badmap, Map}' if `Map' is not a map. %% %% This function may be used in a guard expression. %% @end @@ -389,10 +387,9 @@ map_get(_Key, _Map) -> %% @param Key the key %% @param Map the map %% @returns `true' if `Key' is associated with a value in `Map'; `false', otherwise. -%% @throws {badmap, Map} %% @doc Return `true' if `Key' is associated with a value in `Map'; `false', otherwise. %% -%% This function throws a `{badmap, Map}' exception if `Map' is not a map. +%% This function raises a `{badmap, Map}' error if `Map' is not a map. %% %% This function may be used in a guard expression. %% @end diff --git a/libs/estdlib/src/io_lib.erl b/libs/estdlib/src/io_lib.erl index 8f79ba7f13..4c2b6304ff 100644 --- a/libs/estdlib/src/io_lib.erl +++ b/libs/estdlib/src/io_lib.erl @@ -47,7 +47,7 @@ format(Format, Args) -> true -> interleave(FormatTokens, Instr, Args, []); false -> - throw(badarg) + error(badarg) end. %% @@ -145,7 +145,7 @@ parse_format_control([$+ | Rest], Format) -> {Format#format{control = '+'}, Rest parse_format_control([$e | Rest], Format) -> {Format#format{control = e}, Rest}; parse_format_control([$f | Rest], Format) -> {Format#format{control = f}, Rest}; parse_format_control([$g | Rest], Format) -> {Format#format{control = g}, Rest}; -parse_format_control(_String, _Format) -> throw({badarg, _String}). +parse_format_control(_String, _Format) -> error({badarg, _String}). %% @private parse_integer([$- | Tail]) -> @@ -251,8 +251,8 @@ format_spw(#format{control = Control, mod = undefined}, T) when is_binary(T) -> format_spw(#format{control = s, mod = Mod}, L) when is_list(L) -> Flatten = lists:flatten(L), case {Mod, test_string_class(Flatten)} of - {_, not_a_string} -> throw(badarg); - {undefined, unicode} -> throw(badarg); + {_, not_a_string} -> error(badarg); + {undefined, unicode} -> error(badarg); {_, _} -> Flatten end; format_spw(#format{control = p} = Format, L) when is_list(L) -> @@ -263,7 +263,7 @@ format_spw(#format{control = p} = Format, L) when is_list(L) -> format_spw(#format{control = w} = Format, L) when is_list(L) -> [$[, lists:join($,, [format_spw(Format, E) || E <- L]), $]]; format_spw(#format{control = s}, _) -> - throw(badarg); + error(badarg); format_spw(_Format, T) when is_integer(T) -> erlang:integer_to_list(T); format_spw(_Format, T) when is_float(T) -> @@ -317,7 +317,7 @@ format_integer(#format{control = 'B', precision = Base}, T) when is_integer(T) - format_integer(#format{control = b, precision = Base}, T) when is_integer(T) -> string:to_lower(integer_to_list(T, Base)); format_integer(_Format, _) -> - throw(badarg). + error(badarg). %% @private format_float(#format{control = f, precision = undefined}, T) when is_float(T) -> @@ -341,7 +341,7 @@ format_float(#format{control = C, precision = Precision}, T) when -> format_scientific(T, Precision, 0); format_float(_Format, _) -> - throw(badarg). + error(badarg). %% @private format_scientific(T, Precision, E) when (T < 1 andalso T > 0) orelse (T > -1 andalso T < 0) -> @@ -366,7 +366,7 @@ format_char(#format{precision = Precision} = Format, T) when Precision =/= undef [Ch] = format_char(Format#format{field_width = undefined, precision = undefined}, T), lists:duplicate(Precision, Ch); format_char(_, _) -> - throw(badarg). + error(badarg). %% @private %% String classes: diff --git a/libs/estdlib/src/lists.erl b/libs/estdlib/src/lists.erl index 63471d47aa..4dfbea6a98 100644 --- a/libs/estdlib/src/lists.erl +++ b/libs/estdlib/src/lists.erl @@ -461,7 +461,7 @@ seq(From, To, Incr) when (To > (From - Incr) andalso Incr < 0) orelse (Incr =:= 0 andalso From =/= To) -> - throw(badarg); + error(badarg); seq(To, To, 0) -> [To]; seq(From, To, Incr) -> diff --git a/libs/estdlib/src/logger.erl b/libs/estdlib/src/logger.erl index ed4f458ce8..e74abb3c20 100644 --- a/libs/estdlib/src/logger.erl +++ b/libs/estdlib/src/logger.erl @@ -544,9 +544,7 @@ validate_level(Level) when Level == info orelse Level == debug -> - Level; -validate_level(Level) -> - throw({unsupported_level, Level}). + Level. %% @private to_int_level(emergency) -> diff --git a/libs/estdlib/src/maps.erl b/libs/estdlib/src/maps.erl index f266910802..826aad1554 100644 --- a/libs/estdlib/src/maps.erl +++ b/libs/estdlib/src/maps.erl @@ -67,11 +67,10 @@ %% @param Key the key to get %% @param Map the map from which to get the value %% @returns the value in `Map' associated with `Key', if it exists. -%% @throws {badkey, Key} | {badmap, Map} %% @doc Get the value in `Map' associated with `Key', if it exists. %% -%% This function throws a `{badkey, Key}' exception if 'Key' does not occur in `Map' or -%% a `{badmap, Map}' if `Map' is not a map. +%% This function raises a `{badkey, Key}' error if 'Key' does not occur in +%% `Map' or a `{badmap, Map}' error if `Map' is not a map. %% @end %%----------------------------------------------------------------------------- -spec get(Key :: key(), Map :: map()) -> Value :: value(). @@ -82,13 +81,12 @@ get(Key, Map) -> %% @param Key the key %% @param Map the map %% @param Default default value -%% @throws {badmap, Map} %% @returns the value in `Map' associated with `Key', or `Default', if %% the key is not associated with a value in `Map'. %% @doc Get the value in `Map' associated with `Key', or `Default', if %% the key is not associated with a value in `Map'. %% -%% This function throws a `{badmap, Map}' exception if `Map' is not a map. +%% This function raises a `{badmap, Map}' error if `Map' is not a map. %% @end %%----------------------------------------------------------------------------- -spec get(Key :: key(), Map :: map(), Default :: term()) -> Value :: value(). @@ -96,7 +94,7 @@ get(Key, Map, Default) -> try ?MODULE:get(Key, Map) catch - _:{badkey, _} -> + error:{badkey, _} -> Default end. @@ -104,10 +102,9 @@ get(Key, Map, Default) -> %% @param Key the key %% @param Map the map %% @returns `true' if `Key' is associated with a value in `Map'; `false', otherwise. -%% @throws {badmap, Map} %% @doc Return `true' if `Key' is associated with a value in `Map'; `false', otherwise. %% -%% This function throws a `{badmap, Map}' exception if `Map' is not a map. +%% This function raises a `{badmap, Map}' error if `Map' is not a map. %% @end %%----------------------------------------------------------------------------- -spec is_key(Key :: key(), Map :: map()) -> boolean(). @@ -119,26 +116,24 @@ is_key(Key, Map) -> %% @param Value the value %% @param Map the map %% @returns A copy of `Map' containing the `{Key, Value}' association. -%% @throws {badmap, Map} %% @doc Return the map containing the `{Key, Value}' association. %% %% If `Key' occurs in `Map' then it will be over-written. Otherwise, the %% returned map will contain the new association. %% -%% This function throws a `{badmap, Map}' exception if `Map' is not a map. +%% This function raises a `{badmap, Map}' error if `Map' is not a map. %% @end %%----------------------------------------------------------------------------- -spec put(Key :: key(), Value :: value(), Map :: map()) -> map(). put(Key, Value, Map) when is_map(Map) -> Map#{Key => Value}; put(_Key, _Value, Map) when not is_map(Map) -> - throw({badmap, Map}). + error({badmap, Map}). %%----------------------------------------------------------------------------- %% @param Map the map %% @returns an iterator structure that can be used to iterate over associations %% in a map. -%% @throws {badmap, Map} %% @see next/1 %% @doc Return an iterator structure that can be used to iterate over associations %% in a map. @@ -146,24 +141,23 @@ put(_Key, _Value, Map) when not is_map(Map) -> %% In general, users should make no assumptions about the order in which entries %% appear in an iterator. The order of entries in a map is implementation-defined. %% -%% This function throws a `{badmap, Map}' exception if `Map' is not a map. +%% This function raises a `{badmap, Map}' error if `Map' is not a map. %% @end %%----------------------------------------------------------------------------- -spec iterator(Map :: map()) -> iterator(). iterator(Map) when is_map(Map) -> [0 | Map]; iterator(Map) -> - throw({badmap, Map}). + error({badmap, Map}). %%----------------------------------------------------------------------------- %% @param Iterator a map iterator %% @returns the key and value, along with the next iterator in the map, or the %% atom `none' if there are no more items over which to iterate. -%% @throws badarg %% @doc Returns the next key and value in the map, along with %% a new iterator that can be used to iterate over the remainder of the map. %% -%% This function throws a `badarg' exception if the supplied iterator is not +%% This function raises a `badarg' error if the supplied iterator is not %% of the expected type. Only use iterators that are returned from functions %% in this module. %% @end @@ -185,36 +179,34 @@ new() -> %%----------------------------------------------------------------------------- %% @param Map the map %% @returns the list of keys that occur in this map. -%% @throws {badmap, Map} %% @doc Returns the list of keys that occur in this map. %% %% No guarantees are provided about the order of keys returned from this function. %% -%% This function throws a `{badmap, Map}' exception if `Map' is not a map. +%% This function raises a `{badmap, Map}' error if `Map' is not a map. %% @end %%----------------------------------------------------------------------------- -spec keys(Map :: map()) -> [key()]. keys(Map) when is_map(Map) -> iterate_keys(maps:next(maps:iterator(Map)), []); keys(Map) -> - throw({badmap, Map}). + error({badmap, Map}). %%----------------------------------------------------------------------------- %% @param Map the map %% @returns the list of values that occur in this map. -%% @throws {badmap, Map} %% @doc Returns the list of values that occur in this map. %% %% No guarantees are provided about the order of values returned from this function. %% -%% This function throws a `{badmap, Map}' exception if `Map' is not a map. +%% This function raises a `{badmap, Map}' error if `Map' is not a map. %% @end %%----------------------------------------------------------------------------- -spec values(Map :: map()) -> [key()]. values(Map) when is_map(Map) -> iterate_values(maps:next(maps:iterator(Map)), []); values(Map) -> - throw({badmap, Map}). + error({badmap, Map}). %%----------------------------------------------------------------------------- %% @param Map the map @@ -223,25 +215,24 @@ values(Map) -> %% %% No guarantees are provided about the order of entries returned from this function. %% -%% This function throws a `{badmap, Map}' exception if `Map' is not a map. +%% This function raises a `{badmap, Map}' error if `Map' is not a map. %% @end %%----------------------------------------------------------------------------- -spec to_list(Map :: map()) -> [key()]. to_list(Map) when is_map(Map) -> iterate_entries(maps:next(maps:iterator(Map)), []); to_list(Map) -> - throw({badmap, Map}). + error({badmap, Map}). %%----------------------------------------------------------------------------- %% @param List a list of `[{Key, Value}]' pairs %% @returns the map containing the entries from the list of supplied key-value pairs. -%% @throws badarg %% @doc This function constructs a map from the supplied list of key-value pairs. %% %% If the input list contains duplicate keys, the returned map will contain the %% right-most entry. %% -%% This function will raise a `badarg' exception if the input is not a proper +%% This function will raise a `badarg' error if the input is not a proper %% list or contains an element that is not a key-value pair. %% @end %%----------------------------------------------------------------------------- @@ -249,31 +240,29 @@ to_list(Map) -> from_list(List) when is_list(List) -> iterate_from_list(List, ?MODULE:new()); from_list(_List) -> - throw(badarg). + error(badarg). %%----------------------------------------------------------------------------- %% @param Map the map %% @returns the size of the map -%% @throws {badmap, Map} %% @doc Returns the size of (i.e., the number of entries in) the map %% -%% This function throws a `{badmap, Map}' exception if `Map' is not a map. +%% This function raises a `{badmap, Map}' error if `Map' is not a map. %% @end %%----------------------------------------------------------------------------- -spec size(Map :: map()) -> non_neg_integer(). size(Map) when is_map(Map) -> erlang:map_size(Map); size(Map) -> - throw({badmap, Map}). + error({badmap, Map}). %%----------------------------------------------------------------------------- %% @param Key the key to find %% @param Map the map in which to search %% @returns `{ok, Value}' if `Key' is in `Map'; `error', otherwise. -%% @throws {badmap, Map} %% @doc Returns `{ok, Value}' if `Key' is in `Map'; `error', otherwise. %% -%% This function throws a `{badmap, Map}' exception if `Map' is not a map. +%% This function raises a `{badmap, Map}' error if `Map' is not a map. %% @end %%----------------------------------------------------------------------------- -spec find(Key :: key(), Map :: map()) -> {ok, Value :: value()} | error. @@ -289,7 +278,6 @@ find(Key, Map) -> %% @param Pred a function used to filter entries from the map %% @param MapOrIterator the map or map iterator to filter %% @returns a map containing all elements in `MapOrIterator' that satisfy `Pred' -%% @throws {badmap, Map} | badarg %% @doc Return a map who's entries are filtered by the supplied predicate. %% %% This function returns a new map containing all elements from the input @@ -297,8 +285,8 @@ find(Key, Map) -> %% %% The supplied predicate is a function from key-value inputs to a boolean value. %% -%% This function throws a `{badmap, Map}' exception if `Map' is not a map or map iterator, -%% and a `badarg' exception if the input predicate is not a function. +%% This function raises a `{badmap, Map}' error if `Map' is not a map or map +%% iterator, and a `badarg' error if the input predicate is not a function. %% @end %%----------------------------------------------------------------------------- -spec filter( @@ -312,24 +300,23 @@ filter(Pred, [Pos | Map] = Iterator) when -> iterate_filter(Pred, maps:next(Iterator), ?MODULE:new()); filter(_Pred, Map) when not is_map(Map) -> - throw({badmap, Map}); + error({badmap, Map}); filter(_Pred, _Map) -> - throw(badarg). + error(badarg). %%----------------------------------------------------------------------------- %% @param Fun function over which to fold values %% @param Init the initial value of the fold accumulator %% @param MapOrIterator the map or map iterator over which to fold %% @returns the result of folding over all elements of the supplied map. -%% @throws {badmap, Map} | badarg %% @doc Fold over the entries in a map. %% %% This function takes a function used to fold over all entries in a map %% and an initial accumulator value to use as the value supplied to the %% first entry in the map. %% -%% This function throws a `badmap' exception if `Map' is not a map or map iterator, -%% and a `badarg' exception if the input function is not a function. +%% This function raises a `badmap' error if `Map' is not a map or map iterator, +%% and a `badarg' error if the input function is not a function. %% @end %%----------------------------------------------------------------------------- -spec fold( @@ -344,19 +331,18 @@ fold(Fun, Init, [Pos | Map] = Iterator) when -> iterate_fold(Fun, maps:next(Iterator), Init); fold(_Fun, _Init, Map) when not is_map(Map) -> - throw({badmap, Map}); + error({badmap, Map}); fold(_Fun, _Init, _Map) -> - throw(badarg). + error(badarg). %%----------------------------------------------------------------------------- %% @param Fun the function to apply to every entry in the map %% @param Map the map to which to apply the map function %% @returns the result of applying `Fun' to every entry in `Map' -%% @throws {badmap, Map} | badarg %% @doc Returns the result of applying a function to every element of a map. %% -%% This function throws a `badmap' exception if `Map' is not a map or map iterator, -%% and a `badarg' exception if the input function is not a function. +%% This function raises a `badmap' error if `Map' is not a map or map iterator, +%% and a `badarg' error if the input function is not a function. %% @end %%----------------------------------------------------------------------------- -spec map(Fun :: fun((Key :: key(), Value :: value()) -> value()), Map :: map_or_iterator()) -> @@ -368,35 +354,33 @@ map(Fun, [Pos | Map] = Iterator) when -> iterate_map(Fun, maps:next(Iterator), ?MODULE:new()); map(_Fun, Map) when not is_map(Map) -> - throw({badmap, Map}); + error({badmap, Map}); map(_Fun, _Map) -> - throw(badarg). + error(badarg). %%----------------------------------------------------------------------------- %% @param Map1 a map %% @param Map2 a mpa %% @returns the result of merging entries from `Map1' and `Map2'. -%% @throws {badmap, Map} %% @doc Merge two maps to yield a new map. %% %% If `Map1' and `Map2' contain the same key, then the value from `Map2' will be used. %% -%% This function throws a `badmap' exception if neither `Map1' nor `Map2' is a map. +%% This function raises a `badmap' error if neither `Map1' nor `Map2' is a map. %% @end %%----------------------------------------------------------------------------- -spec merge(Map1 :: map(), Map2 :: map()) -> map(). merge(Map1, Map2) when is_map(Map1) andalso is_map(Map2) -> iterate_merge(maps:next(maps:iterator(Map2)), Map1); merge(Map1, _Map2) when not is_map(Map1) -> - throw({badmap, Map1}); + error({badmap, Map1}); merge(_Map1, Map2) when not is_map(Map2) -> - throw({badmap, Map2}). + error({badmap, Map2}). %%----------------------------------------------------------------------------- %% @param Key the key to remove %% @param MapOrIterator the map or map iterator from which to remove the key %% @returns a new map without `Key' as an entry. -%% @throws {badmap, Map} %% @doc Remove an entry from a map using a key. %% %% If `Key' does not occur in `Map', then the returned Map has the same @@ -405,7 +389,7 @@ merge(_Map1, Map2) when not is_map(Map2) -> %% Note. This function extends the functionality of the OTP `remove/2' function, %% since the OTP interface only takes a map as input. %% -%% This function throws a `badmap' exception if `Map' is not a map or map iterator. +%% This function raises a `badmap' error if `Map' is not a map or map iterator. %% @end %%----------------------------------------------------------------------------- -spec remove(Key :: key(), MapOrIterator :: map_or_iterator()) -> map(). @@ -419,17 +403,16 @@ remove(Key, Map) when is_map(Map) -> remove(Key, [Pos | Map] = Iterator) when is_integer(Pos) andalso is_map(Map) -> iterate_remove(Key, maps:next(Iterator), ?MODULE:new()); remove(_Key, Map) when not is_map(Map) -> - throw({badmap, Map}). + error({badmap, Map}). %%----------------------------------------------------------------------------- %% @param Key the key to update %% @param Value the value to update %% @param Map the map to update %% @returns a new map, with `Key' updated with `Value' -%% @throws {badmap, Map} %% @doc Returns a new map with an updated key-value association. %% -%% This function throws a `badmap' exception if `Map' is not a map and +%% This function raises a `badmap' error if `Map' is not a map and %% `{badkey, Key}` if key doesn't exist %% @end %%----------------------------------------------------------------------------- @@ -507,4 +490,4 @@ iterate_from_list([], Accum) -> iterate_from_list([{Key, Value} | T], Accum) -> iterate_from_list(T, Accum#{Key => Value}); iterate_from_list(_List, _Accum) -> - throw(badarg). + error(badarg). diff --git a/libs/etest/src/etest.erl b/libs/etest/src/etest.erl index b532628dec..7b1a54a5fe 100644 --- a/libs/etest/src/etest.erl +++ b/libs/etest/src/etest.erl @@ -30,9 +30,10 @@ assert_match/2, assert_equals/2, assert_true/1, - assert_failure/1, - assert_failure/2, - flush_msg_queue/0 + flush_msg_queue/0, + assert_exception/1, + assert_exception/2, + assert_exception/3 ]). %%----------------------------------------------------------------------------- @@ -92,11 +93,11 @@ assert_true(_) -> fail. %%----------------------------------------------------------------------------- %% @param F a function to evaluate -%% @returns ok if evaluating F results in Error being thrown; fail, otherwise +%% @returns ok if evaluating F results in Error being raised; fail, otherwise %% @end %%----------------------------------------------------------------------------- --spec assert_failure(fun()) -> ok | fail. -assert_failure(F) -> +-spec assert_exception(fun()) -> ok | fail. +assert_exception(F) -> try F(), fail @@ -106,18 +107,36 @@ assert_failure(F) -> %%----------------------------------------------------------------------------- %% @param F a function to evaluate -%% @returns ok if evaluating F results in Error being thrown; fail, otherwise +%% @param Class expected exception class +%% @returns ok if evaluating F results in an exception of class Class being +%% raised; fail, otherwise %% @end %%----------------------------------------------------------------------------- --spec assert_failure(fun(), Error :: atom()) -> ok | fail. -assert_failure(F, E) -> +-spec assert_exception(fun(), Class :: throw | error | exit) -> ok | fail. +assert_exception(F, Class) -> try F(), fail catch - %% TODO implement opcode 108 (raise/2) - _:E -> - id(E), + Class:_ -> + ok + end. + +%%----------------------------------------------------------------------------- +%% @param F a function to evaluate +%% @param Class expected exception class +%% @param E expected exception value +%% @returns ok if evaluating F results in an exception of class Class and of +%% value E being raised; fail, otherwise +%% @end +%%----------------------------------------------------------------------------- +-spec assert_exception(fun(), Class :: throw | error | exit, E :: any()) -> ok | fail. +assert_exception(F, Class, E) -> + try + F(), + fail + catch + Class:E -> ok end. @@ -196,5 +215,3 @@ check_results([{_Test, ok} | T]) -> check_results(T); check_results([Failure | _T]) -> {fail, Failure}. - -id(X) -> X. diff --git a/libs/include/etest.hrl b/libs/include/etest.hrl index 8bdde762d5..b5cb52f7db 100644 --- a/libs/include/etest.hrl +++ b/libs/include/etest.hrl @@ -48,23 +48,39 @@ ) end ). --define(ASSERT_FAILURE(A), - case etest:assert_failure(fun() -> A end) of +-define(ASSERT_EXCEPTION(A), + case etest:assert_exception(fun() -> A end) of ok -> ok; fail -> throw( - {failed_assert_failure, {?MODULE, ?FUNCTION_NAME, ?FUNCTION_ARITY, ?LINE}, A} + {failed_assert_exception, {?MODULE, ?FUNCTION_NAME, ?FUNCTION_ARITY, ?LINE}, A} ) end ). --define(ASSERT_FAILURE(A, E), - case etest:assert_failure(fun() -> A end, E) of +-define(ASSERT_EXCEPTION(A, C), + case etest:assert_exception(fun() -> A end, C) of ok -> ok; fail -> throw( - {failed_assert_failure, {?MODULE, ?FUNCTION_NAME, ?FUNCTION_ARITY, ?LINE}, A, E} + {failed_assert_exception, {?MODULE, ?FUNCTION_NAME, ?FUNCTION_ARITY, ?LINE}, A} ) end ). +-define(ASSERT_EXCEPTION(A, C, E), + case etest:assert_exception(fun() -> A end, C, E) of + ok -> + ok; + fail -> + throw( + {failed_assert_exception, {?MODULE, ?FUNCTION_NAME, ?FUNCTION_ARITY, ?LINE}, A} + ) + end +). +-define(ASSERT_EXIT(A), ?ASSERT_EXCEPTION(A, exit)). +-define(ASSERT_EXIT(A, E), ?ASSERT_EXCEPTION(A, exit, E)). +-define(ASSERT_ERROR(A), ?ASSERT_EXCEPTION(A, error)). +-define(ASSERT_ERROR(A, E), ?ASSERT_EXCEPTION(A, error, E)). +-define(ASSERT_THROW(A), ?ASSERT_EXCEPTION(A, throw)). +-define(ASSERT_THROW(A, E), ?ASSERT_EXCEPTION(A, throw, E)). diff --git a/tests/libs/alisp/etest.hrl b/tests/libs/alisp/etest.hrl deleted file mode 100644 index 7a5542000d..0000000000 --- a/tests/libs/alisp/etest.hrl +++ /dev/null @@ -1,64 +0,0 @@ -% -% This file is part of AtomVM. -% -% Copyright 2019 Fred Dushin -% -% Licensed under the Apache License, Version 2.0 (the "License"); -% you may not use this file except in compliance with the License. -% You may obtain a copy of the License at -% -% http://www.apache.org/licenses/LICENSE-2.0 -% -% Unless required by applicable law or agreed to in writing, software -% distributed under the License is distributed on an "AS IS" BASIS, -% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -% See the License for the specific language governing permissions and -% limitations under the License. -% -% SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later -% - --define(ASSERT_MATCH(A, B), - case etest:assert_match(A, B) of - ok -> - ok; - fail -> - erlang:display( - {failed_assert_match, {?MODULE, ?FUNCTION_NAME, ?FUNCTION_ARITY, ?LINE}, A, B} - ), - fail - end -). --define(ASSERT_EQUALS(A, B), - case etest:assert_equals(A, B) of - ok -> - ok; - fail -> - erlang:display( - {failed_assert_equals, {?MODULE, ?FUNCTION_NAME, ?FUNCTION_ARITY, ?LINE}, A, B} - ), - fail - end -). --define(ASSERT_TRUE(C), - case etest:assert_true(C) of - ok -> - ok; - fail -> - erlang:display( - {failed_assert_true, {?MODULE, ?FUNCTION_NAME, ?FUNCTION_ARITY, ?LINE}, C} - ), - fail - end -). --define(ASSERT_FAILURE(A, E), - case etest:assert_failure(fun() -> A end, E) of - ok -> - ok; - fail -> - erlang:display( - {failed_assert_failure, {?MODULE, ?FUNCTION_NAME, ?FUNCTION_ARITY, ?LINE}, A, E} - ), - fail - end -). diff --git a/tests/libs/estdlib/test_io_lib.erl b/tests/libs/estdlib/test_io_lib.erl index 30afdc00a5..85e238f43b 100644 --- a/tests/libs/estdlib/test_io_lib.erl +++ b/tests/libs/estdlib/test_io_lib.erl @@ -52,10 +52,10 @@ test() -> ?ASSERT_MATCH(?FLT(io_lib:format("foo: ~w~n", [[1, 2, 3]])), "foo: [1,2,3]\n"), % unprintable lists ?ASSERT_MATCH(?FLT(io_lib:format("foo: ~p~n", [[-1]])), "foo: [-1]\n"), - ?ASSERT_FAILURE(io_lib:format("foo: ~s~n", [[-1]]), badarg), + ?ASSERT_ERROR(io_lib:format("foo: ~s~n", [[-1]]), badarg), ?ASSERT_MATCH(?FLT(io_lib:format("foo: ~w~n", [[-1]])), "foo: [-1]\n"), ?ASSERT_MATCH(?FLT(io_lib:format("foo: ~p~n", [[256]])), "foo: [256]\n"), - ?ASSERT_FAILURE(io_lib:format("foo: ~s~n", [[256]]), badarg), + ?ASSERT_ERROR(io_lib:format("foo: ~s~n", [[256]]), badarg), ?ASSERT_MATCH(?FLT(io_lib:format("foo: ~w~n", [[256]])), "foo: [256]\n"), % escapable strings ?ASSERT_MATCH( @@ -99,10 +99,10 @@ test() -> ?ASSERT_MATCH(?FLT(io_lib:format("foo: ~p~n", [[1, 2, [3]]])), "foo: [1,2,[3]]\n"), % integers ?ASSERT_MATCH(?FLT(io_lib:format("foo: ~p~n", [123])), "foo: 123\n"), - ?ASSERT_FAILURE(io_lib:format("foo: ~s~n", [123]), badarg), + ?ASSERT_ERROR(io_lib:format("foo: ~s~n", [123]), badarg), ?ASSERT_MATCH(?FLT(io_lib:format("foo: ~w~n", [123])), "foo: 123\n"), ?ASSERT_MATCH(?FLT(io_lib:format("foo: ~p~n", [-123])), "foo: -123\n"), - ?ASSERT_FAILURE(io_lib:format("foo: ~s~n", [-123]), badarg), + ?ASSERT_ERROR(io_lib:format("foo: ~s~n", [-123]), badarg), ?ASSERT_MATCH(?FLT(io_lib:format("foo: ~w~n", [-123])), "foo: -123\n"), ?ASSERT_MATCH( ?FLT(io_lib:format("foo: ~p~n", [[65, 116, 111, 109, 86, 77]])), "foo: \"AtomVM\"\n" @@ -128,9 +128,9 @@ test() -> ), ?ASSERT_MATCH(?FLT(io_lib:format("escape ~~p~n", [])), "escape ~p\n"), - ?ASSERT_FAILURE(io_lib:format("no pattern", id([foo])), badarg), - ?ASSERT_FAILURE(io_lib:format("too ~p many ~p patterns", id([foo])), badarg), - ?ASSERT_FAILURE(io_lib:format("not enough ~p patterns", id([foo, bar])), badarg), + ?ASSERT_ERROR(io_lib:format("no pattern", id([foo])), badarg), + ?ASSERT_ERROR(io_lib:format("too ~p many ~p patterns", id([foo])), badarg), + ?ASSERT_ERROR(io_lib:format("not enough ~p patterns", id([foo, bar])), badarg), % ?ASSERT_MATCH(?FLT(io_lib:format("~*.*.0f~n", [9, 5, 3.14159265])), "003.14159\n"), % ?ASSERT_MATCH(?FLT(io_lib:format("~*.*.*f~n", [9, 5, $*, 3.14159265])), "**3.14159\n"), diff --git a/tests/libs/estdlib/test_lists.erl b/tests/libs/estdlib/test_lists.erl index 3138cb4174..11aba4796f 100644 --- a/tests/libs/estdlib/test_lists.erl +++ b/tests/libs/estdlib/test_lists.erl @@ -48,7 +48,7 @@ test_nth() -> ?ASSERT_MATCH(lists:nth(1, [a, b, c]), a), ?ASSERT_MATCH(lists:nth(2, [a, b, c]), b), ?ASSERT_MATCH(lists:nth(3, [a, b, c]), c), - ?ASSERT_FAILURE(lists:nth(-1, [a, b, c]), function_clause), + ?ASSERT_ERROR(lists:nth(-1, [a, b, c]), function_clause), ok. test_member() -> @@ -183,14 +183,14 @@ test_seq() -> ?ASSERT_MATCH(lists:seq(1, 1, 0), [1]), ?ASSERT_MATCH(lists:seq(1, 1), [1]), - ?ASSERT_FAILURE(lists:seq(foo, 1)), - ?ASSERT_FAILURE(lists:seq(1, bar)), - ?ASSERT_FAILURE(lists:seq(foo, bar)), - ?ASSERT_FAILURE(lists:seq(1, 2, tapas)), - ?ASSERT_FAILURE(lists:seq(1, -1)), - ?ASSERT_FAILURE(lists:seq(-1, 1, -1)), - ?ASSERT_FAILURE(lists:seq(1, -1, 1)), - ?ASSERT_FAILURE(lists:seq(1, 2, 0)), + ?ASSERT_ERROR(lists:seq(foo, 1)), + ?ASSERT_ERROR(lists:seq(1, bar)), + ?ASSERT_ERROR(lists:seq(foo, bar)), + ?ASSERT_ERROR(lists:seq(1, 2, tapas)), + ?ASSERT_ERROR(lists:seq(1, -1)), + ?ASSERT_ERROR(lists:seq(-1, 1, -1)), + ?ASSERT_ERROR(lists:seq(1, -1, 1)), + ?ASSERT_ERROR(lists:seq(1, 2, 0)), ok. @@ -204,9 +204,9 @@ test_sort() -> ?ASSERT_MATCH(lists:sort(fun(A, B) -> A > B end, [1, 2, 3, 4, 3, 5]), [5, 4, 3, 3, 2, 1]), - ?ASSERT_FAILURE(lists:sort(1), function_clause), - ?ASSERT_FAILURE(lists:sort(fun(A, B) -> A > B end, 1), function_clause), - ?ASSERT_FAILURE(lists:sort(1, [1]), function_clause), + ?ASSERT_ERROR(lists:sort(1), function_clause), + ?ASSERT_ERROR(lists:sort(fun(A, B) -> A > B end, 1), function_clause), + ?ASSERT_ERROR(lists:sort(1, [1]), function_clause), ok. @@ -220,9 +220,9 @@ test_usort() -> ?ASSERT_MATCH(lists:usort(fun(A, B) -> A > B end, [1, 2, 3, 4, 3, 5]), [5, 4, 3, 3, 2, 1]), ?ASSERT_MATCH(lists:usort(fun(A, B) -> A >= B end, [1, 2, 3, 4, 3, 5]), [5, 4, 3, 2, 1]), - ?ASSERT_FAILURE(lists:usort(1), function_clause), - ?ASSERT_FAILURE(lists:usort(fun(A, B) -> A > B end, 1), function_clause), - ?ASSERT_FAILURE(lists:usort(1, [1]), function_clause), + ?ASSERT_ERROR(lists:usort(1), function_clause), + ?ASSERT_ERROR(lists:usort(fun(A, B) -> A > B end, 1), function_clause), + ?ASSERT_ERROR(lists:usort(1, [1]), function_clause), ok. diff --git a/tests/libs/estdlib/test_logger.erl b/tests/libs/estdlib/test_logger.erl index 2eb68b3f4d..8e6ceb3916 100644 --- a/tests/libs/estdlib/test_logger.erl +++ b/tests/libs/estdlib/test_logger.erl @@ -46,7 +46,7 @@ test_logger() -> ok. test_default_logger() -> - ?ASSERT_FAILURE(?LOG_NOTICE("Tried to log before starting log_manager!")), + ?ASSERT_EXIT(?LOG_NOTICE("Tried to log before starting log_manager!")), {ok, _Pid} = logger_manager:start_link(#{}), @@ -59,10 +59,10 @@ test_default_logger() -> ok = ?LOG_INFO("Info!"), ok = ?LOG_DEBUG("Debug!"), - ?ASSERT_FAILURE(logger:log(bad_level, "foo")), - ?ASSERT_FAILURE(logger:log(notice, not_a_list)), - ?ASSERT_FAILURE(logger:log(notice, "", not_a_list)), - ?ASSERT_FAILURE(logger:log(notice, "", [], not_a_map)), + ?ASSERT_ERROR(logger:log(bad_level, "foo")), + ?ASSERT_ERROR(logger:log(notice, not_a_list)), + ?ASSERT_ERROR(logger:log(notice, "", not_a_list)), + ?ASSERT_ERROR(logger:log(notice, "", [], not_a_map)), logger_manager:stop(), diff --git a/tests/libs/estdlib/test_maps.erl b/tests/libs/estdlib/test_maps.erl index f868f2d246..a2f83bae5a 100644 --- a/tests/libs/estdlib/test_maps.erl +++ b/tests/libs/estdlib/test_maps.erl @@ -49,15 +49,15 @@ test_get() -> ok = check_bad_key(fun() -> maps:get(bar, id(#{foo => bar})) end, bar), ?ASSERT_MATCH(maps:get(gnu, id(#{foo => bar}), gnat), gnat), - ?ASSERT_FAILURE(maps:get({hello}, id(#{foo => bar})), {badkey, {hello}}), - ?ASSERT_FAILURE(maps:get(gnu, id({hello})), {badmap, {hello}}), + ?ASSERT_ERROR(maps:get({hello}, id(#{foo => bar})), {badkey, {hello}}), + ?ASSERT_ERROR(maps:get(gnu, id({hello})), {badmap, {hello}}), ok. test_is_key() -> ?ASSERT_MATCH(maps:is_key(foo, id(#{foo => bar})), true), ok = check_bad_map(fun() -> maps:is_key(bar, id(not_a_map)) end), ?ASSERT_MATCH(maps:is_key(bar, id(#{foo => bar})), false), - ?ASSERT_FAILURE(maps:is_key(gnu, id({hello})), {badmap, {hello}}), + ?ASSERT_ERROR(maps:is_key(gnu, id({hello})), {badmap, {hello}}), ok. test_put() -> @@ -105,14 +105,14 @@ test_to_list() -> test_from_list() -> ?ASSERT_EQUALS(maps:from_list([]), #{}), ?ASSERT_EQUALS(maps:from_list([{a, 1}, {b, 2}, {c, 3}]), #{a => 1, b => 2, c => 3}), - ok = etest:assert_failure(fun() -> maps:from_list(id(foo)) end, badarg), - ok = etest:assert_failure(fun() -> maps:from_list(id([improper | list])) end, badarg), + ?ASSERT_ERROR(maps:from_list(id(foo)), badarg), + ?ASSERT_ERROR(maps:from_list(id([improper | list])), badarg), ok. test_size() -> ?ASSERT_MATCH(maps:size(maps:new()), 0), ?ASSERT_MATCH(maps:size(#{a => 1, b => 2, c => 3}), 3), - ?ASSERT_FAILURE(maps:size({hello}), {badmap, {hello}}), + ?ASSERT_ERROR(maps:size({hello}), {badmap, {hello}}), ok = check_bad_map(fun() -> maps:size(id(not_a_map)) end), ok. @@ -131,7 +131,7 @@ test_filter() -> ?ASSERT_EQUALS(maps:filter(Filter, #{a => 1, b => 2, c => 3}), #{b => 2}), ok = check_bad_map(fun() -> maps:filter(Filter, id(not_a_map)) end), ok = check_bad_map_or_badarg(fun() -> maps:filter(not_a_function, id(not_a_map)) end), - ?ASSERT_FAILURE(maps:filter(not_a_function, maps:new()), badarg), + ?ASSERT_ERROR(maps:filter(not_a_function, maps:new()), badarg), ok. test_fold() -> @@ -140,7 +140,7 @@ test_fold() -> ?ASSERT_EQUALS(maps:fold(Fun, 0, #{a => 1, b => 2, c => 3}), 6), ok = check_bad_map(fun() -> maps:fold(Fun, any, id(not_a_map)) end), ok = check_bad_map_or_badarg(fun() -> maps:fold(not_a_function, any, id(not_a_map)) end), - ?ASSERT_FAILURE(maps:fold(not_a_function, any, maps:new()), badarg), + ?ASSERT_ERROR(maps:fold(not_a_function, any, maps:new()), badarg), ok. test_map() -> @@ -149,7 +149,7 @@ test_map() -> ?ASSERT_EQUALS(maps:map(Fun, #{a => 1, b => 2, c => 3}), #{a => 2, b => 4, c => 6}), ok = check_bad_map(fun() -> maps:map(Fun, id(not_a_map)) end), ok = check_bad_map_or_badarg(fun() -> maps:map(not_a_function, id(not_a_map)) end), - ?ASSERT_FAILURE(maps:map(not_a_function, maps:new()), badarg), + ?ASSERT_ERROR(maps:map(not_a_function, maps:new()), badarg), ok. test_merge() -> @@ -176,13 +176,13 @@ test_remove() -> ok. test_update() -> - ?ASSERT_FAILURE(maps:update(foo, bar, maps:new()), {badkey, foo}), + ?ASSERT_ERROR(maps:update(foo, bar, maps:new()), {badkey, foo}), ?ASSERT_EQUALS(maps:update(a, 10, #{a => 1, b => 2, c => 3}), #{a => 10, b => 2, c => 3}), ?ASSERT_EQUALS(maps:update(b, 20, #{a => 1, b => 2, c => 3}), #{a => 1, b => 20, c => 3}), ?ASSERT_EQUALS(maps:update(c, 30, #{a => 1, b => 2, c => 3}), #{a => 1, b => 2, c => 30}), - ?ASSERT_FAILURE(maps:update(d, 40, #{a => 1, b => 2, c => 3}), {badkey, d}), - ?ASSERT_FAILURE(maps:update({hello}, 40, #{a => 1, b => 2, c => 3}), {badkey, {hello}}), - ?ASSERT_FAILURE(maps:update(a, 40, {hello}), {badmap, {hello}}), + ?ASSERT_ERROR(maps:update(d, 40, #{a => 1, b => 2, c => 3}), {badkey, d}), + ?ASSERT_ERROR(maps:update({hello}, 40, #{a => 1, b => 2, c => 3}), {badkey, {hello}}), + ?ASSERT_ERROR(maps:update(a, 40, {hello}), {badmap, {hello}}), ok = check_bad_map(fun() -> maps:update(foo, bar, id(not_a_map)) end), ok. @@ -193,7 +193,7 @@ check_bad_map(F) -> F(), fail catch - _:{badmap, _} -> ok + error:{badmap, _} -> ok end. check_bad_map_or_badarg(F) -> @@ -206,7 +206,7 @@ check_bad_map_or_badarg(F) -> F(), fail catch - _:{badmap, _} when not BadargFirst -> ok; + error:{badmap, _} when not BadargFirst -> ok; error:badarg when BadargFirst -> ok end. @@ -216,6 +216,6 @@ check_bad_key(F, _Key) -> fail catch %% TODO OTP23 compiler compiles to erlang:map_ equivalents - _:{badkey, _} -> + error:{badkey, _} -> ok end.