--- /dev/null
+function e = errcheck(error_prefix)
+ e = 1;
+ if (index(__error_text__, error_prefix) != 1)
+ e = 0;
+ printf("\nUNEXPECTED ERROR: %s", __error_text__);
+ endif
+end
--- /dev/null
+function rv = erreval(error_prefix, try_str, catch_str)
+ ## erreval() extends the built-in function eval(). Return 0 if
+ ## try_str does not raise the error of type error_prefix, return 1
+ ## otherwise.
+
+ global unittest_results;
+ for k = 1:length(unittest_results.eval_globals)
+ eval(unittest_results.eval_globals{k});
+ end
+
+ rv = 0;
+ try
+ eval(try_str);
+ catch
+ rv = errcheck(error_prefix);
+ end
+endfunction
--- /dev/null
+#!/usr/bin/octave --silent
+
+unit_init(1, {});
+
+unit_test_equals("sin[0] == 0", ...
+ 0, ...
+ divided_difference(@sin, 0));
+
+unit_test_equals("sin[0, pi] == 0", ...
+ 0, ...
+ divided_difference(@sin, [0,pi]));
--- /dev/null
+function unit_init(verbosity, global_vars)
+ ## Initialize the global structure unittest_results, which is needed
+ ## in all functions of the *unittest module. Debugging information
+ ## is printed if verbosity==1. global_vars is a cell array of the
+ ## names of the global variables used in the tests.
+ ##
+ ## e.g. unit_init(1, {"g", "a", "x"})
+
+ global unittest_results;
+
+ unittest_results.verbose = 0;
+ unittest_results.eval_globals = {};
+ if (nargin > 0)
+ if (!isscalar(verbosity) || verbosity < 0 || verbosity > 1)
+ warning("unit_init: verbose must be 0 or 1");
+ else
+ unittest_results.verbose = verbosity;
+ endif
+
+ if (nargin == 2 && iscell(global_vars))
+ for i = 1:length(global_vars)
+ unittest_results.eval_globals{i} = strcat("global ", global_vars{i}, ";");
+ endfor
+ else
+ error("global_vars must be a cell array");
+ endif
+
+ if (nargin > 2)
+ usage("expecting 2 arguments only");
+ end
+ endif
+
+ unittest_results.total = 0; # number of testcases attempted
+ unittest_results.pass = 0; # number of expected passed
+ unittest_results.fail = 0; # number of unexpected failures
+ unittest_results.upass = 0; # number of unexpected passes
+ unittest_results.xfail = 0; # number of expected failures
+ unittest_results.unresolved = 0; # number of unresolved testcases
+
+ default_eval_print_flag = 0;
+endfunction
--- /dev/null
+function unit_results()
+ ## Print the results from previous unittest calls in pretty format.
+
+ global unittest_results;
+
+ printf("\n");
+ printf("# of testcases attempted %d\n", unittest_results.total);
+ printf("# of expected passes %d\n", unittest_results.pass);
+ printf("# of expected failures %d\n", unittest_results.xfail);
+ printf("# of unexpected passes %d\n", unittest_results.upass);
+ printf("# of unexpected failures %d\n", unittest_results.fail);
+ printf("# of unresolved testcases %d\n", unittest_results.unresolved);
+ printf("\n");
+
+ if (unittest_results.total == unittest_results.pass + unittest_results.xfail)
+ printf("Unit testing completed successfully!\n");
+ else
+ printf("One or more tests failed!\n");
+ endif
+endfunction
--- /dev/null
+function result = unit_test(test_title, expect_pass, actual_result)
+ ## Function unittest compares the ACTUAL_RESULT of running
+ ## a test (either 0 for failure, or 1 for success) with the
+ ## expected outcome of the test EXPECT_PASS (either 0 for expecting
+ ## a failure, or 1 for expecting pass). TEST_TITLE is the name of
+ ## the test. All test results will be accompanied by the test's
+ ## title.
+ ##
+ ## The result of unit_test is on of the following: UNRESOLVED: The
+ ## test did neither return 0 nor 1. PASS: expected pass, got pass.
+ ## FAIL: expected pass, got fail. UPASS: expected fail, got pass.
+ ## XFAIL: expected fail, got fail.
+ ##
+ ## A call to unit_test typically looks like this:
+ ##
+ ## unit_test("scalar integer addition", 1, eval("1 + 1 == 2;"));
+
+ global unittest_results;
+
+ ## Sanity check input parameters
+ if ( nargin < 3 || nargin > 4 )
+ error("Function run_rest expects 3 or 4 parameters.");
+ endif
+
+ if (!ischar(test_title))
+ error("Expecting TEST_TITLE (arg 1) to be a string.");
+ endif
+
+ if (expect_pass != 0 && expect_pass != 1)
+ error("Expecting EXPECT_PASS (arg 2) to be 0 or 1.");
+ endif
+
+ unittest_results.total++;
+
+ ## Take actions depending on what test result we expect
+ ## (expect_pass), and what we actually got (actual_result).
+ if (actual_result != 0 && actual_result != 1)
+ result = "UNRESOLVED";
+ unittest_results.unresolved++;
+ if (actual_result == 2)
+ printf("SYNTAX ERROR: %s\n", test_title);
+ endif
+ return;
+ endif
+
+ if (expect_pass == 1 && actual_result == 1)
+ result = "PASS";
+ if (unittest_results.verbose != 0)
+ printf("PASS: %s\n", test_title);
+ else
+ printf('.');
+ endif
+ unittest_results.pass++;
+ elseif (expect_pass == 1 && actual_result == 0)
+ result = "FAIL";
+ printf("FAIL: %s\n\n", test_title);
+ unittest_results.fail++;
+ elseif (expect_pass == 0 && actual_result == 0)
+ result = "XFAIL";
+ printf("XFAIL: %s\n", test_title);
+ unittest_results.xfail++;
+ elseif (expect_pass == 0 && actual_result == 1)
+ result = "UPASS";
+ printf("UPASS: %s\n", test_title);
+ unittest_results.upass++;
+ endif
+endfunction
--- /dev/null
+function unit_test_equals(test_title, result_A, result_B)
+ tol = 0.0001;
+ err = abs(result_A - result_B);
+ unit_test(test_title, 1, all(err < tol));
+endfunction
--- /dev/null
+function unit_test_err(test_title, expected_error_prefix, evaluated_string)
+ unit_test(test_title, 1, erreval(expected_error_prefix, evaluated_string));
+endfunction