diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/eunit/include/eunit.hrl | 264 | ||||
| -rw-r--r-- | lib/eunit/src/Makefile | 2 | ||||
| -rw-r--r-- | lib/stdlib/doc/src/Makefile | 2 | ||||
| -rw-r--r-- | lib/stdlib/doc/src/assert_hrl.xml | 160 | ||||
| -rw-r--r-- | lib/stdlib/doc/src/ref_man.xml | 1 | ||||
| -rw-r--r-- | lib/stdlib/include/assert.hrl | 260 | ||||
| -rw-r--r-- | lib/stdlib/src/Makefile | 1 | ||||
| -rw-r--r-- | lib/stdlib/test/Makefile | 3 | ||||
| -rw-r--r-- | lib/stdlib/test/stdlib_SUITE.erl | 67 | 
9 files changed, 525 insertions, 235 deletions
| diff --git a/lib/eunit/include/eunit.hrl b/lib/eunit/include/eunit.hrl index 53d291430d..88e9d6c19b 100644 --- a/lib/eunit/include/eunit.hrl +++ b/lib/eunit/include/eunit.hrl @@ -15,11 +15,14 @@  %%  %% Copyright (C) 2004-2006 Mickaël Rémond, Richard Carlsson +-ifndef(EUNIT_HRL). +-define(EUNIT_HRL, true). +  %% Including this file turns on testing and defines TEST, unless NOTEST  %% is defined before the file is included. If both NOTEST and TEST are  %% already defined, then TEST takes precedence, and NOTEST will become  %% undefined. -%%  +%%  %% If NODEBUG is defined before this file is included, the debug macros  %% are disabled, unless DEBUG is also defined, in which case NODEBUG  %% will become undefined. NODEBUG also implies NOASSERT, unless testing @@ -31,14 +34,10 @@  %% even if NODEBUG is defined. If both ASSERT and NOASSERT are defined  %% before the file is included, then ASSERT takes precedence, and NOASSERT  %% will become undefined regardless of TEST. -%%  +%%  %% After including this file, EUNIT will be defined if and only if TEST  %% is defined. --ifndef(EUNIT_HRL). --define(EUNIT_HRL, true). - -  %% allow defining TEST to override NOTEST  -ifdef(TEST).  -undef(NOTEST). @@ -49,13 +48,6 @@  -undef(NODEBUG).  -endif. -%% allow NODEBUG to imply NOASSERT, unless overridden below --ifdef(NODEBUG). --ifndef(NOASSERT). --define(NOASSERT, true). --endif. --endif. -  %% note that the main switch used within this file is NOTEST; however,  %% both TEST and EUNIT may be used to check whether testing is enabled  -ifndef(NOTEST). @@ -70,10 +62,8 @@  -undef(EUNIT).  -endif. -%% allow ASSERT to override NOASSERT (regardless of TEST/NOTEST) --ifdef(ASSERT). --undef(NOASSERT). --endif. +%% include the assert macros; ASSERT overrides NOASSERT if defined +-include_lib("stdlib/include/assert.hrl").  %% Parse transforms for automatic exporting/stripping of test functions.  %% (Note that although automatic stripping is convenient, it will make @@ -91,7 +81,7 @@  %% All macros should be available even if testing is turned off, and  %% should preferably not require EUnit to be present at runtime. -%%  +%%  %% 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. @@ -128,211 +118,24 @@  				      current_function)))).  -endif. -%% The plain assert macro should be defined to do nothing if this file -%% is included when debugging/testing is turned off. --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), -	begin -	((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)()) -	end). --endif. --define(assertNot(BoolExpr), ?assert(not (BoolExpr))). +%% General test macros  -define(_test(Expr), {?LINE, fun () -> (Expr) end}). -  -define(_assert(BoolExpr), ?_test(?assert(BoolExpr))). -  -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), -	begin -	((fun () -> -	    case (Expr) of -		Guard -> ok; -		__V -> erlang:error({assertMatch_failed, -				     [{module, ?MODULE}, -				      {line, ?LINE}, -				      {expression, (??Expr)}, -				      {pattern, (??Guard)}, -				      {value, __V}]}) -	    end -	  end)()) -	end). --endif.  -define(_assertMatch(Guard, Expr), ?_test(?assertMatch(Guard, Expr))). - -%% This is the inverse case of assertMatch, for convenience. --ifdef(NOASSERT). --define(assertNotMatch(Guard, Expr), ok). --else. --define(assertNotMatch(Guard, Expr), -	begin -	((fun () -> -	    __V = (Expr), -	    case __V of -		Guard -> erlang:error({assertNotMatch_failed, -				       [{module, ?MODULE}, -					{line, ?LINE}, -					{expression, (??Expr)}, -					{pattern, (??Guard)}, -					{value, __V}]}); -		_ -> ok -	    end -	  end)()) -	end). --endif.  -define(_assertNotMatch(Guard, Expr), ?_test(?assertNotMatch(Guard, Expr))). - -%% 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), -	begin -	((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)) -	end). --endif.  -define(_assertEqual(Expect, Expr), ?_test(?assertEqual(Expect, Expr))). - -%% This is the inverse case of assertEqual, for convenience. --ifdef(NOASSERT). --define(assertNotEqual(Unexpected, Expr), ok). --else. --define(assertNotEqual(Unexpected, Expr), -	begin -	((fun (__X) -> -	    case (Expr) of -		__X -> erlang:error({assertNotEqual_failed, -				     [{module, ?MODULE}, -				      {line, ?LINE}, -				      {expression, (??Expr)}, -				      {value, __X}]}); -		_ -> ok -	    end -	  end)(Unexpected)) -	end). --endif.  -define(_assertNotEqual(Unexpected, Expr),  	?_test(?assertNotEqual(Unexpected, Expr))). - -%% 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), -	begin -	((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)()) -	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)). -  -define(_assertException(Class, Term, Expr),  	?_test(?assertException(Class, Term, Expr))).  -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), -	begin -	((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)()) -	end). --endif.  -define(_assertNotException(Class, Term, Expr),  	?_test(?assertNotException(Class, Term, Expr))). +-define(_assertReceive(Guard, Expr), ?_test(?assertReceive(Guard, Expr))).  %% Macros for running operating system commands. (Note that these  %% require EUnit to be present at runtime, or at least eunit_lib.) @@ -364,18 +167,18 @@  -else.  -define(assertCmdStatus(N, Cmd),  	begin - 	((fun () -> -	    case ?_cmd_(Cmd) of -		{(N), _} -> ok; -		{__N, _} -> erlang:error({assertCmd_failed, -					  [{module, ?MODULE}, -					   {line, ?LINE}, -					   {command, (Cmd)}, -					   {expected_status,(N)}, -					   {status,__N}]}) -	    end -	  end)()) -	 end). +            ((fun () -> +                      case ?_cmd_(Cmd) of +                          {(N), _} -> ok; +                          {__N, _} -> erlang:error({assertCmd_failed, +                                                    [{module, ?MODULE}, +                                                     {line, ?LINE}, +                                                     {command, (Cmd)}, +                                                     {expected_status,(N)}, +                                                     {status,__N}]}) +                      end +              end)()) +        end).  -endif.  -define(assertCmd(Cmd), ?assertCmdStatus(0, Cmd)). @@ -384,17 +187,17 @@  -else.  -define(assertCmdOutput(T, Cmd),  	begin - 	((fun () -> -	    case ?_cmd_(Cmd) of -		{_, (T)} -> ok; -		{_, __T} -> erlang:error({assertCmdOutput_failed, -					  [{module, ?MODULE}, -					   {line, ?LINE}, -					   {command,(Cmd)}, -					   {expected_output,(T)}, -					   {output,__T}]}) -	    end -	  end)()) +            ((fun () -> +                      case ?_cmd_(Cmd) of +                          {_, (T)} -> ok; +                          {_, __T} -> erlang:error({assertCmdOutput_failed, +                                                    [{module, ?MODULE}, +                                                     {line, ?LINE}, +                                                     {command,(Cmd)}, +                                                     {expected_output,(T)}, +                                                     {output,__T}]}) +                      end +              end)())  	end).  -endif. @@ -439,5 +242,4 @@  	end).  -endif. -  -endif. % EUNIT_HRL diff --git a/lib/eunit/src/Makefile b/lib/eunit/src/Makefile index 47aef104ff..86a6d8831e 100644 --- a/lib/eunit/src/Makefile +++ b/lib/eunit/src/Makefile @@ -24,7 +24,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/eunit-$(VSN)  EBIN = ../ebin  INCLUDE=../include -ERL_COMPILE_FLAGS += -pa $(EBIN) -I$(INCLUDE) +warn_unused_vars +nowarn_shadow_vars +warn_unused_import +warn_obsolete_guard +ERL_COMPILE_FLAGS += -pa $(EBIN) -pa ../../stdlib/ebin -I$(INCLUDE) +warn_unused_vars +nowarn_shadow_vars +warn_unused_import +warn_obsolete_guard  PARSE_TRANSFORM = eunit_autoexport.erl diff --git a/lib/stdlib/doc/src/Makefile b/lib/stdlib/doc/src/Makefile index a4a2ed9931..d41f91250e 100644 --- a/lib/stdlib/doc/src/Makefile +++ b/lib/stdlib/doc/src/Makefile @@ -102,7 +102,7 @@ XML_REF3_FILES = \  XML_REF6_FILES = stdlib_app.xml  XML_PART_FILES = part.xml part_notes.xml part_notes_history.xml -XML_CHAPTER_FILES = io_protocol.xml unicode_usage.xml notes.xml notes_history.xml +XML_CHAPTER_FILES = io_protocol.xml unicode_usage.xml notes.xml notes_history.xml assert_hrl.xml  BOOK_FILES = book.xml diff --git a/lib/stdlib/doc/src/assert_hrl.xml b/lib/stdlib/doc/src/assert_hrl.xml new file mode 100644 index 0000000000..d812ee16dc --- /dev/null +++ b/lib/stdlib/doc/src/assert_hrl.xml @@ -0,0 +1,160 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE fileref SYSTEM "fileref.dtd"> + +<fileref> +  <header> +    <copyright> +      <year>2012</year><year>2015</year> +      <holder>Ericsson AB. All Rights Reserved.</holder> +    </copyright> +    <legalnotice> +      The contents of this file are subject to the Erlang Public License, +      Version 1.1, (the "License"); you may not use this file except in +      compliance with the License. You should have received a copy of the +      Erlang Public License along with this software. If not, it can be +      retrieved online at http://www.erlang.org/. + +      Software distributed under the License is distributed on an "AS IS" +      basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +      the License for the specific language governing rights and limitations +      under the License. + +    </legalnotice> + +    <title>assert.hrl</title> +    <prepared></prepared> +    <docno></docno> +    <date></date> +    <rev></rev> +  </header> +  <file>assert.hrl</file> +  <filesummary>Assert Macros</filesummary> +  <description> +    <p>The include file <c>assert.hrl</c> provides macros for inserting +    assertions in your program code.</p> +    <p>These macros are defined in the Stdlib include file +       <c>assert.hrl</c>. Include the following directive in the module +       from which the function is called:</p> +        <code type="none"> +-include_lib("stdlib/include/assert.hrl").</code> +    <p>When an assertion succeeds, the assert macro yields the atom +    <c>ok</c>. When an assertion fails, an exception of type <c>error</c> is +    instead generated. The associated error term will have the form +    <c>{Macro, Info}</c>, where <c>Macro</c> is the name of the macro, for +    example <c>assertEqual</c>, and <c>Info</c> will be a list of tagged +    values such as <c>[{module, M}, {line, L}, ...]</c> giving more +    information about the location and cause of the exception. All entries +    in the <c>Info</c> list are optional, and you should not rely +    programatically on any of them being present.</p> + +    <p>If the macro <c>NOASSERT</c> is defined when the <c>assert.hrl</c> +    include file is read by the compiler, the macros will be defined as +    equivalent to the atom <c>ok</c>. The test will not be performed, and +    there will be no cost at runtime.</p> + +    <p>For example, using <c>erlc</c> to compile your modules, the following +    will disable all assertions:</p> +        <code type="none"> +erlc -DNOASSERT=true *.erl</code> +    <p>(The value of <c>NOASSERT</c> does not matter, only the fact that it +    is defined.)</p> +    <p>A few other macros also have effect on the enabling or disabling of +    assertions:</p> +    <list type="bulleted"> +      <item>If <c>NODEBUG</c> is defined, it implies <c>NOASSERT</c>, unless +      <c>DEBUG</c> is also defined, which is assumed to take +      precedence.</item> +      <item>If <c>ASSERT</c> is defined, it overrides <c>NOASSERT</c>, that +      is, the assertions will remain enabled.</item> +    </list> +    <p>If you prefer, you can thus use only <c>DEBUG</c>/<c>NODEBUG</c> as +    the main flags to control the behaviour of the assertions (which is +    useful if you have other compiler conditionals or debugging macros +    controlled by those flags), or you can use <c>ASSERT</c>/<c>NOASSERT</c> +    to control only the assert macros.</p> + +  </description> + +  <section> +  </section> + +  <section> +    <title>Macros</title> +    <taglist> +      <tag><c>assert(BoolExpr)</c></tag> +      <item><p>Tests that <c>BoolExpr</c> completes normally returning +      <c>true</c>.</p> +      </item> + +      <tag><c>assertNot(BoolExpr)</c></tag> +      <item><p>Tests that <c>BoolExpr</c> completes normally returning +      <c>false</c>.</p> +      </item> + +      <tag><c>assertMatch(GuardedPattern, Expr)</c></tag> +      <item><p>Tests that <c>Expr</c> completes normally yielding a value +      that matches <c>GuardedPattern</c>. For example: +        <code type="none"> +    ?assertMatch({bork, _}, f())</code></p> +      <p>Note that a guard <c>when ...</c> can be included: +        <code type="none"> +    ?assertMatch({bork, X} when X > 0, f())</code></p> +      </item> + +      <tag><c>assertNotMatch(GuardedPattern, Expr)</c></tag> +      <item><p>Tests that <c>Expr</c> completes normally yielding a value +      that does not match <c>GuardedPattern</c>.</p> +      <p>As in <c>assertMatch</c>, <c>GuardedPattern</c> can have a +      <c>when</c> part.</p> +      </item> + +      <tag><c>assertEqual(ExpectedValue, Expr)</c></tag> +      <item><p>Tests that <c>Expr</c> completes normally yielding a value +      that is exactly equal to <c>ExpectedValue</c>.</p> +      </item> + +      <tag><c>assertNotEqual(ExpectedValue, Expr)</c></tag> +      <item><p>Tests that <c>Expr</c> completes normally yielding a value +      that is not exactly equal to <c>ExpectedValue</c>.</p> +      </item> + +      <tag><c>assertException(Class, Term, Expr)</c></tag> +      <item><p>Tests that <c>Expr</c> completes abnormally with an exception +      of type <c>Class</c> and with the associated <c>Term</c>. The +      assertion fails if <c>Expr</c> raises a different exception or if it +      completes normally returning any value.</p> +      <p>Note that both <c>Class</c> and <c>Term</c> can be guarded +      patterns, as in <c>assertMatch</c>.</p> +      </item> + +      <tag><c>assertNotException(Class, Term, Expr)</c></tag> +      <item><p>Tests that <c>Expr</c> does not evaluate abnormally with an +      exception of type <c>Class</c> and with the associated <c>Term</c>. +      The assertion succeeds if <c>Expr</c> raises a different exception or +      if it completes normally returning any value.</p> +      <p>As in <c>assertException</c>, both <c>Class</c> and <c>Term</c> +      can be guarded patterns.</p> +      </item> + +      <tag><c>assertError(Term, Expr)</c></tag> +      <item><p>Equivalent to <c>assertException(error, Term, +      Expr)</c></p> +      </item> + +      <tag><c>assertExit(Term, Expr)</c></tag> +      <item><p>Equivalent to <c>assertException(exit, Term, Expr)</c></p> +      </item> + +      <tag><c>assertThrow(Term, Expr)</c></tag> +      <item><p>Equivalent to <c>assertException(throw, Term, Expr)</c></p> +      </item> + +    </taglist> +  </section> + +  <section> +    <title>SEE ALSO</title> +    <p><seealso marker="compiler:compile">compile(3)</seealso></p> +    <p><seealso marker="erts:erlc">erlc(3)</seealso></p> +  </section> +</fileref> diff --git a/lib/stdlib/doc/src/ref_man.xml b/lib/stdlib/doc/src/ref_man.xml index eee4a68ca1..cae62612aa 100644 --- a/lib/stdlib/doc/src/ref_man.xml +++ b/lib/stdlib/doc/src/ref_man.xml @@ -35,6 +35,7 @@    </description>    <xi:include href="stdlib_app.xml"/>    <xi:include href="array.xml"/> +  <xi:include href="assert_hrl.xml"/>    <xi:include href="base64.xml"/>    <xi:include href="beam_lib.xml"/>    <xi:include href="binary.xml"/> diff --git a/lib/stdlib/include/assert.hrl b/lib/stdlib/include/assert.hrl new file mode 100644 index 0000000000..239d19a6dc --- /dev/null +++ b/lib/stdlib/include/assert.hrl @@ -0,0 +1,260 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright (C) 2004-2014 Richard Carlsson, Mickaël Rémond +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-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. +%% +%% If asserts are disabled, all assert macros are defined to be the atom +%% 'ok'. If asserts are enabled, all assert macros are defined to yield 'ok' +%% as the result if the test succeeds, and raise an error exception if the +%% test fails. The error term will then have the form {Name, Info} where +%% Name is the name of the macro and Info is a list of tagged tuples. + +%% 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. + +-ifdef(NOASSERT). +-define(assert(BoolExpr),ok). +-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. +-define(assert(BoolExpr), +        begin +        ((fun () -> +            case (BoolExpr) of +                true -> ok; +                __V -> erlang:error({assert, +                                     [{module, ?MODULE}, +                                      {line, ?LINE}, +                                      {expression, (??BoolExpr)}, +                                      {expected, true}, +                                      case __V of false -> {value, __V}; +                                          _ -> {not_boolean,__V} +                                      end]}) +            end +          end)()) +        end). +-endif. + +%% This is the inverse case of assert, for convenience. +-ifdef(NOASSERT). +-define(assertNot(BoolExpr),ok). +-else. +-define(assertNot(BoolExpr), +        begin +        ((fun () -> +            case (BoolExpr) of +                false -> ok; +                __V -> erlang:error({assert, +                                     [{module, ?MODULE}, +                                      {line, ?LINE}, +                                      {expression, (??BoolExpr)}, +                                      {expected, false}, +                                      case __V of true -> {value, __V}; +                                          _ -> {not_boolean,__V} +                                      end]}) +            end +          end)()) +        end). +-endif. + +%% 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), +        begin +        ((fun () -> +            case (Expr) of +                Guard -> ok; +                __V -> erlang:error({assertMatch, +                                     [{module, ?MODULE}, +                                      {line, ?LINE}, +                                      {expression, (??Expr)}, +                                      {pattern, (??Guard)}, +                                      {value, __V}]}) +            end +          end)()) +        end). +-endif. + +%% This is the inverse case of assertMatch, for convenience. +-ifdef(NOASSERT). +-define(assertNotMatch(Guard, Expr), ok). +-else. +-define(assertNotMatch(Guard, Expr), +        begin +        ((fun () -> +            __V = (Expr), +            case __V of +                Guard -> erlang:error({assertNotMatch, +                                       [{module, ?MODULE}, +                                        {line, ?LINE}, +                                        {expression, (??Expr)}, +                                        {pattern, (??Guard)}, +                                        {value, __V}]}); +                _ -> ok +            end +          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), +        begin +        ((fun (__X) -> +            case (Expr) of +                __X -> ok; +                __V -> erlang:error({assertEqual, +                                     [{module, ?MODULE}, +                                      {line, ?LINE}, +                                      {expression, (??Expr)}, +                                      {expected, __X}, +                                      {value, __V}]}) +            end +          end)(Expect)) +        end). +-endif. + +%% This is the inverse case of assertEqual, for convenience. +-ifdef(NOASSERT). +-define(assertNotEqual(Unexpected, Expr), ok). +-else. +-define(assertNotEqual(Unexpected, Expr), +        begin +        ((fun (__X) -> +            case (Expr) of +                __X -> erlang:error({assertNotEqual, +                                     [{module, ?MODULE}, +                                      {line, ?LINE}, +                                      {expression, (??Expr)}, +                                      {value, __X}]}); +                _ -> ok +            end +          end)(Unexpected)) +        end). +-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), +        begin +        ((fun () -> +            try (Expr) of +                __V -> erlang:error({assertException, +                                      [{module, ?MODULE}, +                                       {line, ?LINE}, +                                       {expression, (??Expr)}, +                                       {pattern, +                                        "{ "++(??Class)++" , "++(??Term) +                                        ++" , [...] }"}, +                                       {unexpected_success, __V}]}) +            catch +                Class:Term -> ok; +                __C:__T -> +                    erlang:error({assertException, +                                  [{module, ?MODULE}, +                                   {line, ?LINE}, +                                   {expression, (??Expr)}, +                                   {pattern, +                                    "{ "++(??Class)++" , "++(??Term) +                                    ++" , [...] }"}, +                                   {unexpected_exception, +                                    {__C, __T, +                                     erlang:get_stacktrace()}}]}) +            end +          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), +        begin +        ((fun () -> +            try (Expr) of +                _ -> ok +            catch +                __C:__T -> +                    case __C of +                        Class -> +                            case __T of +                                Term -> +                                    erlang:error({assertNotException, +                                                  [{module, ?MODULE}, +                                                   {line, ?LINE}, +                                                   {expression, (??Expr)}, +                                                   {pattern, +                                                    "{ "++(??Class)++" , " +                                                    ++(??Term)++" , [...] }"}, +                                                   {unexpected_exception, +                                                    {__C, __T, +                                                     erlang:get_stacktrace() +                                                    }}]}); +                                _ -> ok +                            end; +                        _ -> ok +                    end +            end +          end)()) +        end). +-endif. + +-endif. % ASSERT_HRL diff --git a/lib/stdlib/src/Makefile b/lib/stdlib/src/Makefile index 55bda60da5..344a5dc099 100644 --- a/lib/stdlib/src/Makefile +++ b/lib/stdlib/src/Makefile @@ -122,6 +122,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 61eb34d565..d4ab674486 100644 --- a/lib/stdlib/test/Makefile +++ b/lib/stdlib/test/Makefile @@ -107,7 +107,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 206eb4fd74..8ab30eb62b 100644 --- a/lib/stdlib/test/stdlib_SUITE.erl +++ b/lib/stdlib/test/stdlib_SUITE.erl @@ -30,7 +30,7 @@  suite() -> [{ct_hooks,[ts_install_cth]}].  all() ->  -    [app_test, appup_test, {group,upgrade}]. +    [app_test, appup_test, assert_test, {group,upgrade}].  groups() ->       [{upgrade,[minor_upgrade,major_upgrade]}]. @@ -185,3 +185,68 @@ upgrade_upgraded(_CtData,State) ->      State.  upgrade_downgraded(_CtData,State) ->      State. + + +-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) -> +    ok = ?assert(true), +    {'EXIT',{{assert, _},_}} = (catch ?assert(false)), +    {'EXIT',{{assert, Info1},_}} = (catch ?assert(0)), +    {not_boolean,0} = lists:keyfind(not_boolean,1,Info1), + +    ok = ?assertNot(false), +    {'EXIT',{{assert, _},_}} = (catch ?assertNot(true)), +    {'EXIT',{{assert, Info2},_}} = (catch ?assertNot(0)), +    {not_boolean,0} = lists:keyfind(not_boolean,1,Info2), + +    ok = ?assertMatch({foo,_}, {foo,bar}), +    {'EXIT',{{assertMatch,_},_}} = +        (catch ?assertMatch({foo,_}, {foo})), + +    ok = ?assertMatch({foo,N} when N > 0, {foo,1}), +    {'EXIT',{{assertMatch,_},_}} = +        (catch ?assertMatch({foo,N} when N > 0, {foo,0})), + +    ok = ?assertNotMatch({foo,_}, {foo,bar,baz}), +    {'EXIT',{{assertNotMatch,_},_}} = +        (catch ?assertNotMatch({foo,_}, {foo,baz})), + +    ok = ?assertNotMatch({foo,N} when N > 0, {foo,0}), +    {'EXIT',{{assertNotMatch,_},_}} = +        (catch ?assertNotMatch({foo,N} when N > 0, {foo,1})), + +    ok = ?assertEqual(1.0, 1.0), +    {'EXIT',{{assertEqual,_},_}} = (catch ?assertEqual(1, 1.0)), + +    ok = ?assertNotEqual(1, 1.0), +    {'EXIT',{{assertNotEqual,_},_}} = (catch ?assertNotEqual(1.0, 1.0)), + +    ok = ?assertException(error, badarith, 1/0), +    ok = ?assertException(exit, foo, exit(foo)), +    ok = ?assertException(throw, foo, throw(foo)), +    ok = ?assertException(throw, {foo,_}, throw({foo,bar})), +    ok = ?assertException(throw, {foo,N} when N > 0, throw({foo,1})), +    {'EXIT',{{assertException,Why1},_}} = +        (catch ?assertException(error, badarith, 0/1)), +    true = lists:keymember(unexpected_success,1,Why1), +    {'EXIT',{{assertException,Why2},_}} = +        (catch ?assertException(error, badarith, 1/length(0))), +    true = lists:keymember(unexpected_exception,1,Why2), +    {'EXIT',{{assertException,Why3},_}} = +        (catch ?assertException(throw, {foo,N} when N > 0, throw({foo,0}))), +    true = lists:keymember(unexpected_exception,1,Why3), + +    ok = ?assertNotException(throw, {foo,baz}, throw({foo,bar})), +    {'EXIT',{{assertNotException,Why4},_}} = +        (catch ?assertNotException(throw, {foo,bar}, throw({foo,bar}))), +    true = lists:keymember(unexpected_exception,1,Why4), + +    ok = ?assertError(badarith, 1/0), +    ok = ?assertExit(foo, exit(foo)), +    ok = ?assertThrow(foo, throw(foo)), +    ok. | 
