/* SPDX-License-Identifier: MIT */
/**
	@file		ntv2bft.h
	@brief		Handy macros for Basic Functionality Tests.
	@deprecated	This module was deprecated in SDK 17.0 ---  use DocTest instead.
	@warning	This module will be removed in a future SDK.
	@copyright	(C) 2014-2022 AJA Video Systems, Inc. All rights reserved.
**/

#ifndef _NTV2BFT_H_
	#define	_NTV2BFT_H_
	#if !defined(NTV2_DEPRECATE_17_0)

	#include <iostream>
	#include <assert.h>

	#if defined (_DEBUG)  &&  defined (MSWindows)
		#include <Windows.h>
	#endif

	#define	STDOUT	std::cout
	#define	STDERR	std::cerr
	#define	ENDL	std::endl

	#if defined (_DEBUG)
		class NTV2BFT_Debugger
		{
			public:
				static inline void Stop (void)
				{
					#if defined (MSWindows)
						DebugBreak ();
					#else
						//	FORCE TRIGGER DEBUGGER
						STDERR << "Stop" << ENDL;
						char *	pByte	(NULL);
						char	byte	(*pByte);
						byte++;
					#endif	//	not Windows
				}
		};
		#define	DEBUG_BREAK()			do {NTV2BFT_Debugger::Stop ();} while (false)
	#else
		#define	DEBUG_BREAK()			do {} while (false)
	#endif	//	_DEBUG


	/**************************************************************************************************************************
		Basic Functionality Testing Macros

		These macros are useful for logging the results of basic functionality tests (BFTs).
		They assume that the function in which they're used returns an boolean value, which will be true if successful,
		and false if unsuccessful.

		SHOULD_BE_TRUE (condition)		--	Logs a failure if the condition evaluates to false; otherwise, logs a success.
											Use this macro when you expect the condition expression to return true.
		SHOULD_BE_FALSE (condition)		--	Logs a failure if the condition evaluates to true; otherwise, logs a success.
											Use this macro when you expect the condition expression to return false.
		SHOULD_BE_EQUAL (x, y)			--	Logs a success if x == y; otherwise logs a failure.
											Use this macro when you expect x to equal y.
		SHOULD_BE_UNEQUAL (x, y)		--	Logs a success if x != y; otherwise logs a failure.
											Use this macro when you expect x to not equal y.

		The following two symbols determine how these macros behave.

			SHOW_PASSED					If true, successes are logged to STDOUT. (Failures are always logged to STDERR.)
										If false, successes are not logged.

			STOP_AFTER_FAILURE			If true, failures will abort the rest of the test.
										If false, failures won't stop execution, but will instead "press on regardless".

			DEBUG_BREAK_AFTER_FAILURE	If true, failures in _DEBUG builds will invoke the DEBUG_BREAK macro (see above).
										If false, failures won't call DEBUG_BREAK in _DEBUG builds.
	**************************************************************************************************************************/
	#if !defined (SHOW_PASSED)
		#define SHOW_PASSED					(false)
	#endif
	#if !defined (STOP_AFTER_FAILURE)
		#define	STOP_AFTER_FAILURE			(true)
	#endif
	#if !defined (DEBUG_BREAK_AFTER_FAILURE)
		#define	DEBUG_BREAK_AFTER_FAILURE	(false)
	#endif


	#define	SHOULD_BE_TRUE(_x_)			do																															\
										{																															\
											if (!(_x_))																												\
											{																														\
												STDERR	<< "## ERROR:  '" << __FUNCTION__ << "' failed at line " << __LINE__ << " of " << __FILE__ << ":" << ENDL	\
														<< "           Expected 'True' result from '" << #_x_ << "'" << ENDL										\
														<< "           Instead got 'False'" << ENDL;																\
												if (STOP_AFTER_FAILURE)																								\
												{																													\
													if (DEBUG_BREAK_AFTER_FAILURE)																					\
														DEBUG_BREAK ();																								\
													return false;																									\
												}																													\
											}																														\
											else if (SHOW_PASSED)																									\
												STDOUT << "## NOTE:  '" << #_x_ << "' in '" << __FUNCTION__ << "' returned 'True'" << ENDL;							\
										} while (false)


	#define	SHOULD_BE_FALSE(_x_)		do																															\
										{																															\
											if (_x_)																												\
											{																														\
												STDERR	<< "## ERROR:  '" << __FUNCTION__ << "' failed at line " << __LINE__ << " of " << __FILE__ << ":" << ENDL	\
														<< "           Expected 'False' result from '" << #_x_ << "'" << ENDL										\
														<< "           Instead got 'True'" << ENDL;																	\
												if (STOP_AFTER_FAILURE)																								\
												{																													\
													if (DEBUG_BREAK_AFTER_FAILURE)																					\
														DEBUG_BREAK ();																								\
													return false;																									\
												}																													\
											}																														\
											else if (SHOW_PASSED)																									\
												STDOUT << "## NOTE:  '" << #_x_ << "' in '" << __FUNCTION__ << "' returned 'False'" << ENDL;						\
										} while (false)


	#define	SHOULD_BE_NULL(_x_)			do																															\
										{																															\
											if ((_x_) != NULL)																										\
											{																														\
												STDERR	<< "## ERROR:  '" << __FUNCTION__ << "' failed at line " << __LINE__ << " of " << __FILE__ << ":" << ENDL	\
														<< "           '" << (_x_) << "' is non-NULL" << ENDL														\
														<< "           Expected '" << #_x_ << "' to be NULL" << ENDL;												\
												if (STOP_AFTER_FAILURE)																								\
												{																													\
													if (DEBUG_BREAK_AFTER_FAILURE)																					\
														DEBUG_BREAK ();																								\
													return false;																									\
												}																													\
											}																														\
											else if (SHOW_PASSED)																									\
												STDOUT << "## NOTE:  '" << #_x_ << "' is NULL in '" << __FUNCTION__ << "'" << ENDL;									\
										} while (false)


	#define	SHOULD_BE_NON_NULL(_x_)		do																															\
										{																															\
											if ((_x_) == NULL)																										\
											{																														\
												STDERR	<< "## ERROR:  '" << __FUNCTION__ << "' failed at line " << __LINE__ << " of " << __FILE__ << ":" << ENDL	\
														<< "           '" << (_x_) << "' is NULL" << ENDL															\
														<< "           Expected '" << #_x_ << "' to be non-NULL" << ENDL;											\
												if (STOP_AFTER_FAILURE)																								\
												{																													\
													if (DEBUG_BREAK_AFTER_FAILURE)																					\
														DEBUG_BREAK ();																								\
													return false;																									\
												}																													\
											}																														\
											else if (SHOW_PASSED)																									\
												STDOUT << "## NOTE:  '" << #_x_ << "' is non-NULL in '" << __FUNCTION__ << "'" << ENDL;								\
										} while (false)


	#define	SHOULD_BE_EQUAL(_x_, _y_)	do																															\
										{																															\
											if ((_x_) != (_y_))																										\
											{																														\
												STDERR	<< "## ERROR:  '" << __FUNCTION__ << "' failed at line " << __LINE__ << " of " << __FILE__ << ":" << ENDL	\
														<< "           '" << (_x_) << "' is not equal to '" << (_y_) << "'" << ENDL									\
														<< "           Expected '" << #_x_ << "' to equal '" << #_y_ << "'" << ENDL;								\
												if (STOP_AFTER_FAILURE)																								\
												{																													\
													if (DEBUG_BREAK_AFTER_FAILURE)																					\
														DEBUG_BREAK ();																								\
													return false;																									\
												}																													\
											}																														\
											else if (SHOW_PASSED)																									\
												STDOUT << "## NOTE:  '" << #_x_ << "' is equal to '" << #_y_ << "' in '" << __FUNCTION__ << "'" << ENDL;			\
										} while (false)


	#define	SHOULD_BE_UNEQUAL(_x_, _y_)	do																															\
										{																															\
											if ((_x_) == (_y_))																										\
											{																														\
												STDERR	<< "## ERROR:  '" << __FUNCTION__ << "' failed at line " << __LINE__ << " of " << __FILE__ << ":" << ENDL	\
														<< "           '" << (_x_) << "' is equal to '" << (_y_) << "'" << ENDL										\
														<< "           Expected '" << #_x_ << "' to not equal '" << #_y_ << "'" << ENDL;							\
												if (STOP_AFTER_FAILURE)																								\
												{																													\
													if (DEBUG_BREAK_AFTER_FAILURE)																					\
														DEBUG_BREAK ();																								\
													return false;																									\
												}																													\
											}																														\
											else if (SHOW_PASSED)																									\
												STDOUT << "## NOTE:  '" << #_x_ << "' is not equal to '" << #_y_ << "' in '" << __FUNCTION__ << "'" << ENDL;		\
										} while (false)

	#endif	//	!defined(NTV2_DEPRECATE_17_0)
#endif	//	_NTV2BFT_H_
