⛏️ index : haiku.git

/*
 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Distributed under the terms of the MIT License.
 */
#ifndef TEST_CONTEXT_H
#define TEST_CONTEXT_H


#include <stdarg.h>
#include <stdio.h>

#include <KernelExport.h>

#include "TestOutput.h"


class Test;
class TestContext;
class TestError;


struct TestOptions {
			bool				panicOnFailure;
			bool				quitAfterFailure;

	public:
								TestOptions();
};


struct GlobalTestContext {
								GlobalTestContext(TestOutput& output,
									TestOptions& options);
								~GlobalTestContext();

	static	GlobalTestContext*	Current();

			TestOutput&			Output() const	{ return fOutput; }
			TestOptions&		Options() const	{ return fOptions; }

			TestContext*		CurrentContext() const
									{ return fCurrentContext; }
			void				SetCurrentContext(TestContext* context);

			int32				TotalTests() const	{ return fTotalTests; }
			int32				FailedTests() const	{ return fFailedTests; }

			void				TestDone(bool success);

			thread_id			SpawnThread(thread_func function,
									const char* name, int32 priority,
									void* arg);

private:
			struct ThreadEntry {
				ThreadEntry*		globalNext;
				ThreadEntry*		contextNext;
				GlobalTestContext*	context;
				thread_id			thread;

				ThreadEntry(GlobalTestContext* context)
					:
					globalNext(NULL),
					contextNext(NULL),
					context(context),
					thread(find_thread(NULL))
				{
				}
			};

			struct ThreadCookie;

private:
	static	void				_SetCurrent(ThreadEntry* entry);
	static	void				_UnsetCurrent(ThreadEntry* entry);
	static	status_t			_ThreadEntry(void* data);

private:
	static	ThreadEntry*		sGlobalThreads;
			ThreadEntry*		fThreads;
			ThreadEntry			fThreadEntry;
			TestOutput&			fOutput;
			TestOptions&		fOptions;
			TestContext*		fCurrentContext;
			int32				fTotalTests;
			int32				fFailedTests;
};


class TestContext {
public:
								TestContext(GlobalTestContext* globalContext);
								TestContext(TestContext& parent, Test* test);
								~TestContext();

	static	TestContext*		Current();

			GlobalTestContext*	GlobalContext() const { return fGlobalContext; }
			TestContext*		Parent() const	{ return fParent; }
			int32				Level() const	{ return fLevel; }
			TestOutput&			Output() const
									{ return fGlobalContext->Output(); }
			TestOptions&		Options() const
									{ return fGlobalContext->Options(); }

	inline	int					PrintArgs(const char* format, va_list args);
	inline	int					Print(const char* format,...);

			void				ErrorArgs(const char* format, va_list args);
	inline	void				Error(const char* format,...);

	inline	void				AssertFailed(const char* file, int line,
									const char* function,
									const char* condition);
	inline	void				AssertFailed(const char* file, int line,
									const char* function,
									const char* condition,
									const char* format,...);

			void				TestDone(bool success);

private:
			GlobalTestContext*	fGlobalContext;
			TestContext*		fParent;
			Test*				fTest;
			TestError*			fErrors;
			int32				fLevel;
};


/*static*/ inline TestContext*
TestContext::Current()
{
	return GlobalTestContext::Current()->CurrentContext();
}


int
TestContext::PrintArgs(const char* format, va_list args)
{
	return Output().PrintArgs(format, args);
}


int
TestContext::Print(const char* format,...)
{
	va_list args;
	va_start(args, format);
	int result = Output().PrintArgs(format, args);
	va_end(args);

	return result;
}


void
TestContext::Error(const char* format,...)
{
	va_list args;
	va_start(args, format);
	ErrorArgs(format, args);
	va_end(args);
}


void
TestContext::AssertFailed(const char* file, int line, const char* function,
	const char* condition)
{
	Error("ASSERT FAILED at %s:%d %s: %s\n", file, line, function, condition);
}


void
TestContext::AssertFailed(const char* file, int line, const char* function,
	const char* condition, const char* format,...)
{
	char buffer[256];

	va_list args;
	va_start(args, format);
	vsnprintf(buffer, sizeof(buffer), format, args);
	va_end(args);

	Error("ASSERT FAILED at %s:%d %s: %s; %s\n", file, line, function,
		condition, buffer);
}


#endif	// TEST_CONTEXT_H