********************************************************************************
HOW TO ADD A UNIT TEST

A test for any given function should be in a file called FTEST_<function name>.
Unit tests for objects are named as OTEST_<object>.  To add a new unit test,
the easiest thing to do is to copy an existing one and clear out the test_
functions, this way the driver is all set up for you. The rest of the function
calls should be self-explanatory. 

There are several changes you need to make to add a new test.  First, go to the
Imakefile and add your test to the correct line.  Then go to unit_tests.cpp. 
To get your test to run with all the rest of the tests, you need to add a 
prototype for your test and register the function with the function driver, just
follow the same format as existing unit tests.

Sometimes it may be useful to add a function you will use several times in your
unit tests, in this case it can go in unit_test_utils.cpp.  Be sure to check 
the functions in there to avoid adding duplicates.

********************************************************************************
Format of the Tests

There are two parts to the output of each test; the function header and the
actual tests.  The function header is displayed once for each function that is
being tested, while the test output will show up once each time you test the 
function. In all, the test ends up looking like this:

FUNCTION:  prototype of function, printed out once
COMMENT:  detailed comments about the function or what is or isn't being tested
TEST:  description of what the test does 
KNOWN PROBLEM:  comments about known problems such as not being able to test 
	something due to an ASSERT or EXCEPT
INPUT:
    emission of input parameters
EXPECTED OUTPUT:
    expected return value and other expected output of test
ACTUAL OUTPUT:
    actual return value and other actual output of test
RESULT:  SUCCESS|FAILURE, test passed|failed at line x

TEST: <more like the above>
    ...


********************************************************************************
Example Test

Assume you had a function, ints_are_equal(), that you wanted to write a unit
test for.  The test file would look something like this:

static bool test_equality(void);

bool FTEST_ints_are_equal(void) {
	emit_function("bool ints_are_equal(int x, int y)");
	emit_comment("Determines if two given ints are equal");

	FunctionDriver driver;
	driver.register_function(test_equality);
	
	return driver.do_all_functions();
}

static bool test_equality() {
	emit_test("Are two equivalent ints considered equal?");
	emit_input_header();
	emit_param("x", "3");
	emit_param("y", "3");
	emit_output_expected_header();
	emit_retval("TRUE");
	emit_output_actual_header();
	bool result = ints_are_equal(3, 3);
	if(result == NULL) {		//not possible in this case, but the idea holds
		emit_alert("ints_are_equal(3, 3) returned NULL");
		ABORT;	//macro that calls emit_result_abort, returns false
	}
	emit_retval("%s", tfstr(result));	//tfstr() comes from unit_test_utils
	if(result) {
		PASS;	//macro that calls emit_result_success, returns true
	} else {
		FAIL;	//macro that calls emit_result_failure, returns false
	}
}

The output from running only that test would look something like this:

---------------------
FUNCTION:  bool ints_are_equal(int x, int y)
COMMENT:  Determines if two given ints are equal

TEST:  Are two equivalent ints considered equal?
INPUT:
	x:  3
	y:  3
EXPECTED OUTPUT:
	RETURN:  TRUE
ACTUAL OUTPUT:
	RETURN:  TRUE
RESULT:  SUCCESS, test passed at line 72 (0.000006 seconds)

---------------------
SUMMARY:
========
    Total Tested Objects:  0
    Total Unit Tests:      1
    Passed Unit Tests:     1
    Failed Unit Tests:     0
    Aborted Unit Tests:    0
    Skipped Unit Tests:    0
    Total Time Taken:      0.000006 seconds
Test suite has passed.

If your test were to fail, the result line would indicate failure instead of
success.  If there is a specific test that fails make a ticket for the problem
and get it fixed by someone soon. This test program is here to help us notice
when something that works perfectly now stops working.


********************************************************************************
MODIFYING THE UNIT TEST SUITE

emit.cpp and emit.h
	Manages all unit test output.

unit_test_utils.cpp and unit_test_utils.h
	Contains helper functions common to many tests.

unit_tests.cpp and unit_tests.h
	Contains the main() function. All new tests need to be registered here.
	example: map(FTEST_host_in_domain),

function_test_driver.cpp and function_test_driver.h
	Handles driver code.

FTEST_ and OTEST_ files
	Actual tests, although be careful because they're not necessarily run 
	unless they're registered in unit_tests.cpp.

********************************************************************************
RUNNING THE UNIT TEST SUITE

condor_unit_tests
	-n x: Run x number of tests
	-N x: Test x number of functions/objects
	-t x: Run test(s) x (x is a test name, FTEST_ or OTEST_)
	-F: Only test functions
	-O: Only test objects
	-f: Only show output for tests that fail
	-p: Only show output for tests that pass
	-y: Only show summary
	-h, --help: Print usage

Examples:
	To only run tests in OTEST_ArgList.cpp and OTEST_StringList.cpp and only 
	show a summary: 
		condor_unit_tests -t OTEST_ArgList OTEST_StringList -y
	To only test 5 functions and only show output for tests that fail:
		condor_unit_tests -F -N 5 -f
	To only run the first 100 tests in OTEST_MyString.cpp:
		condor_unit_tests -n 100 -t OTEST_MyString
