diff options
Diffstat (limited to 'lib/eunit')
42 files changed, 466 insertions, 1464 deletions
diff --git a/lib/eunit/AUTHORS b/lib/eunit/AUTHORS deleted file mode 100644 index b7c1426aff..0000000000 --- a/lib/eunit/AUTHORS +++ /dev/null @@ -1,2 +0,0 @@ -Richard Carlsson <[email protected]> -Micka�l R�mond <[email protected]> diff --git a/lib/eunit/Makefile b/lib/eunit/Makefile index ee69d5e8e0..cd85dff06a 100644 --- a/lib/eunit/Makefile +++ b/lib/eunit/Makefile @@ -13,8 +13,6 @@ # Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings # AB. All Rights Reserved.'' # -# $Id$ -# include $(ERL_TOP)/make/target.mk include $(ERL_TOP)/make/$(TARGET)/otp.mk diff --git a/lib/eunit/doc/.gitignore b/lib/eunit/doc/.gitignore new file mode 100644 index 0000000000..7fcda5db42 --- /dev/null +++ b/lib/eunit/doc/.gitignore @@ -0,0 +1,4 @@ +*.html +stylesheet.css +erlang.png +edoc-info diff --git a/lib/eunit/doc/edoc-info b/lib/eunit/doc/edoc-info deleted file mode 100644 index 1c04b2ed1a..0000000000 --- a/lib/eunit/doc/edoc-info +++ /dev/null @@ -1,3 +0,0 @@ -{application,eunit}. -{packages,[]}. -{modules,[eunit,eunit_surefire]}. diff --git a/lib/eunit/doc/erlang.png b/lib/eunit/doc/erlang.png Binary files differdeleted file mode 100644 index 987a618e24..0000000000 --- a/lib/eunit/doc/erlang.png +++ /dev/null diff --git a/lib/eunit/doc/eunit.html b/lib/eunit/doc/eunit.html deleted file mode 100644 index a181d12ce3..0000000000 --- a/lib/eunit/doc/eunit.html +++ /dev/null @@ -1,71 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> -<html> -<head> -<title>Module eunit</title> -<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc"> -</head> -<body bgcolor="white"> -<div class="navbar"><a name="#navbar_top"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div> -<hr> - -<h1>Module eunit</h1> -<ul class="index"><li><a href="#description">Description</a></li><li><a href="#index">Function Index</a></li><li><a href="#functions">Function Details</a></li></ul>This module is the main EUnit user interface. -<p>Copyright � 2004-2009 Micka�l R�mond, Richard Carlsson</p> - -<p><b>Version:</b> 2.1.1, Apr 22 2009 22:37:19</p> -<p><b>Authors:</b> Micka�l R�mond (<a href="mailto:[email protected]"><tt>[email protected]</tt></a>) [<em>web site:</em> <tt><a href="http://www.process-one.net/" target="_top">http://www.process-one.net/</a></tt>], Richard Carlsson (<a href="mailto:[email protected]"><tt>[email protected]</tt></a>) [<em>web site:</em> <tt><a href="http://user.it.uu.se/~richardc/" target="_top">http://user.it.uu.se/~richardc/</a></tt>].</p> - -<h2><a name="description">Description</a></h2>This module is the main EUnit user interface. -<h2><a name="index">Function Index</a></h2> -<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#start-0">start/0</a></td><td>Starts the EUnit server.</td></tr> -<tr><td valign="top"><a href="#stop-0">stop/0</a></td><td>Stops the EUnit server.</td></tr> -<tr><td valign="top"><a href="#test-1">test/1</a></td><td>Equivalent to <a href="#test-2"><tt>test(Tests, [])</tt></a>. -</td></tr> -<tr><td valign="top"><a href="#test-2">test/2</a></td><td>Runs a set of tests.</td></tr> -</table> - -<h2><a name="functions">Function Details</a></h2> - -<h3 class="function"><a name="start-0">start/0</a></h3> -<div class="spec"> -<p><tt>start() -> any()</tt></p> -</div><p>Starts the EUnit server. Normally, you don't need to call this - function; it is started automatically.</p> - -<h3 class="function"><a name="stop-0">stop/0</a></h3> -<div class="spec"> -<p><tt>stop() -> any()</tt></p> -</div><p>Stops the EUnit server. Normally, you don't need to call this - function.</p> - -<h3 class="function"><a name="test-1">test/1</a></h3> -<div class="spec"> -<p><tt>test(Tests) -> any()</tt></p> -</div><p>Equivalent to <a href="#test-2"><tt>test(Tests, [])</tt></a>.</p> - - -<h3 class="function"><a name="test-2">test/2</a></h3> -<div class="spec"> -<p><tt>test(Tests::term(), Options::[term()]) -> ok | {error, term()}</tt></p> -</div><p><p>Runs a set of tests. The format of <code>Tests</code> is described in the - section <a href="overview-summary.html#EUnit_test_representation">EUnit test - representation</a> of the overview.</p> - - Example: <pre> eunit:test(fred)</pre><p> runs all tests in the module <code>fred</code> - and also any tests in the module <code>fred_tests</code>, if that module exists.</p> - - Options: - <dl> - <dt><code>verbose</code></dt> - <dd>Displays more details about the running tests.</dd> - </dl> - - Options in the environment variable EUNIT are also included last in - the option list, i.e., have lower precedence than those in <code>Options</code>.</p> -<p><b>See also:</b> <a href="#test-1">test/1</a>.</p> -<hr> - -<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div> -<p><i>Generated by EDoc, Apr 22 2009, 22:37:19.</i></p> -</body> -</html> diff --git a/lib/eunit/doc/eunit_surefire.html b/lib/eunit/doc/eunit_surefire.html deleted file mode 100644 index f2ecbae572..0000000000 --- a/lib/eunit/doc/eunit_surefire.html +++ /dev/null @@ -1,78 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> -<html> -<head> -<title>Module eunit_surefire</title> -<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc"> -</head> -<body bgcolor="white"> -<div class="navbar"><a name="#navbar_top"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div> -<hr> - -<h1>Module eunit_surefire</h1> -<ul class="index"><li><a href="#description">Description</a></li><li><a href="#index">Function Index</a></li><li><a href="#functions">Function Details</a></li></ul>Surefire reports for EUnit (Format used by Maven and Atlassian -Bamboo for example to integrate test results). -<p>Copyright � 2009 Micka�l R�mond, Paul Guyot</p> - -<p><b>Behaviours:</b> <a href="eunit_listener.html"><tt>eunit_listener</tt></a>.</p> -<p><b>Authors:</b> Micka�l R�mond (<a href="mailto:[email protected]"><tt>[email protected]</tt></a>).</p> -<p><b>See also:</b> <a href="eunit.html">eunit</a>.</p> - -<h2><a name="description">Description</a></h2><p>Surefire reports for EUnit (Format used by Maven and Atlassian -Bamboo for example to integrate test results). Based on initial code -from Paul Guyot.</p> - - Example: Generate XML result file in the current directory: - <pre> eunit:test([fib, eunit_examples], - [{report,{eunit_surefire,[{dir,"."}]}}]).</pre> -<h2><a name="index">Function Index</a></h2> -<table width="100%" border="1" cellspacing="0" cellpadding="2" summary="function index"><tr><td valign="top"><a href="#handle_begin-3">handle_begin/3</a></td><td></td></tr> -<tr><td valign="top"><a href="#handle_cancel-3">handle_cancel/3</a></td><td></td></tr> -<tr><td valign="top"><a href="#handle_end-3">handle_end/3</a></td><td></td></tr> -<tr><td valign="top"><a href="#init-1">init/1</a></td><td></td></tr> -<tr><td valign="top"><a href="#start-0">start/0</a></td><td></td></tr> -<tr><td valign="top"><a href="#start-1">start/1</a></td><td></td></tr> -<tr><td valign="top"><a href="#terminate-2">terminate/2</a></td><td></td></tr> -</table> - -<h2><a name="functions">Function Details</a></h2> - -<h3 class="function"><a name="handle_begin-3">handle_begin/3</a></h3> -<div class="spec"> -<p><tt>handle_begin(X1, Data, St) -> any()</tt></p> -</div> - -<h3 class="function"><a name="handle_cancel-3">handle_cancel/3</a></h3> -<div class="spec"> -<p><tt>handle_cancel(X1, Data, St) -> any()</tt></p> -</div> - -<h3 class="function"><a name="handle_end-3">handle_end/3</a></h3> -<div class="spec"> -<p><tt>handle_end(X1, Data, St) -> any()</tt></p> -</div> - -<h3 class="function"><a name="init-1">init/1</a></h3> -<div class="spec"> -<p><tt>init(Options) -> any()</tt></p> -</div> - -<h3 class="function"><a name="start-0">start/0</a></h3> -<div class="spec"> -<p><tt>start() -> any()</tt></p> -</div> - -<h3 class="function"><a name="start-1">start/1</a></h3> -<div class="spec"> -<p><tt>start(Options) -> any()</tt></p> -</div> - -<h3 class="function"><a name="terminate-2">terminate/2</a></h3> -<div class="spec"> -<p><tt>terminate(X1, St) -> any()</tt></p> -</div> -<hr> - -<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div> -<p><i>Generated by EDoc, Apr 22 2009, 22:37:19.</i></p> -</body> -</html> diff --git a/lib/eunit/doc/index.html b/lib/eunit/doc/index.html deleted file mode 100644 index 9bd8e8cf6b..0000000000 --- a/lib/eunit/doc/index.html +++ /dev/null @@ -1,17 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> -<html> -<head> -<title>The eunit application</title> -</head> -<frameset cols="20%,80%"> -<frame src="modules-frame.html" name="modulesFrame" title=""> - -<frame src="overview-summary.html" name="overviewFrame" title=""> -<noframes> -<h2>This page uses frames</h2> -<p>Your browser does not accept frames. -<br>You should go to the <a href="overview-summary.html">non-frame version</a> instead. -</p> -</noframes> -</frameset> -</html>
\ No newline at end of file diff --git a/lib/eunit/doc/modules-frame.html b/lib/eunit/doc/modules-frame.html deleted file mode 100644 index a484e99d4c..0000000000 --- a/lib/eunit/doc/modules-frame.html +++ /dev/null @@ -1,13 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> -<html> -<head> -<title>The eunit application</title> -<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc"> -</head> -<body bgcolor="white"> -<h2 class="indextitle">Modules</h2> -<table width="100%" border="0" summary="list of modules"> -<tr><td><a href="eunit.html" target="overviewFrame" class="module">eunit</a></td></tr> -<tr><td><a href="eunit_surefire.html" target="overviewFrame" class="module">eunit_surefire</a></td></tr></table> -</body> -</html>
\ No newline at end of file diff --git a/lib/eunit/doc/overview-summary.html b/lib/eunit/doc/overview-summary.html deleted file mode 100644 index ea7beba8b3..0000000000 --- a/lib/eunit/doc/overview-summary.html +++ /dev/null @@ -1,1032 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> -<html> -<head> -<title>EUnit - a Lightweight Unit Testing Framework for Erlang -</title> -<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc"> -</head> -<body bgcolor="white"> -<div class="navbar"><a name="#navbar_top"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div> -<h1>EUnit - a Lightweight Unit Testing Framework for Erlang -</h1> -<p>Copyright � 2004-2007 Micka�l R�mond, Richard Carlsson</p> -<p><b>Version:</b> 2.1.1, Apr 22 2009 22:37:19 -</p> -<p><b>Authors:</b> Richard Carlsson (<a href="mailto:[email protected]"><tt>[email protected]</tt></a>) [<em>web site:</em> <tt><a href="http://user.it.uu.se/~richardc/" target="_top">http://user.it.uu.se/~richardc/</a></tt>], Micka�l R�mond (<a href="mailto:[email protected]"><tt>[email protected]</tt></a>) [<em>web site:</em> <tt><a href="http://www.process-one.net/" target="_top">http://www.process-one.net/</a></tt>].</p> -<p>EUnit is a unit testing framework for Erlang. It is very powerful -and flexible, is easy to use, and has small syntactical overhead.</p> - -<ul> -<li><a href="#Unit_testing">Unit testing</a></li> -<li><a href="#Terminology">Terminology</a></li> -<li><a href="#Getting_started">Getting started</a></li> -<li><a href="#EUnit_macros">EUnit macros</a></li> -<li><a href="#EUnit_test_representation">EUnit test representation</a></li> -</ul> - -<p>EUnit builds on ideas from the family of unit testing frameworks for -Object Oriented languages that originated with JUnit by Beck and Gamma -(and Beck's previous framework SUnit for Smalltalk). However, EUnit uses -techniques more adapted to functional and concurrent programming, and is -typically less verbose than its relatives.</p> - -<p>Although EUnit uses many preprocessor macros, they have been designed to -be as nonintrusive as possible, and should not cause conflicts with -existing code. Adding EUnit tests to a module should thus not normally -require changing existing code. Furthermore, tests that only exercise -the exported functions of a module can always be placed in a completely -separate module, avoiding any conflicts entirely.</p> - -<h3><a name="Unit_testing">Unit testing</a></h3> - -<p>Unit Testing is testing of individual program "units" in relative -isolation. There is no particular size requirement: a unit can be a -function, a module, a process, or even a whole application, but the most -typical testing units are individual functions or modules. In order to -test a unit, you specify a set of individual tests, set up the smallest -necessary environment for being able to run those tests (often, you -don't need to do any setup at all), you run the tests and collect the -results, and finally you do any necessary cleanup so that the test can -be run again later. A Unit Testing Framework tries to help you in each -stage of this process, so that it is easy to write tests, easy to run -them, and easy to see which tests failed (so you can fix the bugs).</p> - -<h4><a name="Advantages_of_unit_testing">Advantages of unit testing</a></h4> - -<dl> - <dt>Reduces the risks of changing the program</dt> - <dd>Most programs will be modified during their lifetime: bugs will be - fixed, features will be added, optimizations may become necessary, or - the code will need to be refactored or cleaned up in other ways to - make it easier to work with. But every change to a working program is - a risk of introducing new bugs - or reintroducing bugs that had - previously been fixed. Having a set of unit tests that you can run - with very little effort makes it easy to know that the code still - works as it should (this use is called <em>regression testing</em>; - see <a href="#Terminology">Terminology</a>). This goes a long way to reduce the - resistance to changing and refactoring code.</dd> - <dt>Helps guide and speed up the development process</dt> - <dd>By focusing on getting the code to pass the tests, the programmer - can become more productive, not overspecify or get lost in premature - optimizations, and create code that is correct from the very beginning - (so-called <em>test-driven development</em>; see <a href="#Terminology">Terminology</a>).</dd> - <dt>Helps separate interface from implementation</dt> - <dd>When writing tests, the programmer may discover dependencies - (in order to get the tests to run) that ought not to be there, and - which need to be abstracted away to get a cleaner design. This helps - eliminate bad dependencies before they spread throughout the - code.</dd> - <dt>Makes component integration easier</dt> - <dd>By testing in a bottom-up fashion, beginning with the smallest - program units and creating a confidence in that they work as they - should, it becomes easier to test that a higher-level component, - consisting of several such units, also behaves according to - specification (known as <em>integration testing</em>; see <a href="#Terminology">Terminology</a>).</dd> - <dt>Is self-documenting</dt> - <dd>The tests can be read as documentation, typically showing both - examples of correct and incorrect usage, along with the expected - consequences.</dd> -</dl> - -<h3><a name="Terminology">Terminology</a></h3> - -<dl> - <dt>Unit testing</dt> - <dd>Testing that a program unit behaves as it is supposed to do (in - itself), according to its specifications. Unit tests have an important - function as regression tests, when the program later is modified for - some reason, since they check that the program still behaves according - to specification.</dd> - <dt>Regression testing</dt> - <dd>Running a set of tests after making changes to a program, to check - that the program behaves as it did before the changes (except, of - course, for any intentional changes in behaviour). Unit tests are - important as regression tests, but regression testing can involve more - than just unit testing, and may also test behaviour that might not be - part of the normal specification (such as bug-for-bug-compatibility). - </dd> - <dt>Integration testing</dt> - <dd>Testing that a number of individually developed program units - (assumed to already have been separately unit tested) work together as - expected. Depending on the system being developed, integration testing - may be as simple as "just another level of unit testing", but might - also involve other kinds of tests (compare <em>system testing</em>). -</dd> - <dt>System testing</dt> - <dd>Testing that a complete system behaves according to its - specification. Specifically, system testing should not require knowing - any details about the implementation. It typically involves testing - many different aspects of the system behaviour apart from the basic - functionality, such as performance, usability, and reliability.</dd> - <dt>Test-driven development</dt> - <dd>A program development technique where you continuously write tests - <em>before</em> you implement the code that is supposed to pass those - tests. This can help you focus on solving the right problems, and not - make a more complicated implementation than necessary, by letting the - unit tests determine when a program is "done": if it fulfils its - specifications, there is no need to keep adding functionality.</dd> - <dt>Mock object</dt> - <dd>Sometimes, testing some unit <code>A</code> (e.g., a function) requires that - it collaborates somehow with some other unit <code>B</code> (perhaps being passed - as an argument, or by reference) - but <code>B</code> has not been implemented - yet. A "mock object" - an object which, for the purposes of testing - <code>A</code>, looks and behaves like a real <code>B</code> - might then be used instead. - (This is of course only useful if it would be significantly more work - to implement a real <code>B</code> than to create a mock object.)</dd> - <dt>Test case</dt> - <dd>A single, well-defined test, that somehow can be uniquely - identified. When executed, the test case either <em>passes</em> or - <em>fails</em>; the test report should identify exactly which test - cases failed.</dd> - <dt>Test suite</dt> - <dd>A collection of test cases, generally with a specific, common - target for testing, such as a single function, module, or subsystem. A - test suite may also be recursively composed by smaller test - suites.</dd> -</dl> - -<h3><a name="Getting_started">Getting started</a></h3> -<ul> - <li><a href="#Including_the_EUnit_header_file">Including the EUnit header file</a></li> - <li><a href="#Writing_simple_test_functions">Writing simple test functions</a></li> - <li><a href="#Running_EUnit">Running EUnit</a></li> - <li><a href="#Writing_test_generating_functions">Writing test generating functions</a></li> - <li><a href="#An_example">An example</a></li> - <li><a href="#Disabling_testing">Disabling testing</a></li> - <li><a href="#Avoiding_compile-time_dependency_on_EUnit">Avoiding compile-time dependency on EUnit</a></li> -</ul> - -<h4><a name="Including_the_EUnit_header_file">Including the EUnit header file</a></h4> - -The simplest way to use EUnit in an Erlang module is to add the -following line at the beginning of the module (after the <code>-module</code> -declaration, but before any function definitions): -<pre> -include_lib("eunit/include/eunit.hrl").</pre> - -This will have the following effect: -<ul> - <li>Creates an exported function <code>test()</code> (unless testing is turned - off, and the module does not already contain a test() function), that - can be used to run all the unit tests defined in the module</li> - <li>Causes all functions whose names match <code>..._test()</code> or <code>..._test_()</code> - to be automatically exported from the module (unless testing is - turned off, or the <code>EUNIT_NOAUTO</code> macro is defined)</li> - <li>Makes all the preprocessor macros of EUnit available, to help - writing tests</li> -</ul> - -<strong>Note:</strong> For <code>-include_lib(...)</code> to work, the Erlang -module search path <em>must</em> contain a directory whose name ends in -<code>eunit/ebin</code> (pointing to the <code>ebin</code> subdirectory of the EUnit -installation directory). If EUnit is installed as <code>lib/eunit</code> under your -Erlang/OTP system directory, its <code>ebin</code> subdirectory will be -automatically added to the search path when Erlang starts. Otherwise, -you need to add the directory explicitly, by passing a <code>-pa</code> flag to the -<code>erl</code> or <code>erlc</code> command. For example, a Makefile could contain the -following action for compiling <code>.erl</code> files: -<pre> erlc -pa "path/to/eunit/ebin" $(ERL_COMPILE_FLAGS) -o$(EBIN) $<</pre> -or if you want Eunit to always be available when you run Erlang -interactively, you can add a line like the following to your -<code>$HOME/.erlang</code> file: -<pre> code:add_path("/path/to/eunit/ebin").</pre> - -<h4><a name="Writing_simple_test_functions">Writing simple test functions</a></h4> - -<p>The EUnit framework makes it extremely easy to write unit tests in -Erlang. There are a few different ways of writing them, though, so we -start with the simplest:</p> - -<p>A function with a name ending in <code>..._test()</code> is recognized by EUnit as -a simple test function - it takes no arguments, and its execution either -succeeds (returning some arbitrary value that EUnit will throw away), or -fails by throwing an exception of some kind (or by not terminating, in -which case it will be aborted after a while).</p> - -An example of a simple test function could be the following: -<pre> reverse_test() -> lists:reverse([1,2,3]).</pre><p> -This just tests that the function <code>lists:reverse(List)</code> does not crash -when <code>List</code> is <code>[1,2,3]</code>. It is not a great test, but many people write -simple functions like this one to test the basic functionality of their -code, and those tests can be used directly by EUnit, without changes, -as long as their function names match.</p> - -<h5><a name="Use_exceptions_to_signal_failure">Use exceptions to signal failure</a></h5> - -To write more interesting tests, we need to make them crash (throw an -exception) when they don't get the result they expect. A simple way of -doing this is to use pattern matching with <code>=</code>, as in the following -examples: -<pre> reverse_nil_test() -> [] = lists:reverse([]). - reverse_one_test() -> [1] = lists:reverse([1]). - reverse_two_test() -> [2,1] = lists:reverse([1,2]).</pre><p> -If there was some bug in <code>lists:reverse/1</code> that made it return something -other than <code>[2,1]</code> when it got <code>[1,2]</code> as input, then the last test -above would throw a <code>badmatch</code> error. The first two (we assume they do -not get a <code>badmatch</code>) would simply return <code>[]</code> and <code>[1]</code>, respectively, -so both succeed. (Note that EUnit is not psychic: if you write a test -that returns a value, even if it is the wrong value, EUnit will consider -it a success. You must make sure that the test is written so that it -causes a crash if the result is not what it should be.)</p> - -<h5><a name="Using_assert_macros">Using assert macros</a></h5> - -If you want to use Boolean operators for your tests, the <code>assert</code> -macro comes in handy (see <a href="#EUnit_macros">EUnit macros</a> for details): -<pre> length_test() -> ?assert(length([1,2,3]) =:= 3).</pre><p> -The <code>?assert(Expression)</code> macro will evaluate <code>Expression</code>, and if that -does not evaluate to <code>true</code>, it will throw an exception; otherwise it -just returns <code>ok</code>. In the above example, the test will thus fail if the -call to <code>length</code> does not return 3.</p> - -<h4><a name="Running_EUnit">Running EUnit</a></h4> - -<p>If you have added the declaration -<code>-include_lib("eunit/include/eunit.hrl")</code> to your module, as described -above, you only need to compile the module, and run the automatically -exported function <code>test()</code>. For example, if your module was named <code>m</code>, -then calling <code>m:test()</code> will run EUnit on all the tests defined in the -module. You do not need to write <code>-export</code> declarations for the test -functions. This is all done by magic.</p> - -<p>You can also use the function <a href="eunit.html#test-1"><code>eunit:test/1</code></a> to run arbitrary -tests, for example to try out some more advanced test descriptors (see -<a href="#EUnit_test_representation">EUnit test representation</a>). For example, running -<code>eunit:test(m)</code> does the same thing as the auto-generated function -<code>m:test()</code>, while <code>eunit:test({inparallel, m})</code> runs the same test -cases but executes them all in parallel.</p> - -<h5><a name="Putting_tests_in_separate_modules">Putting tests in separate modules</a></h5> - -<p>If you want to separate your test code from your normal code (at least -for testing the exported functions), you can simply write the test -functions in a module named <code>m_tests</code> (note: not <code>m_test</code>), if your -module is named <code>m</code>. Then, whenever you ask EUnit to test the module -<code>m</code>, it will also look for the module <code>m_tests</code> and run those tests as -well. See <code>ModuleName</code> in the section <a href="#Primitives">Primitives</a> for details.</p> - -<h5><a name="EUnit_captures_standard_output">EUnit captures standard output</a></h5> - -<p>If your test code writes to the standard output, you may be surprised to -see that the text does not appear on the console when the tests are -running. This is because EUnit captures all standard output from test -functions (this also includes setup and cleanup functions, but not -generator functions), so that it can be included in the test report if -errors occur. To bypass EUnit and print text directly to the console -while testing, you can write to the <code>user</code> output stream, as in -<code>io:format(user, "~w", [Term])</code>. The recommended way of doing this is to -use the EUnit <a href="#Debugging_macros">Debugging macros</a>, which make it much simpler.</p> - -<h4><a name="Writing_test_generating_functions">Writing test generating functions</a></h4> - -<p>A drawback of simple test functions is that you must write a separate -function (with a separate name) for each test case. A more compact way -of writing tests (and much more flexible, as we shall see), is to write -functions that <em>return</em> tests, instead of <em>being</em> tests.</p> - -<p>A function with a name ending in <code>..._test_()</code> (note the final -underscore) is recognized by EUnit as a <em>test generator</em> -function. Test generators return a <em>representation</em> of a <em>set -of tests</em> to be executed by EUnit.</p> - -<h5><a name="Representing_a_test_as_data">Representing a test as data</a></h5> - -The most basic representation of a test is a single fun-expression that -takes no arguments. For example, the following test generator: -<pre> basic_test_() -> - fun () -> ?assert(1 + 1 =:= 2) end.</pre> -will have the same effect as the following simple test: -<pre> simple_test() -> - ?assert(1 + 1 =:= 2).</pre><p> -(in fact, EUnit will handle all simple tests just like it handles -fun-expressions: it will put them in a list, and run them one by one).</p> - -<h5><a name="Using_macros_to_write_tests">Using macros to write tests</a></h5> - -To make tests more compact and readable, as well as automatically add -information about the line number in the source code where a test -occurred (and reduce the number of characters you have to type), you can -use the <code>_test</code> macro (note the initial underscore character), like -this: -<pre> basic_test_() -> - ?_test(?assert(1 + 1 =:= 2)).</pre><p> -The <code>_test</code> macro takes any expression (the "body") as argument, and -places it within a fun-expression (along with some extra information). -The body can be any kind of test expression, just like the body of a -simple test function.</p> - -<h5><a name="Underscore-prefixed_macros_create_test_objects">Underscore-prefixed macros create test objects</a></h5> - -But this example can be made even shorter! Most test macros, such as the -family of <code>assert</code> macros, have a corresponding form with an initial -underscore character, which automatically adds a <code>?_test(...)</code> wrapper. -The above example can then simply be written: -<pre> basic_test_() -> - ?_assert(1 + 1 =:= 2).</pre><p> -which has exactly the same meaning (note the <code>_assert</code> instead of -<code>assert</code>). You can think of the initial underscore as signalling -<em>test object</em>.</p> - -<h4><a name="An_example">An example</a></h4> - -Sometimes, an example says more than a thousand words. The following -small Erlang module shows how EUnit can be used in practice. -<pre> -module(fib). - -export([fib/1]). - -include_lib("eunit/include/eunit.hrl"). - - fib(0) -> 1; - fib(1) -> 1; - fib(N) when N > 1 -> fib(N-1) + fib(N-2). - - fib_test_() -> - [?_assert(fib(0) =:= 1), - ?_assert(fib(1) =:= 1), - ?_assert(fib(2) =:= 2), - ?_assert(fib(3) =:= 3), - ?_assert(fib(4) =:= 5), - ?_assert(fib(5) =:= 8), - ?_assertException(error, function_clause, fib(-1)), - ?_assert(fib(31) =:= 2178309) - ].</pre> - -<p>(Author's note: When I first wrote this example, I happened to write a -<code>*</code> instead of <code>+</code> in the <code>fib</code> function. Of course, this showed up -immediately when I ran the tests.)</p> - -<p>See <a href="#EUnit_test_representation">EUnit test representation</a> for a full list of all the ways -you can specify test sets in EUnit.</p> - -<h4><a name="Disabling_testing">Disabling testing</a></h4> - -Testing can be turned off by defining the <code>NOTEST</code> macro when compiling, -for example as an option to <code>erlc</code>, as in: -<pre> erlc -DNOTEST my_module.erl</pre> -or by adding a macro definition to the code, <em>before the EUnit header -file is included</em>: -<pre> -define(NOTEST, 1).</pre><p> -(the value is not important, but should typically be 1 or <code>true</code>). -Note that unless the <code>EUNIT_NOAUTO</code> macro is defined, disabling testing -will also automatically strip all test functions from the code, except -for any that are explicitly declared as exported.</p> - -For instance, to use EUnit in your application, but with testing turned -off by default, put the following lines in a header file: -<pre> -define(NOTEST, true). - -include_lib("eunit/include/eunit.hrl").</pre> -and then make sure that every module of your application includes that -header file. This means that you have a only a single place to modify in -order to change the default setting for testing. To override the <code>NOTEST</code> -setting without modifying the code, you can define <code>TEST</code> in a compiler -option, like this: -<pre> erlc -DTEST my_module.erl</pre> - -<p>See <a href="#Compilation_control_macros">Compilation control macros</a> for details about these -macros.</p> - -<h4><a name="Avoiding_compile-time_dependency_on_EUnit">Avoiding compile-time dependency on EUnit</a></h4> - -If you are distributing the source code for your application for other -people to compile and run, you probably want to ensure that the code -compiles even if EUnit is not available. Like the example in the -previous section, you can put the following lines in a common header -file: -<pre> -ifdef(TEST). - -include_lib("eunit/include/eunit.hrl"). - -endif.</pre><p> -and, of course, also make sure that you place all test code that uses -EUnit macros within <code>-ifdef(TEST)</code> or <code>-ifdef(EUNIT)</code> sections.</p> - - -<h3><a name="EUnit_macros">EUnit macros</a></h3> - -<p>Although all the functionality of EUnit is avaliable even without the -use of preprocessor macros, the EUnit header file defines a number of -such macros in order to make it as easy as possible to write unit tests -as compactly as possible and without getting too many details in the -way.</p> - -<p>Except where explicitly stated, using EUnit macros will never introduce -run-time dependencies on the EUnit library code, regardless of whether -your code is compiled with testing enabled or disabled.</p> - -<ul> -<li><a href="#Basic_macros">Basic macros</a></li> -<li><a href="#Compilation_control_macros">Compilation control macros</a></li> -<li><a href="#Utility_macros">Utility macros</a></li> -<li><a href="#Assert_macros">Assert macros</a></li> -<li><a href="#Macros_for_running_external_commands">Macros for running external commands</a></li> -<li><a href="#Debugging_macros">Debugging macros</a></li> -</ul> - -<h4><a name="Basic_macros">Basic macros</a></h4> - -<dl> -<dt><code>_test(Expr)</code></dt> -<dd>Turns <code>Expr</code> into a "test object", by wrapping it in a -fun-expression and a source line number. Technically, this is the same -as <code>{?LINE, fun () -> (Expr) end}</code>. -</dd> -</dl> - -<h4><a name="Compilation_control_macros">Compilation control macros</a></h4> - -<dl> -<dt><code>EUNIT</code></dt> -<dd>This macro is always defined to <code>true</code> whenever EUnit is enabled at -compile time. This is typically used to place testing code within -conditional compilation, as in: -<pre> -ifdef(EUNIT). - % test code here - ... - -endif.</pre> -e.g., to ensure that the code can be compiled without including the -EUnit header file, when testing is disabled. See also the macros <code>TEST</code> -and <code>NOTEST</code>. -</dd> - -<dt><code>EUNIT_NOAUTO</code></dt> -<dd>If this macro is defined, the automatic exporting or stripping of -test functions will be disabled. -</dd> - -<dt><code>TEST</code></dt> -<dd><p>This macro is always defined (to <code>true</code>, unless previously defined -by the user to have another value) whenever EUnit is enabled at compile -time. This can be used to place testing code within conditional -compilation; see also the macros <code>NOTEST</code> and <code>EUNIT</code>.</p> - -<p>For testing code that is strictly dependent on EUnit, it may be -preferable to use the <code>EUNIT</code> macro for this purpose, while for code -that uses more generic testing conventions, using the <code>TEST</code> macro may -be preferred.</p> - -The <code>TEST</code> macro can also be used to override the <code>NOTEST</code> macro. If -<code>TEST</code> is defined <em>before</em> the EUnit header file is -included (even if <code>NOTEST</code> is also defined), then the code will be -compiled with EUnit enabled. -</dd> - -<dt><code>NOTEST</code></dt> -<dd><p>This macro is always defined (to <code>true</code>, unless previously defined -by the user to have another value) whenever EUnit is <em>disabled</em> -at compile time. (Compare the <code>TEST</code> macro.)</p> - -This macro can also be used for conditional compilation, but is more -typically used to disable testing: If <code>NOTEST</code> is defined -<em>before</em> the EUnit header file is included, and <code>TEST</code> -is <em>not</em> defined, then the code will be compiled with EUnit -disabled. See also <a href="#Disabling_testing">Disabling testing</a>. -</dd> - -<dt><code>NOASSERT</code></dt> -<dd>If this macro is defined, the assert macros will have no effect, -when testing is also disabled. See <a href="#Assert_macros">Assert macros</a>. When -testing is enabled, the assert macros are always enabled automatically -and cannot be disabled. -</dd> - -<dt><code>ASSERT</code></dt> -<dd>If this macro is defined, it overrides the NOASSERT macro, forcing -the assert macros to always be enabled regardless of other settings. -</dd> - -<dt><code>NODEBUG</code></dt> -<dd>If this macro is defined, the debugging macros will have no effect. -See <a href="#Debugging_macros">Debugging macros</a>. <code>NODEBUG</code> also implies <code>NOASSERT</code>, -unless testing is enabled. -</dd> - -<dt><code>DEBUG</code></dt> -<dd>If this macro is defined, it overrides the NODEBUG macro, forcing -the debugging macros to be enabled. -</dd> -</dl> - -<h4><a name="Utility_macros">Utility macros</a></h4> - -<p>The following macros can make tests more compact and readable:</p> - -<dl> -<dt><code>LET(Var,Arg,Expr)</code></dt> -<dd>Creates a local binding <code>Var = Arg</code> in <code>Expr</code>. (This is the same as -<code>(fun(Var)->(Expr)end)(Arg)</code>.) Note that the binding is not exported -outside of <code>Expr</code>, and that within <code>Expr</code>, this binding of <code>Var</code> will -shadow any binding of <code>Var</code> in the surrounding scope. -</dd> -<dt><code>IF(Cond,TrueCase,FalseCase)</code></dt> -<dd>Evaluates <code>TrueCase</code> if <code>Cond</code> evaluates to <code>true</code>, or otherwise -evaluates <code>FalseCase</code> if <code>Cond</code> evaluates to <code>false</code>. (This is the same -as <code>(case (Cond) of true->(TrueCase); false->(FalseCase) end)</code>.) Note -that it is an error if <code>Cond</code> does not yield a boolean value. -</dd> -</dl> - -<h4><a name="Assert_macros">Assert macros</a></h4> - -<p>(Note that these macros also have corresponding forms which start with -an "<code>_</code>" (underscore) character, as in <code>?_assert(BoolExpr)</code>, that create -a "test object" instead of performing the test immediately. This is -equivalent to writing <code>?_test(assert(BoolExpr))</code>, etc.)</p> - -<p>If the macro <code>NOASSERT</code> is defined before the EUnit header file is -included, these macros have no effect when testing is also disabled; see -<a href="#Compilation_control_macros">Compilation control macros</a> for details.</p> - -<dl> -<dt><code>assert(BoolExpr)</code></dt> -<dd><p>Evaluates the expression <code>BoolExpr</code>, if testing is enabled. Unless -the result is <code>true</code>, an informative exception will be generated. If -there is no exception, the result of the macro expression is the atom -<code>ok</code>, and the value of <code>BoolExpr</code> is discarded. If testing is disabled, -the macro will not generate any code except the atom <code>ok</code>, and -<code>BoolExpr</code> will not be evaluated.</p> - -Typical usage: -<pre> ?assert(f(X, Y) =:= [])</pre> - -The <code>assert</code> macro can be used anywhere in a program, not just in unit -tests, to check pre/postconditions and invariants. For example: -<pre> some_recursive_function(X, Y, Z) -> - ?assert(X + Y > Z), - ...</pre> -</dd> -<dt><code>assertNot(BoolExpr)</code></dt> -<dd>Equivalent to <code>assert(not (BoolExpr))</code>. -</dd> -<dt><code>assertMatch(GuardedPattern, Expr)</code></dt> -<dd><p>Evaluates <code>Expr</code> and matches the result against <code>GuardedPattern</code>, if -testing is enabled. If the match fails, an informative exception will be -generated; see the <code>assert</code> macro for further details. <code>GuardedPattern</code> -can be anything that you can write on the left hand side of the <code>-></code> -symbol in a case-clause, except that it cannot contain comma-separated -guard tests.</p> - -<p>The main reason for using <code>assertMatch</code> also for simple matches, instead -of matching with <code>=</code>, is that it produces more detailed error messages.</p> - -Examples: -<pre> ?assertMatch({found, {fred, _}}, lookup(bloggs, Table))</pre> -<pre> ?assertMatch([X|_] when X > 0, binary_to_list(B))</pre> -</dd> -<dt><code>assertEqual(Expect, Expr)</code></dt> -<dd><p>Evaluates the expressions <code>Expect</code> and <code>Expr</code> and compares the -results for equality, if testing is enabled. If the values are not -equal, an informative exception will be generated; see the <code>assert</code> -macro for further details.</p> - -<p><code>assertEqual</code> is more suitable than than <code>assertMatch</code> when the -left-hand side is a computed value rather than a simple pattern, and -gives more details than <code>?assert(Expect =:= Expr)</code>.</p> - -Examples: -<pre> ?assertEqual("b" ++ "a", lists:reverse("ab"))</pre> -<pre> ?assertEqual(foo(X), bar(Y))</pre> -</dd> -<dt><code>assertException(ClassPattern, TermPattern, Expr)</code></dt> -<dt><code>assertError(TermPattern, Expr)</code></dt> -<dt><code>assertExit(TermPattern, Expr)</code></dt> -<dt><code>assertThrow(TermPattern, Expr)</code></dt> -<dd><p>Evaluates <code>Expr</code>, catching any exception and testing that it matches -the expected <code>ClassPattern:TermPattern</code>. If the match fails, or if no -exception is thrown by <code>Expr</code>, an informative exception will be -generated; see the <code>assert</code> macro for further details. The -<code>assertError</code>, <code>assertExit</code>, and <code>assertThrow</code> macros, are equivalent to -using <code>assertException</code> with a <code>ClassPattern</code> of <code>error</code>, <code>exit</code>, or -<code>throw</code>, respectively.</p> - -Examples: -<pre> ?assertError(badarith, X/0)</pre> -<pre> ?assertExit(normal, exit(normal))</pre> -<pre> ?assertException(throw, {not_found,_}, throw({not_found,42}))</pre> -</dd> -</dl> - -<h4><a name="Macros_for_running_external_commands">Macros for running external commands</a></h4> - -<p>Keep in mind that external commands are highly dependent on the -operating system. You can use the standard library function <code>os:type()</code> -in test generator functions, to produce different sets of tests -depending on the current operating system.</p> - -<p>Note: these macros introduce a run-time dependency on the EUnit library -code, if compiled with testing enabled.</p> - -<dl> -<dt><code>assertCmd(CommandString)</code></dt> -<dd><p>Runs <code>CommandString</code> as an external command, if testing is enabled. -Unless the returned status value is 0, an informative exception will be -generated. If there is no exception, the result of the macro expression -is the atom <code>ok</code>. If testing is disabled, the macro will not generate -any code except the atom <code>ok</code>, and the command will not be executed.</p> - -Typical usage: -<pre> ?assertCmd("mkdir foo")</pre> -</dd> -<dt><code>assertCmdStatus(N, CommandString)</code></dt> -<dd>Like the <code>assertCmd(CommandString)</code> macro, but generates an -exception unless the returned status value is <code>N</code>. -</dd> -<dt><code>assertCmdOutput(Text, CommandString)</code></dt> -<dd>Runs <code>CommandString</code> as an external command, if testing is enabled. -Unless the output produced by the command exactly matches the specified -string <code>Text</code>, an informative exception will be generated. (Note that -the output is normalized to use a single LF character as line break on -all platforms.) If there is no exception, the result of the macro -expression is the atom <code>ok</code>. If testing is disabled, the macro will not -generate any code except the atom <code>ok</code>, and the command will not be -executed. -</dd> -<dt><code>cmd(CommandString)</code></dt> -<dd><p>Runs <code>CommandString</code> as an external command. Unless the returned -status value is 0 (indicating success), an informative exception will be -generated; otherwise, the result of the macro expression is the output -produced by the command, as a flat string. The output is normalized to -use a single LF character as line break on all platforms.</p> - -<p>This macro is useful in the setup and cleanup sections of fixtures, -e.g., for creating and deleting files or perform similar operating -system specific tasks, to make sure that the test system is informed of -any failures.</p> - -A Unix-specific example: -<pre> {setup, - fun () -> ?cmd("mktemp") end, - fun (FileName) -> ?cmd("rm " ++ FileName) end, - ...}</pre> -</dd> -</dl> - -<h4><a name="Debugging_macros">Debugging macros</a></h4> - -<p>To help with debugging, EUnit defines several useful macros for printing -messages directly to the console (rather than to the standard output). -Furthermore, these macros all use the same basic format, which includes -the file and line number where they occur, making it possible in some -development environments (e.g., when running Erlang in an Emacs buffer) -to simply click on the message and jump directly to the corresponding -line in the code.</p> - -<p>If the macro <code>NODEBUG</code> is defined before the EUnit header file is -included, these macros have no effect; see -<a href="#Compilation_control_macros">Compilation control macros</a> for details.</p> - -<dl> -<dt><code>debugHere</code></dt> -<dd>Just prints a marker showing the current file and line number. Note -that this is an argument-less macro. The result is always <code>ok</code>.</dd> -<dt><code>debugMsg(Text)</code></dt> -<dd>Outputs the message <code>Text</code> (which can be a plain string, an IO-list, -or just an atom). The result is always <code>ok</code>.</dd> -<dt><code>debugFmt(FmtString, Args)</code></dt> -<dd>This formats the text like <code>io:format(FmtString, Args)</code> and outputs -it like <code>debugMsg</code>. The result is always <code>ok</code>.</dd> -<dt><code>debugVal(Expr)</code></dt> -<dd>Prints both the source code for <code>Expr</code> and its current value. E.g., -<code>?debugVal(f(X))</code> might be displayed as "<code>f(X) = 42</code>". (Large terms are -shown truncated.) The result is always the value of <code>Expr</code>, so this -macro can be wrapped around any expression to display its value when -the code is compiled with debugging enabled.</dd> -<dt><code>debugTime(Text,Expr)</code></dt> -<dd>Prints <code>Text</code> and the wall clock time for evaluation of <code>Expr</code>. The -result is always the value of <code>Expr</code>, so this macro can be wrapped -around any expression to show its run time when the code is compiled -with debugging enabled. For example, <code>List1 = ?debugTime("sorting", -lists:sort(List))</code> might show as "<code>sorting: 0.015 s</code>".</dd> - -</dl> - - -<h3><a name="EUnit_test_representation">EUnit test representation</a></h3> - -<p>The way EUnit represents tests and test sets as data is flexible, -powerful, and concise. This section describes the representation in -detail.</p> - -<ul> -<li><a href="#Simple_test_objects">Simple test objects</a></li> -<li><a href="#Test_sets_and_deep_lists">Test sets and deep lists</a></li> -<li><a href="#Titles">Titles</a></li> -<li><a href="#Primitives">Primitives</a></li> -<li><a href="#Control">Control</a></li> -<li><a href="#Fixtures">Fixtures</a></li> -<li><a href="#Lazy_generators">Lazy generators</a></li> -</ul> - -<h4><a name="Simple_test_objects">Simple test objects</a></h4> - -A <em>simple test object</em> is one of the following: -<ul> - <li>A nullary functional value (i.e., a fun that takes zero - arguments). Examples: -<pre> fun () -> ... end</pre> -<pre> fun some_function/0</pre> -<pre> fun some_module:some_function/0</pre> - </li> - <li>A pair of atoms <code>{ModuleName, FunctionName}</code>, referring to the - function <code>ModuleName:FunctionName/0</code></li> - <li>A pair <code>{LineNumber, SimpleTest}</code>, where <code>LineNumber</code> is a - nonnegative integer and <code>SimpleTest</code> is another simple test - object. <code>LineNumber</code> should indicate the source line of the test. - Pairs like this are usually only created via <code>?_test(...)</code> macros; - see <a href="#Basic_macros">Basic macros</a>.</li> -</ul><p> -In brief, a simple test object consists of a single function that takes -no arguments (possibly annotated with some additional metadata, i.e., a -line number). Evaluation of the function either <em>succeeds</em>, by -returning some value (which is ignored), or <em>fails</em>, by throwing -an exception.</p> - -<h4><a name="Test_sets_and_deep_lists">Test sets and deep lists</a></h4> - -<p>A test set can be easily created by placing a sequence of test objects -in a list. If <code>T_1</code>, ..., <code>T_N</code> are individual test objects, then <code>[T_1, -..., T_N]</code> is a test set consisting of those objects (in that order).</p> - -<p>Test sets can be joined in the same way: if <code>S_1</code>, ..., <code>S_K</code> are test -sets, then <code>[S_1, ..., S_K]</code> is also a test set, where the tests of -<code>S_i</code> are ordered before those of <code>S_(i+1)</code>, for each subset <code>S_i</code>.</p> - -<p>Thus, the main representation of test sets is <em>deep lists</em>, and -a simple test object can be viewed as a test set containing only a -single test; there is no difference between <code>T</code> and <code>[T]</code>.</p> - -<p>A module can also be used to represent a test set; see <code>ModuleName</code> -under <a href="#Primitives">Primitives</a> below.</p> - -<h4><a name="Titles">Titles</a></h4> - -<p>Any test or test set <code>T</code> can be annotated with a title, by wrapping it -in a pair <code>{Title, T}</code>, where <code>Title</code> is a string. For convenience, any -test which is normally represented using a tuple can simply be given a -title string as the first element, i.e., writing <code>{"The Title", ...}</code> -instead of adding an extra tuple wrapper as in <code>{"The Title", {...}}</code>.</p> - - -<h4><a name="Primitives">Primitives</a></h4> - -The following are primitives, which do not contain other test sets as -arguments: -<dl> -<dt><code>ModuleName::atom()</code> -</dt> -<dd>A single atom represents a module name, and is equivalent to -<code>{module, ModuleName}</code>. This is often used as in the call -<code>eunit:test(some_module)</code>. -</dd> -<dt><code>{module, ModuleName::atom()}</code> -</dt> -<dd><p>This composes a test set from the exported test functions of the -named module, i.e., those functions with arity zero whose names end -with <code>_test</code> or <code>_test_</code>. Basically, the <code>..._test()</code> functions become -simple tests, while the <code>..._test_()</code> functions become generators.</p> - -In addition, EUnit will also look for another module whose name is -<code>ModuleName</code> plus the suffix <code>_tests</code>, and if it exists, all the tests -from that module will also be added. (If <code>ModuleName</code> already contains -the suffix <code>_tests</code>, this is not done.) E.g., the specification -<code>{module, mymodule}</code> will run all tests in the modules <code>mymodule</code> and -<code>mymodule_tests</code>. Typically, the <code>_tests</code> module should only contain -test cases that use the public interface of the main module (and no -other code). -</dd> -<dt><code>{application, AppName::atom(), Info::list()}</code> -</dt> -<dd>This is a normal Erlang/OTP application descriptor, as found in an - <code>.app</code> file. The resulting test set consists of the modules listed in - the <code>modules</code> entry in <code>Info</code>. -</dd> -<dt><code>{application, AppName::atom()}</code> -</dt> -<dd>This creates a test set from all the modules belonging to the -specified application, by consulting the application's <code>.app</code> file -(see <code>{file, FileName}</code>), or if no such file exists, by testing all -object files in the application's <tt>ebin</tt>-directory (see <code>{dir, -Path}</code>); if that does not exist, the <code>code:lib_dir(AppName)</code> directory -is used. -</dd> -<dt><code>Path::string()</code> -</dt> -<dd>A single string represents the path of a file or directory, and is -equivalent to <code>{file, Path}</code>, or <code>{dir, Path}</code>, respectively, depending -on what <code>Path</code> refers to in the file system. -</dd> -<dt><code>{file, FileName::string()}</code> -</dt> -<dd><p>If <code>FileName</code> has a suffix that indicates an object file (<code>.beam</code>), -EUnit will try to reload the module from the specified file and test it. -Otherwise, the file is assumed to be a text file containing test -specifications, which will be read using the standard library function -<code>file:path_consult/2</code>.</p> - -Unless the file name is absolute, the file is first searched for -relative to the current directory, and then using the normal search path -(<code>code:get_path()</code>). This means that the names of typical "app" files -can be used directly, without a path, e.g., <code>"mnesia.app"</code>. -</dd> -<dt><code>{dir, Path::string()}</code> -</dt> -<dd>This tests all object files in the specified directory, as if they -had been individually specified using <code>{file, FileName}</code>. -</dd> -<dt><code>{generator, GenFun::(() -> Tests)}</code> -</dt> -<dd>The generator function <code>GenFun</code> is called to produce a test -set. -</dd> -<dt><code>{generator, ModuleName::atom(), FunctionName::atom()}</code> -</dt> -<dd>The function <code>ModuleName:FunctionName()</code> is called to produce a test -set. -</dd> -<dt><code>{with, X::any(), [AbstractTestFun::((any()) -> any())]}</code> -</dt> -<dd>Distributes the value <code>X</code> over the unary functions in the list, -turning them into nullary test functions. An <code>AbstractTestFun</code> is like -an ordinary test fun, but takes one argument instead of zero - it's -basically missing some information before it can be a proper test. In -practice, <code>{with, X, [F_1, ..., F_N]}</code> is equivalent to <code>[fun () -> -F_1(X) end, ..., fun () -> F_N(X) end]</code>. This is particularly useful if -your abstract test functions are already implemented as proper -functions: <code>{with, FD, [fun filetest_a/1, fun filetest_b/1, fun -filetest_c/1]}</code> is equivalent to <code>[fun () -> filetest_a(FD) end, fun () --> filetest_b(FD) end, fun () -> filetest_c(FD) end]</code>, but much more -compact. See also <a href="#Fixtures">Fixtures</a>, below. -</dd> -</dl> - -<h4><a name="Control">Control</a></h4> - -The following representations control how and where tests are executed: -<dl> -<dt><code>{spawn, Tests}</code></dt> -<dd>Runs the specified tests in a separate subprocess, while the current -test process waits for it to finish. This is useful for tests that need -a fresh, isolated process state. (Note that EUnit always starts at least -one such a subprocess automatically; tests are never executed by the -caller's own process.)</dd> -<dt><code>{spawn, Node::atom(), Tests}</code></dt> -<dd>Like <code>{spawn, Tests}</code>, but runs the specified tests on the given -Erlang node.</dd> -<dt><code>{timeout, Time::number(), Tests}</code></dt> -<dd>Runs the specified tests under the given timeout. Time is in -seconds; e.g., 60 means one minute and 0.1 means 1/10th of a second. If -the timeout is exceeded, the unfinished tests will be forced to -terminate. Note that if a timeout is set around a fixture, it includes -the time for setup and cleanup, and if the timeout is triggered, the -entire fixture is abruptly terminated (without running the -cleanup).</dd> -<dt><code>{inorder, Tests}</code></dt> -<dd>Runs the specified tests in strict order. Also see <code>{inparallel, -Tests}</code>. By default, tests are neither marked as <code>inorder</code> or -<code>inparallel</code>, but may be executed as the test framework chooses.</dd> -<dt><code>{inparallel, Tests}</code></dt> -<dd>Runs the specified tests in parallel (if possible). Also see -<code>{inorder, Tests}</code>.</dd> -<dt><code>{inparallel, N::integer(), Tests}</code></dt> -<dd>Like <code>{inparallel, Tests}</code>, but running no more than <code>N</code> subtests -simultaneously.</dd> -</dl> - -<h4><a name="Fixtures">Fixtures</a></h4> - -<p>A "fixture" is some state that is necessary for a particular set of -tests to run. EUnit's support for fixtures makes it easy to set up such -state locally for a test set, and automatically tear it down again when -the test set is finished, regardless of the outcome (success, failures, -timeouts, etc.).</p> - -<p>To make the descriptions simpler, we first list some definitions: -<center> -<table border="0" cellspacing="4"> -<tr> -<td><code>Setup</code></td><td><code>() -> (R::any())</code></td> -</tr> -<tr> -<td><code>SetupX</code></td><td><code>(X::any()) -> (R::any())</code></td> -</tr> -<tr> -<td><code>Cleanup</code></td><td><code>(R::any()) -> any()</code></td> -</tr> -<tr> -<td><code>CleanupX</code></td><td><code>(X::any(), R::any()) -> any()</code></td> -</tr> -<tr> -<td><code>Instantiator</code></td><td><code>((R::any()) -> Tests) | {with, [AbstractTestFun::((any()) -> any())]}</code></td> -</tr> -<tr> -<td><code>Where</code></td><td><code>local | spawn | {spawn, Node::atom()}</code></td> -</tr> -</table> -</center> -(these are explained in more detail further below.)</p> - -The following representations specify fixture handling for test sets: -<dl> -<dt><code>{setup, Setup, Tests | Instantiator}</code></dt> -<dt><code>{setup, Setup, Cleanup, Tests | Instantiator}</code></dt> -<dt><code>{setup, Where, Setup, Tests | Instantiator}</code></dt> -<dt><code>{setup, Where, Setup, Cleanup, Tests | Instantiator}</code></dt> -<dd><code>setup</code> sets up a single fixture for running all of the specified -tests, with optional teardown afterwards. The arguments are described in -detail below. -</dd> -<dt><code>{node, Node::atom(), Tests | Instantiator}</code></dt> -<dt><code>{node, Node::atom(), Args::string(), Tests | Instantiator}</code></dt> -<dd><code>node</code> is like <code>setup</code>, but with a built-in behaviour: it starts a -slave node for the duration of the tests. The atom <code>Node</code> should have -the format <code>[email protected]</code>, and <code>Args</code> are the optional -arguments to the new node; see <code>slave:start_link/3</code> for details. -</dd> -<dt><code>{foreach, Where, Setup, Cleanup, [Tests | Instantiator]}</code></dt> -<dt><code>{foreach, Setup, Cleanup, [Tests | Instantiator]}</code></dt> -<dt><code>{foreach, Where, Setup, [Tests | Instantiator]}</code></dt> -<dt><code>{foreach, Setup, [Tests | Instantiator]}</code></dt> -<dd><code>foreach</code> is used to set up a fixture and optionally tear it down -afterwards, repeated for each single one of the specified test sets. -</dd> -<dt><code>{foreachx, Where, SetupX, CleanupX, - Pairs::[{X::any(), ((X::any(), R::any()) -> Tests)}]}</code></dt> -<dt><code>{foreachx, SetupX, CleanupX, Pairs}</code></dt> -<dt><code>{foreachx, Where, SetupX, Pairs}</code></dt> -<dt><code>{foreachx, SetupX, Pairs}</code></dt> -<dd><code>foreachx</code> is like <code>foreach</code>, but uses a list of pairs, each -containing an extra argument <code>X</code> and an extended instantiator function. -</dd> -</dl> - -<p>A <code>Setup</code> function is executed just before any of the specified tests -are run, and a <code>Cleanup</code> function is executed when no more of the -specified tests will be run, regardless of the reason. A <code>Setup</code> -function takes no argument, and returns some value which will be passed -as it is to the <code>Cleanup</code> function. A <code>Cleanup</code> function should do -whatever necessary and return some arbitrary value, such as the atom -<code>ok</code>. (<code>SetupX</code> and <code>CleanupX</code> functions are similar, but receive one -additional argument: some value <code>X</code>, which depends on the context.) When -no <code>Cleanup</code> function is specified, a dummy function is used which has -no effect.</p> - -<p>An <code>Instantiator</code> function receives the same value as the <code>Cleanup</code> -function, i.e., the value returned by the <code>Setup</code> function. It should -then behave much like a generator (see <a href="#Primitives">Primitives</a>), and -return a test set whose tests have been <em>instantiated</em> with the -given value. A special case is the syntax <code>{with, [AbstractTestFun]}</code> -which represents an instantiator function that distributes the value -over a list of unary functions; see <a href="#Primitives">Primitives</a>: <code>{with, X, -[...]}</code> for more details.</p> - -A <code>Where</code> term controls how the specified tests are executed. The -default is <code>spawn</code>, which means that the current process handles the -setup and teardown, while the tests are executed in a subprocess. -<code>{spawn, Node}</code> is like <code>spawn</code>, but runs the subprocess on the -specified node. <code>local</code> means that the current process will handle both -setup/teardown and running the tests - the drawback is that if a test -times out so that the process is killed, the <em>cleanup will not be -performed</em>; hence, avoid this for persistent fixtures such as file -operations. In general, 'local' should only be used when: -<ul> - <li>the setup/teardown needs to be executed by the process that will - run the tests;</li> - <li>no further teardown needs to be done if the process is killed - (i.e., no state outside the process was affected by the setup)</li> -</ul> - -<h4><a name="Lazy_generators">Lazy generators</a></h4> - -<p>Sometimes, it can be convenient not to produce the whole set of test -descriptions before the testing begins; for example, if you want to -generate a huge amount of tests that would take up too much space to -keep in memory all at once.</p> - -<p>It is fairly easy to write a generator which, each time it is called, -either produces an empty list if it is done, or otherwise produces a -list containing a single test case plus a new generator which will -produce the rest of the tests. This demonstrates the basic pattern:</p> - -<pre> lazy_test_() -> - lazy_gen(10000). - - lazy_gen(N) -> - {generator, - fun () -> - if N > 0 -> - [?_test(...) - | lazy_gen(N-1)]; - true -> - [] - end - end}.</pre> - -<p>When EUnit traverses the test representation in order to run the tests, -the new generator will not be called to produce the next test until the -previous test has been executed.</p> - -Note that it is easiest to write this kind of recursive generator using -a help function, like the <code>lazy_gen/1</code> function above. It can also be -written using a recursive fun, if you prefer to not clutter your -function namespace and are comfortable with writing that kind of code. - -<hr> -<div class="navbar"><a name="#navbar_bottom"></a><table width="100%" border="0" cellspacing="0" cellpadding="2" summary="navigation bar"><tr><td><a href="overview-summary.html" target="overviewFrame">Overview</a></td><td><a href="http://www.erlang.org/"><img src="erlang.png" align="right" border="0" alt="erlang logo"></a></td></tr></table></div> -<p><i>Generated by EDoc, Apr 22 2009, 22:37:19.</i></p> -</body> -</html> diff --git a/lib/eunit/doc/overview.edoc b/lib/eunit/doc/overview.edoc index 2583f0be25..ad449cb6fc 100644 --- a/lib/eunit/doc/overview.edoc +++ b/lib/eunit/doc/overview.edoc @@ -5,8 +5,7 @@ @title EUnit - a Lightweight Unit Testing Framework for Erlang -@author Richard Carlsson <[email protected]> - [http://user.it.uu.se/~richardc/] +@author Richard Carlsson <[email protected]> @author Micka�l R�mond <[email protected]> [http://www.process-one.net/] @copyright 2004-2007 Micka�l R�mond, Richard Carlsson diff --git a/lib/eunit/doc/packages-frame.html b/lib/eunit/doc/packages-frame.html deleted file mode 100644 index 52b45534f5..0000000000 --- a/lib/eunit/doc/packages-frame.html +++ /dev/null @@ -1,11 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> -<html> -<head> -<title>The eunit application</title> -<link rel="stylesheet" type="text/css" href="stylesheet.css" title="EDoc"> -</head> -<body bgcolor="white"> -<h2 class="indextitle">Packages</h2> -<table width="100%" border="0" summary="list of packages"></table> -</body> -</html>
\ No newline at end of file diff --git a/lib/eunit/doc/src/Makefile b/lib/eunit/doc/src/Makefile index 19be96d763..2cdc579275 100644 --- a/lib/eunit/doc/src/Makefile +++ b/lib/eunit/doc/src/Makefile @@ -146,7 +146,7 @@ debug opt: clean clean_docs: rm -rf $(HTMLDIR)/* rm -f $(MAN3DIR)/* - rm -f $(XML_CHAPTER_FILES) *.html + rm -f $(XML_REF3_FILES) $(XML_CHAPTER_FILES) *.html rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) rm -f errs core *~ diff --git a/lib/eunit/doc/src/book.xml b/lib/eunit/doc/src/book.xml index 4444b1dd7a..eb044c1a66 100644 --- a/lib/eunit/doc/src/book.xml +++ b/lib/eunit/doc/src/book.xml @@ -5,7 +5,7 @@ <header titlestyle="normal"> <copyright> <year>2008</year> - <year>2008</year> + <year>2011</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> diff --git a/lib/eunit/doc/src/notes.xml b/lib/eunit/doc/src/notes.xml index 974ba1db4e..e68330482c 100644 --- a/lib/eunit/doc/src/notes.xml +++ b/lib/eunit/doc/src/notes.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>2008</year> - <year>2008</year> + <year>2011</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -32,6 +32,118 @@ </header> <p>This document describes the changes made to the EUnit application.</p> +<section><title>Eunit 2.2.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Generate separate surefire XMLs for each test suite</p> + <p> + Previously the test cases of all test suites (=modules) + were put in one and the same surefire report XML thereby + breaking the principle of least astonishment and making + post analysis harder. Assume the following layout:</p> + <p> + src/x.erl src/y.erl test/x_tests.erl test/y_tests.erl</p> + <p> + The results for both x_tests and y_tests were written to + only one report grouped under either module x or y + (seemingly randomly).</p> + <p> + Now two reports, one for module x and one for y are + generated. (Thanks to Klas Johansson)</p> + <p> + Own Id: OTP-9465</p> + </item> + <item> + <p> + Updated to EUnit version 2.2.0</p> + <p> + New macros assertNotMatch(Guard, Expr), + assertNotEqual(Unexpected, Expr), and + assertNotException(Class, Term, Expr). </p> + <p> + The debugMsg macro now also prints the pid of the current + process.</p> + <p> + When testing all modules in a directory, tests in + Module_tests.erl are no longer executed twice.</p> + <p> + The use of regexp internally has been replaced with re. + (Thanks to Richard Carlsson)</p> + <p> + Own Id: OTP-9505</p> + </item> + <item> + <p> + Removed some never-matching clauses reported by dialyzer + Updated author e-mails and homepages Removed cvs keywords + from files Removed files that should not be checked in + (Thanks to Richard Carlsson)</p> + <p> + Own Id: OTP-9591</p> + </item> + </list> + </section> + +</section> + +<section><title>Eunit 2.1.7</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Increase depth of error messages in Eunit Surefire + reports</p> + <p> + Currently, error messages in Eunit Surefire reports are + shortened just like when written to a terminal. However, + the space limitations that constrain terminal output do + not apply here, so it's more useful to include more of + the error message. The new depth of 100 should be enough + for most cases, while protecting against runaway errors. + (Thanks to Magnus Henoch)</p> + <p> + Own Id: OTP-9220</p> + </item> + <item> + <p> + Don't let eunit_surefire report back to eunit when + stopping</p> + <p> + When eunit is terminating, a stop message is sent to all + listeners and eunit then waits for *one* result message + but previously both eunit_tty and eunit_surefire sent a + response on error. Don't send a result message from + eunit_surefire; let eunit_tty take care of all result + reporting, both positive and negative to avoid race + conditions and inconsistencies. (Thanks to Klas + Johansson)</p> + <p> + Own Id: OTP-9269</p> + </item> + </list> + </section> + +</section> + +<section><title>Eunit 2.1.6</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> Fix format_man_pages so it handles all man sections + and remove warnings/errors in various man pages. </p> + <p> + Own Id: OTP-8600</p> + </item> + </list> + </section> + +</section> + <section><title>Eunit 2.1.5</title> <section><title>Improvements and New Features</title> diff --git a/lib/eunit/doc/src/part.xml b/lib/eunit/doc/src/part.xml index e31a8d1b78..84e5aec039 100644 --- a/lib/eunit/doc/src/part.xml +++ b/lib/eunit/doc/src/part.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>2008</year> - <year>2008</year> + <year>2011</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> diff --git a/lib/eunit/doc/src/part_notes.xml b/lib/eunit/doc/src/part_notes.xml index 28644f961b..191d69b915 100644 --- a/lib/eunit/doc/src/part_notes.xml +++ b/lib/eunit/doc/src/part_notes.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>2008</year> - <year>2008</year> + <year>2011</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> diff --git a/lib/eunit/doc/src/ref_man.xml b/lib/eunit/doc/src/ref_man.xml index 02feef5e97..eb46ceda1e 100644 --- a/lib/eunit/doc/src/ref_man.xml +++ b/lib/eunit/doc/src/ref_man.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>2008</year> - <year>2008</year> + <year>2011</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> diff --git a/lib/eunit/doc/stylesheet.css b/lib/eunit/doc/stylesheet.css deleted file mode 100644 index e426a90483..0000000000 --- a/lib/eunit/doc/stylesheet.css +++ /dev/null @@ -1,55 +0,0 @@ -/* standard EDoc style sheet */ -body { - font-family: Verdana, Arial, Helvetica, sans-serif; - margin-left: .25in; - margin-right: .2in; - margin-top: 0.2in; - margin-bottom: 0.2in; - color: #000000; - background-color: #ffffff; -} -h1,h2 { - margin-left: -0.2in; -} -div.navbar { - background-color: #add8e6; - padding: 0.2em; -} -h2.indextitle { - padding: 0.4em; - background-color: #add8e6; -} -h3.function,h3.typedecl { - background-color: #add8e6; - padding-left: 1em; -} -div.spec { - margin-left: 2em; - background-color: #eeeeee; -} -a.module,a.package { - text-decoration:none -} -a.module:hover,a.package:hover { - background-color: #eeeeee; -} -ul.definitions { - list-style-type: none; -} -ul.index { - list-style-type: none; - background-color: #eeeeee; -} - -/* - * Minor style tweaks - */ -ul { - list-style-type: square; -} -table { - border-collapse: collapse; -} -td { - padding: 3 -} diff --git a/lib/eunit/examples/Makefile b/lib/eunit/examples/Makefile index d1b5bac224..48ec2ebf2b 100644 --- a/lib/eunit/examples/Makefile +++ b/lib/eunit/examples/Makefile @@ -13,8 +13,6 @@ # Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings # AB. All Rights Reserved.'' # -# $Id$ -# include $(ERL_TOP)/make/target.mk include $(ERL_TOP)/make/$(TARGET)/otp.mk diff --git a/lib/eunit/include/eunit.hrl b/lib/eunit/include/eunit.hrl index 82ba982f03..db68d8ae60 100644 --- a/lib/eunit/include/eunit.hrl +++ b/lib/eunit/include/eunit.hrl @@ -13,8 +13,6 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id: eunit.hrl 337 2009-03-09 08:38:28Z rcarlsson $ -%% %% Copyright (C) 2004-2006 Micka�l R�mond, Richard Carlsson %% Including this file turns on testing and defines TEST, unless NOTEST @@ -39,6 +37,7 @@ -ifndef(EUNIT_HRL). -define(EUNIT_HRL, true). + %% allow defining TEST to override NOTEST -ifdef(TEST). -undef(NOTEST). @@ -164,7 +163,7 @@ %% 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). +-define(assertMatch(Guard, Expr), ok). -else. -define(assertMatch(Guard, Expr), ((fun () -> @@ -174,17 +173,37 @@ [{module, ?MODULE}, {line, ?LINE}, {expression, (??Expr)}, - {expected, (??Guard)}, + {pattern, (??Guard)}, {value, __V}]}) 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), + ((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. +-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). +-define(assertEqual(Expect, Expr), ok). -else. -define(assertEqual(Expect, Expr), ((fun (__X) -> @@ -201,9 +220,29 @@ -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), + ((fun (__X) -> + case (Expr) of + __X -> .erlang:error({assertNotEqual_failed, + [{module, ?MODULE}, + {line, ?LINE}, + {expression, (??Expr)}, + {value, __X}]}); + _ -> ok + end + end)(Unexpected))). +-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). +-define(assertException(Class, Term, Expr), ok). -else. -define(assertException(Class, Term, Expr), ((fun () -> @@ -212,7 +251,7 @@ [{module, ?MODULE}, {line, ?LINE}, {expression, (??Expr)}, - {expected, + {pattern, "{ "++(??Class)++" , "++(??Term) ++" , [...] }"}, {unexpected_success, __V}]}) @@ -223,7 +262,7 @@ [{module, ?MODULE}, {line, ?LINE}, {expression, (??Expr)}, - {expected, + {pattern, "{ "++(??Class)++" , "++(??Term) ++" , [...] }"}, {unexpected_exception, @@ -243,6 +282,43 @@ -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. +-define(_assertNotException(Class, Term, Expr), + ?_test(?assertNotException(Class, Term, Expr))). + %% Macros for running operating system commands. (Note that these %% require EUnit to be present at runtime, or at least eunit_lib.) @@ -267,7 +343,7 @@ %% these are only used for testing; they always return 'ok' on success, %% and have no effect if debugging/testing is turned off -ifdef(NOASSERT). --define(assertCmdStatus(N, Cmd),ok). +-define(assertCmdStatus(N, Cmd), ok). -else. -define(assertCmdStatus(N, Cmd), ((fun () -> @@ -285,7 +361,7 @@ -define(assertCmd(Cmd), ?assertCmdStatus(0, Cmd)). -ifdef(NOASSERT). --define(assertCmdOutput(T, Cmd),ok). +-define(assertCmdOutput(T, Cmd), ok). -else. -define(assertCmdOutput(T, Cmd), ((fun () -> @@ -313,11 +389,12 @@ -define(debugHere, ok). -define(debugFmt(S, As), ok). -define(debugVal(E), (E)). --define(debugTime(S,E), (E)). +-define(debugTime(S, E), (E)). -else. -define(debugMsg(S), (begin - .io:fwrite(user, <<"~s:~w: ~s\n">>, [?FILE, ?LINE, S]), + .io:fwrite(user, <<"~s:~w:~w: ~s\n">>, + [?FILE, ?LINE, self(), S]), ok end)). -define(debugHere, (?debugMsg("<-"))). @@ -327,7 +404,7 @@ ?debugFmt(<<"~s = ~P">>, [(??E), __V, 15]), __V end)(E))). --define(debugTime(S,E), +-define(debugTime(S, E), ((fun () -> {__T0, _} = statistics(wall_clock), __V = (E), @@ -337,4 +414,5 @@ end)())). -endif. + -endif. % EUNIT_HRL diff --git a/lib/eunit/src/eunit.app.src b/lib/eunit/src/eunit.app.src index 4fd76588c3..5e16dfa2ce 100644 --- a/lib/eunit/src/eunit.app.src +++ b/lib/eunit/src/eunit.app.src @@ -5,17 +5,17 @@ {vsn, "%VSN%"}, {modules, [eunit, eunit_autoexport, - eunit_striptests, - eunit_server, + eunit_data, + eunit_lib, + eunit_listener, eunit_proc, eunit_serial, + eunit_server, + eunit_striptests, + eunit_surefire, eunit_test, eunit_tests, - eunit_lib, - eunit_listener, - eunit_data, - eunit_tty, - eunit_surefire]}, + eunit_tty]}, {registered,[]}, - {applications, [stdlib]}, + {applications, [kernel,stdlib]}, {env, []}]}. diff --git a/lib/eunit/src/eunit.erl b/lib/eunit/src/eunit.erl index 59084a52fb..95857e83c8 100644 --- a/lib/eunit/src/eunit.erl +++ b/lib/eunit/src/eunit.erl @@ -13,13 +13,10 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id: eunit.erl 339 2009-04-05 14:10:47Z rcarlsson $ -%% %% @copyright 2004-2009 Micka�l R�mond, Richard Carlsson %% @author Micka�l R�mond <[email protected]> %% [http://www.process-one.net/] -%% @author Richard Carlsson <[email protected]> -%% [http://user.it.uu.se/~richardc/] +%% @author Richard Carlsson <[email protected]> %% @version {@version}, {@date} {@time} %% @doc This module is the main EUnit user interface. @@ -157,6 +154,7 @@ test_run(Reference, Listeners) -> receive {done, Reference} -> cast(Listeners, {stop, Reference, self()}), + wait_until_listeners_have_terminated(Listeners), receive {result, Reference, Result} -> Result @@ -169,6 +167,15 @@ cast([P | Ps], Msg) -> cast([], _Msg) -> ok. +wait_until_listeners_have_terminated([P | Ps]) -> + MRef = erlang:monitor(process, P), + receive + {'DOWN', MRef, process, P, _} -> + wait_until_listeners_have_terminated(Ps) + end; +wait_until_listeners_have_terminated([]) -> + ok. + %% TODO: functions that run tests on a given node, not a given server %% TODO: maybe some functions could check for a globally registered server? %% TODO: some synchronous but completely quiet interface function diff --git a/lib/eunit/src/eunit_autoexport.erl b/lib/eunit/src/eunit_autoexport.erl index 7b153c1194..099bcb222e 100644 --- a/lib/eunit/src/eunit_autoexport.erl +++ b/lib/eunit/src/eunit_autoexport.erl @@ -13,9 +13,7 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id: eunit_autoexport.erl 329 2009-03-01 11:23:32Z rcarlsson $ -%% -%% @author Richard Carlsson <[email protected]> +%% @author Richard Carlsson <[email protected]> %% @copyright 2006 Richard Carlsson %% @private %% @see eunit diff --git a/lib/eunit/src/eunit_data.erl b/lib/eunit/src/eunit_data.erl index 0543b6c543..392d378a0e 100644 --- a/lib/eunit/src/eunit_data.erl +++ b/lib/eunit/src/eunit_data.erl @@ -13,9 +13,7 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id$ -%% -%% @author Richard Carlsson <[email protected]> +%% @author Richard Carlsson <[email protected]> %% @copyright 2006 Richard Carlsson %% @private %% @see eunit @@ -146,8 +144,10 @@ iter_next(I = #iter{next = [T | Ts]}) -> iter_prev(#iter{prev = []}) -> none; -iter_prev(#iter{prev = [T | Ts], next = Next, pos = Pos} = I) -> - {T, I#iter{prev = Ts, next = [T | Next], pos = Pos - 1}}. +iter_prev(#iter{prev = [T | Ts]} = I) -> + {T, I#iter{prev = Ts, + next = [T | I#iter.next], + pos = I#iter.pos - 1}}. %% --------------------------------------------------------------------- @@ -363,7 +363,8 @@ parse({file, F} = T) when is_list(F) -> parse({dir, D}=T) when is_list(D) -> case eunit_lib:is_string(D) of true -> - {data, {"directory \"" ++ D ++ "\"", get_directory_modules(D)}}; + {data, {"directory \"" ++ D ++ "\"", + get_directory_module_tests(D)}}; false -> bad_test(T) end; @@ -385,10 +386,10 @@ parse({S, T1} = T) when is_list(S) -> end; parse({S, T1}) when is_binary(S) -> group(#group{tests = T1, desc = S}); -parse(T) when tuple_size(T) > 2, is_list(element(1, T)) -> +parse(T) when is_tuple(T), size(T) > 2, is_list(element(1, T)) -> [S | Es] = tuple_to_list(T), parse({S, list_to_tuple(Es)}); -parse(T) when tuple_size(T) > 2, is_binary(element(1, T)) -> +parse(T) when is_tuple(T), size(T) > 2, is_binary(element(1, T)) -> [S | Es] = tuple_to_list(T), parse({S, list_to_tuple(Es)}); parse(M) when is_atom(M) -> @@ -596,7 +597,7 @@ testfuns(Es, M, TestSuffix, GeneratorSuffix) -> %% --------------------------------------------------------------------- -%% Getting a test set from a file +%% Getting a test set from a file (text file or object file) %% @throws {file_read_error, {Reason::atom(), Message::string(), %% fileName()}} @@ -625,17 +626,23 @@ get_file_tests(F) -> is_module_filename(F) -> filename:extension(F) =:= code:objfile_extension(). +objfile_test({M, File}) -> + {setup, + fun () -> + %% TODO: better error/stacktrace for this internal fun + code:purge(M), + {module,M} = code:load_abs(filename:rootname(File)), + ok + end, + {module, M}}; objfile_test(File) -> + objfile_test({objfile_module(File), File}). + +objfile_module(File) -> try - {module, M} = lists:keyfind(module, 1, beam_lib:info(File)), - {setup, - fun () -> - %% TODO: better error/stacktrace for this internal fun - code:purge(M), - {module,M} = code:load_abs(filename:rootname(File)), - ok - end, - {module, M}} + {value, {module, M}} = lists:keysearch(module, 1, + beam_lib:info(File)), + M catch _:_ -> throw({file_read_error, @@ -644,15 +651,34 @@ objfile_test(File) -> %% --------------------------------------------------------------------- -%% Getting a list of module names from object files in a directory - -%% @throws {file_read_error, {Reason::atom(), Message::string(), -%% fileName()}} +%% Getting a set of module tests from the object files in a directory + +%% @throws {file_read_error, +%% {Reason::atom(), Message::string(), fileName()}} + +get_directory_module_tests(D) -> + Ms = get_directory_modules(D), + %% for all 'm' in the set, remove 'm_tests' if present + F = fun ({M,_}, S) -> + Name = atom_to_list(M), + case lists:suffix(?DEFAULT_TESTMODULE_SUFFIX, Name) of + false -> + Name1 = Name ++ ?DEFAULT_TESTMODULE_SUFFIX, + M1 = list_to_atom(Name1), + dict:erase(M1, S); + true -> + S + end + end, + [objfile_test(Obj) + || Obj <- dict:to_list(lists:foldl(F, dict:from_list(Ms), Ms))]. %% TODO: handle packages (recursive search for files) - get_directory_modules(D) -> - [objfile_test(filename:join(D, F)) + [begin + F1 = filename:join(D, F), + {objfile_module(F1), F1} + end || F <- eunit_lib:list_dir(D), is_module_filename(F)]. diff --git a/lib/eunit/src/eunit_internal.hrl b/lib/eunit/src/eunit_internal.hrl index 8d0ac30bd7..92694ec39b 100644 --- a/lib/eunit/src/eunit_internal.hrl +++ b/lib/eunit/src/eunit_internal.hrl @@ -1,11 +1,7 @@ %% ------------------------------------------------------------------- %% File: eunit_internal.hrl %% -%% $Id: eunit_internal.hrl 329 2009-03-01 11:23:32Z rcarlsson $ -%% -%% @author Richard Carlsson <[email protected]> -%% @copyright 2006 Richard Carlsson -%% @doc +%% Copyright (C) 2006 Richard Carlsson <[email protected]> -define(SERVER, eunit_server). -define(DEFAULT_TEST_SUFFIX, "_test"). diff --git a/lib/eunit/src/eunit_lib.erl b/lib/eunit/src/eunit_lib.erl index 4751f1094a..1c41e229c5 100644 --- a/lib/eunit/src/eunit_lib.erl +++ b/lib/eunit/src/eunit_lib.erl @@ -13,13 +13,10 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id: eunit_lib.erl 339 2009-04-05 14:10:47Z rcarlsson $ -%% %% @copyright 2004-2007 Micka�l R�mond, Richard Carlsson %% @author Micka�l R�mond <[email protected]> %% [http://www.process-one.net/] -%% @author Richard Carlsson <[email protected]> -%% [http://user.it.uu.se/~richardc/] +%% @author Richard Carlsson <[email protected]> %% @private %% @see eunit %% @doc Utility functions for eunit @@ -33,7 +30,7 @@ -export([dlist_next/1, uniq/1, fun_parent/1, is_string/1, command/1, command/2, command/3, trie_new/0, trie_store/2, trie_match/2, split_node/1, consult_file/1, list_dir/1, format_exit_term/1, - format_exception/1, format_error/1]). + format_exception/1, format_exception/2, format_error/1]). %% Type definitions for describing exceptions @@ -55,21 +52,23 @@ %% --------------------------------------------------------------------- %% Formatting of error descriptors +format_exception(Exception) -> + format_exception(Exception, 20). -format_exception({Class,Term,Trace}) +format_exception({Class,Term,Trace}, Depth) when is_atom(Class), is_list(Trace) -> case is_stacktrace(Trace) of true -> io_lib:format("~w:~P\n~s", - [Class, Term, 20, format_stacktrace(Trace)]); + [Class, Term, Depth, format_stacktrace(Trace)]); false -> - format_term(Term) + format_term(Term, Depth) end; -format_exception(Term) -> - format_term(Term). +format_exception(Term, Depth) -> + format_term(Term, Depth). -format_term(Term) -> - io_lib:format("~P\n", [Term, 15]). +format_term(Term, Depth) -> + io_lib:format("~P\n", [Term, Depth]). format_exit_term(Term) -> {Reason, Trace} = analyze_exit_term(Term), diff --git a/lib/eunit/src/eunit_listener.erl b/lib/eunit/src/eunit_listener.erl index 20faecbf01..ecaac424a2 100644 --- a/lib/eunit/src/eunit_listener.erl +++ b/lib/eunit/src/eunit_listener.erl @@ -13,9 +13,7 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id$ -%% -%% @author Richard Carlsson <[email protected]> +%% @author Richard Carlsson <[email protected]> %% @copyright 2009 Richard Carlsson %% @private %% @see eunit diff --git a/lib/eunit/src/eunit_proc.erl b/lib/eunit/src/eunit_proc.erl index e2d51d8bd5..ec7d93fd48 100644 --- a/lib/eunit/src/eunit_proc.erl +++ b/lib/eunit/src/eunit_proc.erl @@ -13,9 +13,7 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id$ -%% -%% @author Richard Carlsson <[email protected]> +%% @author Richard Carlsson <[email protected]> %% @copyright 2006 Richard Carlsson %% @private %% @see eunit diff --git a/lib/eunit/src/eunit_serial.erl b/lib/eunit/src/eunit_serial.erl index d9ccae86f9..80e79116e3 100644 --- a/lib/eunit/src/eunit_serial.erl +++ b/lib/eunit/src/eunit_serial.erl @@ -13,9 +13,7 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id$ -%% -%% @author Richard Carlsson <[email protected]> +%% @author Richard Carlsson <[email protected]> %% @copyright 2006 Richard Carlsson %% @private %% @see eunit diff --git a/lib/eunit/src/eunit_server.erl b/lib/eunit/src/eunit_server.erl index bf1bb9bcef..2002930abb 100644 --- a/lib/eunit/src/eunit_server.erl +++ b/lib/eunit/src/eunit_server.erl @@ -13,9 +13,7 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id: eunit_server.erl 267 2008-10-19 18:48:03Z rcarlsson $ -%% -%% @author Richard Carlsson <[email protected]> +%% @author Richard Carlsson <[email protected]> %% @copyright 2006 Richard Carlsson %% @private %% @see eunit @@ -59,8 +57,9 @@ watch(Server, Module, Opts) when is_atom(Module) -> watch_path(Server, Path, Opts) -> command(Server, {watch, {path, filename:flatten(Path)}, Opts}). +%% note that the user must use $ at the end to match whole paths only watch_regexp(Server, Regex, Opts) -> - case regexp:parse(Regex) of + case re:compile(Regex,[anchored]) of {ok, R} -> command(Server, {watch, {regexp, R}, Opts}); {error, _}=Error -> @@ -278,8 +277,8 @@ is_watched(Path, St) -> match_any(sets:to_list(St#state.regexps), Path). match_any([R | Rs], Str) -> - case regexp:first_match(Str, R) of - {match, _, _} -> true; + case re:run(Str, R, [{capture,none}]) of + match -> true; _ -> match_any(Rs, Str) end; match_any([], _Str) -> false. diff --git a/lib/eunit/src/eunit_striptests.erl b/lib/eunit/src/eunit_striptests.erl index 606e44b286..c6ade389ba 100644 --- a/lib/eunit/src/eunit_striptests.erl +++ b/lib/eunit/src/eunit_striptests.erl @@ -13,10 +13,8 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id: eunit_striptests.erl 329 2009-03-01 11:23:32Z rcarlsson $ -%% -%% @author Richard Carlsson <[email protected]> -%% @author Eric Merritt <[email protected]> +%% @author Richard Carlsson <[email protected]> +%% @author Eric Merritt <[email protected]> %% @copyright 2006 Richard Carlsson, Eric Merritt %% @private %% @see eunit diff --git a/lib/eunit/src/eunit_surefire.erl b/lib/eunit/src/eunit_surefire.erl index aeda31d251..2a6cbca14d 100644 --- a/lib/eunit/src/eunit_surefire.erl +++ b/lib/eunit/src/eunit_surefire.erl @@ -13,9 +13,7 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id: $ -%% -%% @author Micka�l R�mond <[email protected]> +%% @author Micka�l R�mond <[email protected]> %% @copyright 2009 Micka�l R�mond, Paul Guyot %% @see eunit %% @doc Surefire reports for EUnit (Format used by Maven and Atlassian @@ -58,12 +56,13 @@ { name :: chars(), description :: chars(), - result :: ok | {failed, tuple()} | {aborted, tuple()} | {skipped, tuple()}, + result :: ok | {failed, tuple()} | {aborted, tuple()} | {skipped, term()}, time :: integer(), output :: binary() }). -record(testsuite, { + id = 0 :: integer(), name = <<>> :: binary(), time = 0 :: integer(), output = <<>> :: binary(), @@ -76,7 +75,7 @@ -record(state, {verbose = false, indent = 0, xmldir = ".", - testsuite = #testsuite{} + testsuites = [] :: [#testsuite{}] }). start() -> @@ -89,61 +88,60 @@ init(Options) -> XMLDir = proplists:get_value(dir, Options, ?XMLDIR), St = #state{verbose = proplists:get_bool(verbose, Options), xmldir = XMLDir, - testsuite = #testsuite{}}, + testsuites = []}, receive {start, _Reference} -> St end. terminate({ok, _Data}, St) -> - TestSuite = St#state.testsuite, + TestSuites = St#state.testsuites, XmlDir = St#state.xmldir, - write_report(TestSuite, XmlDir), + write_reports(TestSuites, XmlDir), ok; -terminate({error, Reason}, _St) -> - io:fwrite("Internal error: ~P.\n", [Reason, 25]), - sync_end(error). - -sync_end(Result) -> - receive - {stop, Reference, ReplyTo} -> - ReplyTo ! {result, Reference, Result}, - ok - end. - -handle_begin(group, Data, St) -> +terminate({error, _Reason}, _St) -> + %% Don't report any errors here, since eunit_tty takes care of that. + %% Just terminate. + ok. + +handle_begin(Kind, Data, St) when Kind == group; Kind == test -> + %% Run this code both for groups and tests; test is a bit + %% surprising: This is a workaround for the fact that we don't get + %% a group (handle_begin(group, ...) for testsuites (modules) + %% which only have one test case. In that case we get a test case + %% with an id comprised of just one integer - the group id. NewId = proplists:get_value(id, Data), case NewId of [] -> St; - [_GroupId] -> + [GroupId] -> Desc = proplists:get_value(desc, Data), - TestSuite = St#state.testsuite, - NewTestSuite = TestSuite#testsuite{name = Desc}, - St#state{testsuite=NewTestSuite}; + TestSuite = #testsuite{id = GroupId, name = Desc}, + St#state{testsuites=store_suite(TestSuite, St#state.testsuites)}; %% Surefire format is not hierarchic: Ignore subgroups: _ -> St - end; -handle_begin(test, _Data, St) -> - St. + end. handle_end(group, Data, St) -> %% Retrieve existing test suite: case proplists:get_value(id, Data) of [] -> St; - [_GroupId|_] -> - TestSuite = St#state.testsuite, + [GroupId|_] -> + TestSuites = St#state.testsuites, + TestSuite = lookup_suite_by_group_id(GroupId, TestSuites), %% Update TestSuite data: Time = proplists:get_value(time, Data), Output = proplists:get_value(output, Data), NewTestSuite = TestSuite#testsuite{ time = Time, output = Output }, - St#state{testsuite=NewTestSuite} + St#state{testsuites=store_suite(NewTestSuite, TestSuites)} end; handle_end(test, Data, St) -> %% Retrieve existing test suite: - TestSuite = St#state.testsuite, + [GroupId|_] = proplists:get_value(id, Data), + TestSuites = St#state.testsuites, + TestSuite = lookup_suite_by_group_id(GroupId, TestSuites), %% Create test case: Name = format_name(proplists:get_value(source, Data), @@ -155,7 +153,7 @@ handle_end(test, Data, St) -> TestCase = #testcase{name = Name, description = Desc, time = Time,output = Output}, NewTestSuite = add_testcase_to_testsuite(Result, TestCase, TestSuite), - St#state{testsuite=NewTestSuite}. + St#state{testsuites=store_suite(NewTestSuite, TestSuites)}. %% Cancel group does not give information on the individual cancelled test case %% We ignore this event @@ -163,7 +161,9 @@ handle_cancel(group, _Data, St) -> St; handle_cancel(test, Data, St) -> %% Retrieve existing test suite: - TestSuite = St#state.testsuite, + [GroupId|_] = proplists:get_value(id, Data), + TestSuites = St#state.testsuites, + TestSuite = lookup_suite_by_group_id(GroupId, TestSuites), %% Create test case: Name = format_name(proplists:get_value(source, Data), @@ -177,7 +177,7 @@ handle_cancel(test, Data, St) -> NewTestSuite = TestSuite#testsuite{ skipped = TestSuite#testsuite.skipped+1, testcases=[TestCase|TestSuite#testsuite.testcases] }, - St#state{testsuite=NewTestSuite}. + St#state{testsuites=store_suite(NewTestSuite, TestSuites)}. format_name({Module, Function, Arity}, Line) -> lists:flatten([atom_to_list(Module), ":", atom_to_list(Function), "/", @@ -189,6 +189,12 @@ format_desc(Desc) when is_binary(Desc) -> format_desc(Desc) when is_list(Desc) -> Desc. +lookup_suite_by_group_id(GroupId, TestSuites) -> + #testsuite{} = lists:keyfind(GroupId, #testsuite.id, TestSuites). + +store_suite(#testsuite{id=GroupId} = TestSuite, TestSuites) -> + lists:keystore(GroupId, #testsuite.id, TestSuites, TestSuite). + %% Add testcase to testsuite depending on the result of the test. add_testcase_to_testsuite(ok, TestCaseTmp, TestSuite) -> TestCase = TestCaseTmp#testcase{ result = ok }, @@ -220,6 +226,10 @@ add_testcase_to_testsuite({error, Exception}, TestCaseTmp, TestSuite) -> %% Write a report to the XML directory. %% This function opens the report file, calls write_report_to/2 and closes the file. %% ---------------------------------------------------------------------------- +write_reports(TestSuites, XmlDir) -> + lists:foreach(fun(TestSuite) -> write_report(TestSuite, XmlDir) end, + TestSuites). + write_report(#testsuite{name = Name} = TestSuite, XmlDir) -> Filename = filename:join(XmlDir, lists:flatten(["TEST-", escape_suitename(Name)], ".xml")), case file:open(Filename, [write, raw]) of @@ -299,7 +309,6 @@ write_testcase( output = Output}, FileDescriptor) -> DescriptionAttr = case Description of - <<>> -> []; [] -> []; _ -> [<<" description=\"">>, escape_attr(Description), <<"\"">>] end, @@ -308,7 +317,6 @@ write_testcase( <<"\" name=\"">>, escape_attr(Name), <<"\"">>, DescriptionAttr], ContentAndEndTag = case {Result, Output} of - {ok, []} -> [<<"/>">>, ?NEWLINE]; {ok, <<>>} -> [<<"/>">>, ?NEWLINE]; _ -> [<<">">>, ?NEWLINE, format_testcase_result(Result), format_testcase_output(Output), ?INDENT, <<"</testcase>">>, ?NEWLINE] end, @@ -323,7 +331,7 @@ write_testcase( format_testcase_result(ok) -> [<<>>]; format_testcase_result({failed, {error, {Type, _}, _} = Exception}) when is_atom(Type) -> [?INDENT, ?INDENT, <<"<failure type=\"">>, escape_attr(atom_to_list(Type)), <<"\">">>, ?NEWLINE, - <<"::">>, escape_text(eunit_lib:format_exception(Exception)), + <<"::">>, escape_text(eunit_lib:format_exception(Exception, 100)), ?INDENT, ?INDENT, <<"</failure>">>, ?NEWLINE]; format_testcase_result({failed, Term}) -> [?INDENT, ?INDENT, <<"<failure type=\"unknown\">">>, ?NEWLINE, @@ -331,7 +339,7 @@ format_testcase_result({failed, Term}) -> ?INDENT, ?INDENT, <<"</failure>">>, ?NEWLINE]; format_testcase_result({aborted, {Class, _Term, _Trace} = Exception}) when is_atom(Class) -> [?INDENT, ?INDENT, <<"<error type=\"">>, escape_attr(atom_to_list(Class)), <<"\">">>, ?NEWLINE, - <<"::">>, escape_text(eunit_lib:format_exception(Exception)), + <<"::">>, escape_text(eunit_lib:format_exception(Exception, 100)), ?INDENT, ?INDENT, <<"</error>">>, ?NEWLINE]; format_testcase_result({aborted, Term}) -> [?INDENT, ?INDENT, <<"<error type=\"unknown\">">>, ?NEWLINE, @@ -357,7 +365,6 @@ format_testcase_result({skipped, Term}) -> %% Empty output is simply the empty string. %% Other output is inside a <system-out> xml tag. %% ---------------------------------------------------------------------------- -format_testcase_output([]) -> []; format_testcase_output(Output) -> [?INDENT, ?INDENT, <<"<system-out>">>, escape_text(Output), ?NEWLINE, ?INDENT, ?INDENT, <<"</system-out>">>, ?NEWLINE]. @@ -375,8 +382,6 @@ format_time_s([Digit1, Digit2, Digit3 | Tail]) -> [lists:reverse(Tail), $., Digi %% Escape a suite's name to generate the filename. %% Remark: we might overwrite another testsuite's file. %% ---------------------------------------------------------------------------- -escape_suitename([Head | _T] = List) when is_list(Head) -> - escape_suitename(lists:flatten(List)); escape_suitename(Binary) when is_binary(Binary) -> escape_suitename(binary_to_list(Binary)); escape_suitename("module '" ++ String) -> @@ -384,7 +389,6 @@ escape_suitename("module '" ++ String) -> escape_suitename(String) -> escape_suitename(String, []). -escape_suitename(Binary, Acc) when is_binary(Binary) -> escape_suitename(binary_to_list(Binary), Acc); escape_suitename([], Acc) -> lists:reverse(Acc); escape_suitename([$ | Tail], Acc) -> escape_suitename(Tail, [$_ | Acc]); escape_suitename([$' | Tail], Acc) -> escape_suitename(Tail, Acc); diff --git a/lib/eunit/src/eunit_test.erl b/lib/eunit/src/eunit_test.erl index d322c4b420..bca49ae626 100644 --- a/lib/eunit/src/eunit_test.erl +++ b/lib/eunit/src/eunit_test.erl @@ -13,9 +13,7 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id: eunit_test.erl 336 2009-03-06 14:43:21Z rcarlsson $ -%% -%% @author Richard Carlsson <[email protected]> +%% @author Richard Carlsson <[email protected]> %% @copyright 2006 Richard Carlsson %% @private %% @see eunit @@ -131,12 +129,27 @@ macro_test_() -> [{module,_}, {line,_}, {expression,_}, - {expected,"[ _ ]"}, + {pattern,"[ _ ]"}, {value,[]}]}, _}} = run_testfun(F) end), ?_test(begin + {?LINE, F} = ?_assertNotMatch(ok, error), + {ok, ok} = run_testfun(F) + end), + ?_test(begin + {?LINE, F} = ?_assertNotMatch([_], [42]), + {error,{error,{assertNotMatch_failed, + [{module,_}, + {line,_}, + {expression,_}, + {pattern,"[ _ ]"}, + {value,[42]}]}, + _}} + = run_testfun(F) + end), + ?_test(begin {?LINE, F} = ?_assertEqual(ok, ok), {ok, ok} = run_testfun(F) end), @@ -152,6 +165,20 @@ macro_test_() -> = run_testfun(F) end), ?_test(begin + {?LINE, F} = ?_assertNotEqual(1, 0), + {ok, ok} = run_testfun(F) + end), + ?_test(begin + {?LINE, F} = ?_assertNotEqual(2, 1+1), + {error,{error,{assertNotEqual_failed, + [{module,_}, + {line,_}, + {expression,_}, + {value,2}]}, + _}} + = run_testfun(F) + end), + ?_test(begin {?LINE, F} = ?_assertException(error, badarith, erlang:error(badarith)), {ok, ok} = run_testfun(F) @@ -162,7 +189,7 @@ macro_test_() -> [{module,_}, {line,_}, {expression,_}, - {expected,_}, + {pattern,_}, {unexpected_success,ok}]}, _}} = run_testfun(F) @@ -174,15 +201,48 @@ macro_test_() -> [{module,_}, {line,_}, {expression,_}, - {expected,_}, + {pattern,_}, + {unexpected_exception, + {error,badarith,_}}]}, + _}} + = run_testfun(F) + end), + ?_test(begin + {?LINE, F} = ?_assertError(badarith, + erlang:error(badarith)), + {ok, ok} = run_testfun(F) + end), + ?_test(begin + {?LINE, F} = ?_assertExit(normal, exit(normal)), + {ok, ok} = run_testfun(F) + end), + ?_test(begin + {?LINE, F} = ?_assertThrow(foo, throw(foo)), + {ok, ok} = run_testfun(F) + end), + ?_test(begin + {?LINE, F} = ?_assertNotException(error, badarith, 42), + {ok, ok} = run_testfun(F) + end), + ?_test(begin + {?LINE, F} = ?_assertNotException(error, badarith, + erlang:error(badarg)), + {ok, ok} = run_testfun(F) + end), + ?_test(begin + {?LINE, F} = ?_assertNotException(error, badarith, + erlang:error(badarith)), + {error,{error,{assertNotException_failed, + [{module,_}, + {line,_}, + {expression,_}, + {pattern,_}, {unexpected_exception, {error,badarith,_}}]}, _}} = run_testfun(F) end) ]}. - -under_eunit_test() -> ?assert(?UNDER_EUNIT). -endif. diff --git a/lib/eunit/src/eunit_tests.erl b/lib/eunit/src/eunit_tests.erl index 37c0b4d6ae..47ea0aaf46 100644 --- a/lib/eunit/src/eunit_tests.erl +++ b/lib/eunit/src/eunit_tests.erl @@ -13,9 +13,7 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id: eunit_tests.erl 238 2007-11-15 10:23:54Z mremond $ -%% -%% @author Richard Carlsson <[email protected]> +%% @author Richard Carlsson <[email protected]> %% @copyright 2007 Richard Carlsson %% @private %% @see eunit @@ -26,17 +24,17 @@ -include("eunit.hrl"). -ifdef(TEST). -%% Cause all the other modules to be tested as well as this one. -full_test_() -> - %%{application, eunit}. % this currently causes a loop - %% We use the below until loop detection is implemented - [eunit_autoexport, - eunit_striptests, - eunit_server, - eunit_proc, - eunit_serial, - eunit_test, - eunit_lib, - eunit_data, - eunit_tty]. +id(X) -> X. % for suppressing compiler warnings -endif. + +under_eunit_test() -> ?assert(?UNDER_EUNIT). + +let_test() -> ?assertEqual(42, ?LET(X, 17, X+25)). + +if_test_() -> + [?_assertEqual(17, ?IF(id(1) > 0, 17, 42)), + ?_assertEqual(42, ?IF(id(1) < 0, 17, 42))]. + +matches_test_() -> + [?_assert(?MATCHES("hel"++_, "hello")), + ?_assertNot(?MATCHES("hal"++_, "hello"))]. diff --git a/lib/eunit/src/eunit_tty.erl b/lib/eunit/src/eunit_tty.erl index 5fe0140559..e3e7b710b2 100644 --- a/lib/eunit/src/eunit_tty.erl +++ b/lib/eunit/src/eunit_tty.erl @@ -13,9 +13,7 @@ %% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 %% USA %% -%% $Id: eunit_tty.erl 330 2009-03-01 16:28:02Z rcarlsson $ -%% -%% @author Richard Carlsson <[email protected]> +%% @author Richard Carlsson <[email protected]> %% @copyright 2006-2009 Richard Carlsson %% @private %% @see eunit diff --git a/lib/eunit/test/Makefile b/lib/eunit/test/Makefile index 74d485d1cc..a2d276f619 100644 --- a/lib/eunit/test/Makefile +++ b/lib/eunit/test/Makefile @@ -75,7 +75,7 @@ release_spec: opt release_tests_spec: make_emakefile $(INSTALL_DIR) $(RELSYSDIR) - $(INSTALL_DATA) eunit.dynspec $(EMAKEFILE) \ + $(INSTALL_DATA) eunit.spec $(EMAKEFILE) \ $(COVERFILE) $(ERL_FILES) \ $(RELSYSDIR) diff --git a/lib/eunit/test/eunit.cover b/lib/eunit/test/eunit.cover index d1eaf770b6..00c09127a8 100644 --- a/lib/eunit/test/eunit.cover +++ b/lib/eunit/test/eunit.cover @@ -1,3 +1,5 @@ +{incl_app,eunit,details}. + %% -*- erlang -*- -{exclude,[eunit_test]}. +{excl_mods,eunit,[eunit_test]}. diff --git a/lib/eunit/test/eunit.dynspec b/lib/eunit/test/eunit.dynspec deleted file mode 100644 index c1d345ac14..0000000000 --- a/lib/eunit/test/eunit.dynspec +++ /dev/null @@ -1,6 +0,0 @@ -%% -*- erlang -*- -%% You can test this file using this command. -%% file:script("eunit.dynspec", [{'Os',"Unix"}]). - -[]. - diff --git a/lib/eunit/test/eunit.spec b/lib/eunit/test/eunit.spec new file mode 100644 index 0000000000..2db7731a7e --- /dev/null +++ b/lib/eunit/test/eunit.spec @@ -0,0 +1,3 @@ +%% -*- erlang -*- +{suites,"../eunit_test",all}. + diff --git a/lib/eunit/test/eunit_SUITE.erl b/lib/eunit/test/eunit_SUITE.erl index 4ebcec6f5d..47c2435d63 100644 --- a/lib/eunit/test/eunit_SUITE.erl +++ b/lib/eunit/test/eunit_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. %% %% 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 @@ -18,13 +18,32 @@ %% -module(eunit_SUITE). --export([all/1,eunit_test/1]). +-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, + init_per_group/2,end_per_group/2,eunit_test/1]). --include("test_server.hrl"). +-include_lib("common_test/include/ct.hrl"). -all(suite) -> +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> [eunit_test]. +groups() -> + []. + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + + eunit_test(Config) when is_list(Config) -> ok = file:set_cwd(code:lib_dir(eunit)), ok = eunit:test(eunit). diff --git a/lib/eunit/vsn.mk b/lib/eunit/vsn.mk index 3bfa9c8000..b0a77a225b 100644 --- a/lib/eunit/vsn.mk +++ b/lib/eunit/vsn.mk @@ -1 +1 @@ -EUNIT_VSN = 2.1.5 +EUNIT_VSN = 2.2.1 |