// ----------------------------------------------------------------------------------------
//
//  common/test/assertions.h
//    
//  Bob Cook Development, Robotics Library
//  http://www.bobcookdev.com/rl/
//    
//  This file provides unit testing assertion macros.
//
//  Copyright (C) 2008 Bob Cook
//
//      This program is free software; you can redistribute it and/or modify it
//      under the terms of the GNU General Public License as published by the
//      Free Software Foundation; either version 2 of the License, or (at your
//      option) any later version.
//    
//      This program is distributed in the hope that it will be useful, but 
//      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
//      or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License 
//      for more details.
//    
//      You should have received a copy of the GNU General Public License along
//      with this program; if not, write to the Free Software Foundation, Inc., 
//      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
//
// ----------------------------------------------------------------------------------------


#if !defined( BCDRL_COMMON_TEST_ASSERTIONS_H )
#define BCDRL_COMMON_TEST_ASSERTIONS_H


#include <stdint.h>


// ----------------------------------------------------------------------------------------
//  definitions from "project_defs.h"
//
//  enable support for numberic double types as well as integer types
//
//      + TEST_INC_SUPPORT_DOUBLES
//
// ----------------------------------------------------------------------------------------

// ----------------------------------------------------------------------------------------
//	test_assert
//
//		Test an arbitrary boolean condition: test_assert( i != 42 );
//

#define test_assert( t ) \
	do { if ( ! (t) ) { test_report_failed( #t, __FILE__, __LINE__ ); } } while( 0 )

// ----------------------------------------------------------------------------------------
//	test_assert_failed
//
//		Trigger a failure without a test condition: test_assert_failed( message );
//

#define test_assert_failed( m ) \
	do { test_report_failed( m, __FILE__, __LINE__ ); } while( 0 )

// ----------------------------------------------------------------------------------------
//	test_assert_not_null
//
//		Test that a given value is not null (not zero): test_assert_not_null( i );
//

#define test_assert_not_null( t ) \
	do { if ( (t) == 0 ) \
		{ test_report_failed( #t " is null", __FILE__, __LINE__ ); } } while( 0 )

// ----------------------------------------------------------------------------------------
//	test_assert_is_null
//
//		Test that a given value is null (zero): test_assert_is_null( i );
//

#define test_assert_is_null( t ) \
	do { if ( (t) != 0 ) \
		{ test_report_failed( #t " is not null", __FILE__, __LINE__ ); } } while( 0 )

// ----------------------------------------------------------------------------------------
//	test_assert_equals
//
//		Test for integer equality: test_assert_equals( i, j );
//
//		This test macro is not appropriate for testing equality of floating point
//		numbers; see test_assert_float_equals().
//

#define test_assert_equals( a, b ) \
	do { if ( (a) != (b) ) \
		{ test_report_failed_num( a, b, "!=", __FILE__, __LINE__ ); } } while( 0 )

// ----------------------------------------------------------------------------------------
//	test_assert_less_than
//
//		Test a numerical condition: test_assert_less_than( i, j );
//

#define test_assert_less_than( a, b ) \
	do { if ( ! ( (a) < (b) ) ) \
		{ test_report_failed_num( a, b, "<", __FILE__, __LINE__ ); } } while( 0 )

// ----------------------------------------------------------------------------------------
//	test_assert_less_than_or_equals
//
//		Test a numerical condition: test_assert_less_than_or_equals( i, j );
//
//		This test macro is not appropriate for testing equality of floating point
//		numbers; see test_assert_float_equals().
//

#define test_assert_less_than_or_equals( a, b ) \
	do { if ( ! ( (a) <= (b) ) ) \
		{ test_report_failed_num( a, b, "<=", __FILE__, __LINE__ ); } } while( 0 )

// ----------------------------------------------------------------------------------------
//	test_assert_greater_than
//
//		Test a numerical condition: test_assert_greater_than( i, j );
//

#define test_assert_greater_than( a, b ) \
	do { if ( ! ( (a) > (b) ) ) \
		{ test_report_failed_num( a, b, ">", __FILE__, __LINE__ ); } } while( 0 )

// ----------------------------------------------------------------------------------------
//	test_assert_greater_than_or_equals
//
//		Test a boolean condition: test_assert_greater_than_or_equals( i, j );
//
//		This test macro is not appropriate for testing equality of floating point
//		numbers; see test_assert_float_equals().
//

#define test_assert_greater_than_or_equals( a, b ) \
	do { if ( ! ( (a) >= (b) ) ) \
		{ test_report_failed_num( a, b, ">=", __FILE__, __LINE__ ); } } while( 0 )

// ----------------------------------------------------------------------------------------
//	test_assert_float_equals
//
//		Test a comparion between two numbers: test_assert_float_equals( i, j );
//
//		The allowable delta between floating point numbers is 0.001.
//
//		This functionality is only included if TEST_INC_SUPPORT_DOUBLES is defined.
//

#define TEST_FLOAT_TOLERANCE 0.0001

#define test_assert_float_equals( a, b, e ) \
	do { \
		if ( ( (a) < (b) ) && ( (b) - (a) > e ) ) \
			{ test_report_failed_num( a, b, "!=", __FILE__, __LINE__ ); } \
		if ( ( (a) >= (b) ) && ( (a) - b > e ) ) \
			{ test_report_failed_num( a, b, "!=", __FILE__, __LINE__ ); } \
	} while( 0 )

// ----------------------------------------------------------------------------------------
//	test_assert_str_equals
//
//		Test a boolean condition: test_assert_str_equals( "foo", "bar" );
//

#define test_assert_str_equals( a, b ) \
	do { if ( ! test_strings_equal( a, b ) ) \
		{ test_report_failed_str( a, b, __FILE__, __LINE__ ); } } while( 0 )

// ----------------------------------------------------------------------------------------
//	test_reset_failure_count
//
//		Reset the count of failed tests to zero.
//

void test_reset_failure_count();

// ----------------------------------------------------------------------------------------
//	test_get_failure_count
//
//		Retrieve the total number of failed tests since the last reset (or start).
//

int test_get_failure_count();

// ----------------------------------------------------------------------------------------
//	Assertion handler prototypes
//
//		Generally there is no reason to use these functions, use the above macros.
//

bool test_strings_equal( const char* a, const char* b );
void test_report_failed( const char* test, const char* f, int l );
void test_report_failed_str( const char* a, const char* b, const char* f, int l );
void test_report_failed_num( int a, int b, const char* op, const char* f, int l );
void test_report_failed_num( double a, int b, const char* op, const char* f, int l );
void test_report_failed_num( int a, double b, const char* op, const char* f, int l );
void test_report_failed_num( double a, double b, const char* op, const char* f, int l );

// ----------------------------------------------------------------------------------------

#endif // #if !defined( BCDRL_COMMON_TEST_ASSERTIONS_H )
// ----------------------------------------------------------------------------------------
//  end of assertions.h
// ----------------------------------------------------------------------------------------

