diff doc/interpreter/testfun.txi @ 5582:6bf56668b01a

[project @ 2005-12-15 01:08:20 by jwe]
author jwe
date Thu, 15 Dec 2005 01:10:05 +0000
parents
children a25173d58101
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/interpreter/testfun.txi	Thu Dec 15 01:10:05 2005 +0000
@@ -0,0 +1,283 @@
+@c Copyright (C) 2005 David Bateman
+@c Copyright (C) 2002-2005 Paul Kienzle
+@c This is part of the Octave manual.
+@c For copying conditions, see the file gpl.texi.
+
+@node Test and Demo Functions
+@appendix Test and Demo Functions
+@cindex test functions
+
+Octave includes a number of functions to allow the integration of testing
+and demonstration code in the source code of the functions themselves.
+
+@menu
+* Test Functions::
+* Demonstration Functions::
+@end menu
+
+@node Test Functions
+@section Test Functions
+
+@DOCSTRING(test)
+
+@code{test} scans the named script file looking for lines which
+start with @code{%!}. The prefix is stripped off and the rest of the
+line is processed through the octave interpreter. If the code
+generates an error, then the test is said to fail.
+
+Since @code{eval()} will stop at the first error it encounters, you must
+divide your tests up into blocks, with anything in a separate
+block evaluated separately.  Blocks are introduced by the keyword
+@code{test} immediately following the @code{%!}.  For example,
+
+@example
+@group
+   %!test error("this test fails!");
+   %!test "this test doesn't fail since it doesn't generate an error";
+@end group
+@end example
+
+When a test fails, you will see something like:
+
+@example
+@group
+     ***** test error('this test fails!')
+   !!!!! test failed
+   this test fails!
+@end group
+@end example
+
+Generally, to test if something works, you want to assert that it
+produces a correct value.  A real test might look something like
+
+@example
+@group
+   %!test
+   %! @var{a} = [1, 2, 3; 4, 5, 6]; B = [1; 2];
+   %! expect = [ @var{a} ; 2*@var{a} ];
+   %! get = kron (@var{b}, @var{a});
+   %! if (any(size(expect) != size(get)))
+   %!    error ("wrong size: expected %d,%d but got %d,%d",
+   %!           size(expect), size(get));
+   %! elseif (any(any(expect!=get)))
+   %!    error ("didn't get what was expected.");
+   %! endif
+@end group
+@end example
+
+To make the process easier, use the @code{assert} function.  For example,
+with @code{assert} the previous test is reduced to:
+
+@example
+@group
+   %!test
+   %! @var{a} = [1, 2, 3; 4, 5, 6]; @var{b} = [1; 2];
+   %! assert (kron (@var{b}, @var{a}), [ @var{a}; 2*@var{a} ]);
+@end group
+@end example
+
+@code{assert} can accept a tolerance so that you can compare results
+absolutely or relatively. For example, the following all succeed:
+
+@example
+@group
+   %!test assert (1+eps, 1, 2*eps)          # absolute error
+   %!test assert (100+100*eps, 100, -2*eps) # relative error
+@end group
+@end example
+
+You can also do the comparison yourself, but still have assert
+generate the error:
+
+@example
+@group
+   %!test assert (isempty([]))
+   %!test assert ([ 1,2; 3,4 ] > 0)
+@end group
+@end example
+
+Because @code{assert} is so frequently used alone in a test block, there
+is a shorthand form:
+
+@example
+   %!assert (@dots{})
+@end example
+
+which is equivalent to:
+
+@example
+   %!test assert (@dots{})
+@end example
+
+Each block is evaluated in its own function environment, which means
+that variables defined in one block are not automatically shared
+with other blocks.  If you do want to share variables, then you
+must declare them as @code{shared} before you use them.  For example, the
+following declares the variable @var{a}, gives it an initial value (default
+is empty), then uses it in several subsequent tests.
+
+@example
+@group
+   %!shared @var{a}
+   %! @var{a} = [1, 2, 3; 4, 5, 6];
+   %!assert (kron ([1; 2], @var{a}), [ @var{a}; 2*@var{a} ]);
+   %!assert (kron ([1, 2], @var{a}), [ @var{a}, 2*@var{a} ]);
+   %!assert (kron ([1,2; 3,4], @var{a}), [ @var{a},2*@var{a}; 3*@var{a},4*@var{a} ]);
+@end group
+@end example
+
+You can share several variables at the same time:
+
+@example
+   %!shared @var{a}, @var{b}
+@end example
+
+You can also share test functions:
+
+@example
+@group
+   %!function @var{a} = fn(@var{b})
+   %!  @var{a} = 2*@var{b};
+   %!assert (@var{a}(2),4);
+@end group
+@end example
+
+Note that all previous variables and values are lost when a new 
+shared block is declared.
+
+Error and warning blocks are like test blocks, but they only succeed 
+if the code generates an error.  You can check the text of the error
+is correct using an optional regular expression @code{<pattern>}.  
+For example:
+
+@example
+   %!error <passes!> error('this test passes!');
+@end example
+
+If the code doesn't generate an error, the test fails. For example,
+
+@example
+   %!error "this is an error because it succeeds.";
+@end example
+
+produces
+
+@example
+@group
+   ***** error "this is an error because it succeeds.";
+   !!!!! test failed: no error
+@end group
+@end example
+
+It is important to automate the tests as much as possible, however
+some tests require user interaction.  These can be isolated into
+demo blocks, which if you are in batch mode, are only run when 
+called with @code{demo} or @code{verbose}. The code is displayed before
+it is executed. For example,
+
+@example
+@group
+   %!demo
+   %! @var{t}=[0:0.01:2*pi]; @var{x}=sin(@var{t});
+   %! plot(@var{t},@var{x});
+   %! you should now see a sine wave in your figure window
+@end group
+@end example
+
+produces
+
+@example
+@group
+   > @var{t}=[0:0.01:2*pi]; @var{x}=sin(@var{t});
+   > plot(@var{t},@var{x});
+   > you should now see a sine wave in your figure window
+   Press <enter> to continue: 
+@end group
+@end example
+
+Note that demo blocks cannot use any shared variables.  This is so
+that they can be executed by themselves, ignoring all other tests.
+
+If you want to temporarily disable a test block, put @code{#} in place
+of the block type.  This creates a comment block which is echoed
+in the log file, but is not executed.  For example:
+
+@example
+@group
+   %!#demo
+   %! @var{t}=[0:0.01:2*pi]; @var{x}=sin(@var{t});
+   %! plot(@var{t},@var{x});
+   %! you should now see a sine wave in your figure window
+@end group
+@end example
+
+Block type summary:
+
+@table @code
+@item %!test
+check that entire block is correct
+@item %!error
+check for correct error message
+@item %!warning
+check for correct warning message
+@item %!demo
+demo only executes in interactive mode
+@item %!#
+comment: ignore everything within the block
+@item %!shared x,y,z
+declares variables for use in multiple tests
+@item %!function
+defines a function value for a shared variable
+@item %!assert (x, y, tol)
+shorthand for %!test assert (x, y, tol)
+@end table
+
+You can also create test scripts for builtins and your own C++
+functions. Just put a file of the function name on your path without
+any extension and it will be picked up by the test procedure.  You
+can even embed tests directly in your C++ code:
+
+@example
+@group
+   #if 0
+   %!test disp('this is a test')
+   #endif
+@end group
+@end example
+
+or
+
+@example
+@group
+   /*
+   %!test disp('this is a test')
+   */
+@end group
+@end example
+
+but then the code will have to be on the load path and the user 
+will have to remember to type test('name.cc').  Conversely, you
+can separate the tests from normal octave script files by putting
+them in plain files with no extension rather than in script files.
+@c DO I WANT TO INCLUDE THE EDITOR SPECIFIC STATEMENT BELOW???
+@c Don't forget to tell emacs that the plain text file you are using
+@c is actually octave code, using something like:
+@c   -*-octave-*-
+
+@DOCSTRING(assert)
+
+@DOCSTRING(fail)
+
+@node Demonstration Functions
+@section Demonstration Functions
+
+@DOCSTRING(demo)
+
+@DOCSTRING(example)
+
+@DOCSTRING(speed)
+
+
+@c Local Variables: ***
+@c Mode: texinfo ***
+@c End: ***