summaryrefslogtreecommitdiff
path: root/lib/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'lib/stdlib')
-rw-r--r--lib/stdlib/include/assert.hrl230
-rw-r--r--lib/stdlib/src/Makefile1
-rw-r--r--lib/stdlib/test/Makefile3
-rw-r--r--lib/stdlib/test/stdlib_SUITE.erl29
-rw-r--r--lib/stdlib/vsn.mk2
5 files changed, 261 insertions, 4 deletions
diff --git a/lib/stdlib/include/assert.hrl b/lib/stdlib/include/assert.hrl
new file mode 100644
index 0000000000..a401229135
--- /dev/null
+++ b/lib/stdlib/include/assert.hrl
@@ -0,0 +1,230 @@
+%% 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.
+%%
+%% Copyright (C) 2004-2012 Richard Carlsson, Mickaël Rémond
+
+-ifndef(ASSERT_HRL).
+-define(ASSERT_HRL, true).
+
+%% Asserts are enabled unless NOASSERT is defined, and ASSERT can be used to
+%% override it: if both ASSERT and NOASSERT are defined, then ASSERT takes
+%% precedence, and NOASSERT will become undefined.
+%%
+%% Furthermore, if NODEBUG is defined, it implies NOASSERT, unless DEBUG or
+%% ASSERT are defined.
+
+
+%% allow NODEBUG to imply NOASSERT, unless DEBUG
+-ifdef(NODEBUG).
+-ifndef(DEBUG).
+-ifndef(NOASSERT).
+-define(NOASSERT, true).
+-endif.
+-endif.
+-endif.
+
+
+%% allow ASSERT to override NOASSERT
+-ifdef(ASSERT).
+-undef(NOASSERT).
+-endif.
+
+
+%% Assert macros must not depend on any non-kernel or stdlib libraries.
+%%
+%% We must use fun-call wrappers ((fun () -> ... end)()) to avoid
+%% exporting local variables, and furthermore we only use variable names
+%% prefixed with "__", that hopefully will not be bound outside the fun.
+%% It is not possible to nest assert macros.
+
+
+%% The plain assert macro should be defined to do nothing if this file is
+%% included when asserts are turned off, but avoid getting a compilation
+%% error if a macro called assert is already defined for some reason.
+-ifdef(NOASSERT).
+-ifndef(assert).
+-define(assert(BoolExpr),ok).
+-endif.
+-else.
+%% The assert macro is written the way it is so as not to cause warnings
+%% for clauses that cannot match, even if the expression is a constant.
+-undef(assert).
+-define(assert(BoolExpr),
+ ((fun () ->
+ case (BoolExpr) of
+ true -> ok;
+ __V -> erlang:error({assertion_failed,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {expression, (??BoolExpr)},
+ {expected, true},
+ {value, case __V of false -> __V;
+ _ -> {not_a_boolean,__V}
+ end}]})
+ end
+ end)())).
+-endif.
+
+-define(assertNot(BoolExpr), ?assert(not (BoolExpr))).
+
+
+%% This is mostly a convenience which gives more detailed reports.
+%% Note: Guard is a guarded pattern, and can not be used for value.
+-ifdef(NOASSERT).
+-define(assertMatch(Guard, Expr), ok).
+-else.
+-define(assertMatch(Guard, Expr),
+ ((fun () ->
+ case (Expr) of
+ Guard -> ok;
+ __V -> erlang:error({assertMatch_failed,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {expression, (??Expr)},
+ {pattern, (??Guard)},
+ {value, __V}]})
+ end
+ end)())).
+-endif.
+
+
+%% This is the inverse case of assertMatch, for convenience.
+-ifdef(NOASSERT).
+-define(assertNotMatch(Guard, Expr), ok).
+-else.
+-define(assertNotMatch(Guard, Expr),
+ ((fun () ->
+ __V = (Expr),
+ case __V of
+ Guard -> erlang:error({assertNotMatch_failed,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {expression, (??Expr)},
+ {pattern, (??Guard)},
+ {value, __V}]});
+ _ -> ok
+ end
+ end)())).
+-endif.
+
+
+%% This is a convenience macro which gives more detailed reports when
+%% the expected LHS value is not a pattern, but a computed value
+-ifdef(NOASSERT).
+-define(assertEqual(Expect, Expr), ok).
+-else.
+-define(assertEqual(Expect, Expr),
+ ((fun (__X) ->
+ case (Expr) of
+ __X -> ok;
+ __V -> erlang:error({assertEqual_failed,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {expression, (??Expr)},
+ {expected, __X},
+ {value, __V}]})
+ end
+ end)(Expect))).
+-endif.
+
+
+%% This is the inverse case of assertEqual, for convenience.
+-ifdef(NOASSERT).
+-define(assertNotEqual(Unexpected, Expr), ok).
+-else.
+-define(assertNotEqual(Unexpected, Expr),
+ ((fun (__X) ->
+ case (Expr) of
+ __X -> erlang:error({assertNotEqual_failed,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {expression, (??Expr)},
+ {value, __X}]});
+ _ -> ok
+ end
+ end)(Unexpected))).
+-endif.
+
+
+%% Note: Class and Term are patterns, and can not be used for value.
+%% Term can be a guarded pattern, but Class cannot.
+-ifdef(NOASSERT).
+-define(assertException(Class, Term, Expr), ok).
+-else.
+-define(assertException(Class, Term, Expr),
+ ((fun () ->
+ try (Expr) of
+ __V -> erlang:error({assertException_failed,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {expression, (??Expr)},
+ {pattern,
+ "{ "++(??Class)++" , "++(??Term)
+ ++" , [...] }"},
+ {unexpected_success, __V}]})
+ catch
+ Class:Term -> ok;
+ __C:__T ->
+ erlang:error({assertException_failed,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {expression, (??Expr)},
+ {pattern,
+ "{ "++(??Class)++" , "++(??Term)
+ ++" , [...] }"},
+ {unexpected_exception,
+ {__C, __T,
+ erlang:get_stacktrace()}}]})
+ end
+ end)())).
+-endif.
+
+-define(assertError(Term, Expr), ?assertException(error, Term, Expr)).
+-define(assertExit(Term, Expr), ?assertException(exit, Term, Expr)).
+-define(assertThrow(Term, Expr), ?assertException(throw, Term, Expr)).
+
+
+%% This is the inverse case of assertException, for convenience.
+%% Note: Class and Term are patterns, and can not be used for value.
+%% Both Class and Term can be guarded patterns.
+-ifdef(NOASSERT).
+-define(assertNotException(Class, Term, Expr), ok).
+-else.
+-define(assertNotException(Class, Term, Expr),
+ ((fun () ->
+ try (Expr) of
+ _ -> ok
+ catch
+ __C:__T ->
+ case __C of
+ Class ->
+ case __T of
+ Term ->
+ erlang:error({assertNotException_failed,
+ [{module, ?MODULE},
+ {line, ?LINE},
+ {expression, (??Expr)},
+ {pattern,
+ "{ "++(??Class)++" , "
+ ++(??Term)++" , [...] }"},
+ {unexpected_exception,
+ {__C, __T,
+ erlang:get_stacktrace()
+ }}]});
+ _ -> ok
+ end;
+ _ -> ok
+ end
+ end
+ end)())).
+-endif.
+
+
+-endif. % ASSERT_HRL
diff --git a/lib/stdlib/src/Makefile b/lib/stdlib/src/Makefile
index f3387d669b..1a5fb2462d 100644
--- a/lib/stdlib/src/Makefile
+++ b/lib/stdlib/src/Makefile
@@ -120,6 +120,7 @@ MODULES= \
zip
HRL_FILES= \
+ ../include/assert.hrl \
../include/erl_compile.hrl \
../include/erl_bits.hrl \
../include/ms_transform.hrl \
diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile
index 6aa09d7bd0..b0bb83dfa0 100644
--- a/lib/stdlib/test/Makefile
+++ b/lib/stdlib/test/Makefile
@@ -101,7 +101,8 @@ RELSYSDIR = $(RELEASE_PATH)/stdlib_test
ERL_MAKE_FLAGS +=
ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/test_server/include \
- -I$(ERL_TOP)/lib/kernel/include
+ -I$(ERL_TOP)/lib/kernel/include \
+ -I$(ERL_TOP)/lib/stdlib/include
EBIN = .
diff --git a/lib/stdlib/test/stdlib_SUITE.erl b/lib/stdlib/test/stdlib_SUITE.erl
index 8a2cb5ea6b..eb71463deb 100644
--- a/lib/stdlib/test/stdlib_SUITE.erl
+++ b/lib/stdlib/test/stdlib_SUITE.erl
@@ -33,7 +33,7 @@
-export([init_per_testcase/2, end_per_testcase/2]).
% Test cases must be exported.
--export([app_test/1, appup_test/1]).
+-export([app_test/1, appup_test/1, assert_test/1]).
%%
%% all/1
@@ -41,7 +41,7 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [app_test, appup_test].
+ [app_test, appup_test, assert_test].
groups() ->
[].
@@ -136,3 +136,28 @@ check_appup([Vsn|Vsns],Instrs,Expected) ->
end;
check_appup([],_,_) ->
ok.
+
+-include_lib("stdlib/include/assert.hrl").
+-include_lib("stdlib/include/assert.hrl"). % test repeated inclusion
+assert_test(suite) ->
+ [];
+assert_test(doc) ->
+ ["Assert macros test."];
+assert_test(_Config) ->
+ ?assert(1 =:= 1),
+ ?assertNot(1 =:= 1.0),
+ ?assertMatch({foo,_}, {foo,bar}),
+ ?assertNotMatch({foo,_}, {foo,bar,baz}),
+ ?assertMatch({foo,N} when N > 0, {foo,1}),
+ ?assertNotMatch({foo,N} when N > 0, {foo,0}),
+ ?assertEqual(1.0, 1.0),
+ ?assertNotEqual(1, 1.0),
+ ?assertException(error, badarith, 1/0),
+ ?assertException(exit, foo, exit(foo)),
+ ?assertException(throw, foo, throw(foo)),
+ ?assertException(throw, {foo,_}, throw({foo,bar})),
+ ?assertNotException(throw, {foo,baz}, throw({foo,bar})),
+ ?assertError(badarith, 1/0),
+ ?assertExit(foo, exit(foo)),
+ ?assertThrow(foo, throw(foo)),
+ ok.
diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk
index c1467697e3..c9d596f737 100644
--- a/lib/stdlib/vsn.mk
+++ b/lib/stdlib/vsn.mk
@@ -1 +1 @@
-STDLIB_VSN = 1.19.1
+STDLIB_VSN = 1.20