1/*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5#ifndef TEST_CONTEXT_H
6#define TEST_CONTEXT_H
7
8
9#include <stdarg.h>
10#include <stdio.h>
11
12#include <KernelExport.h>
13
14#include "TestOutput.h"
15
16
17class Test;
18class TestContext;
19class TestError;
20
21
22struct TestOptions {
23			bool				panicOnFailure;
24			bool				quitAfterFailure;
25
26	public:
27								TestOptions();
28};
29
30
31struct GlobalTestContext {
32								GlobalTestContext(TestOutput& output,
33									TestOptions& options);
34								~GlobalTestContext();
35
36	static	GlobalTestContext*	Current();
37
38			TestOutput&			Output() const	{ return fOutput; }
39			TestOptions&		Options() const	{ return fOptions; }
40
41			TestContext*		CurrentContext() const
42									{ return fCurrentContext; }
43			void				SetCurrentContext(TestContext* context);
44
45			int32				TotalTests() const	{ return fTotalTests; }
46			int32				FailedTests() const	{ return fFailedTests; }
47
48			void				TestDone(bool success);
49
50			thread_id			SpawnThread(thread_func function,
51									const char* name, int32 priority,
52									void* arg);
53
54private:
55			struct ThreadEntry {
56				ThreadEntry*		globalNext;
57				ThreadEntry*		contextNext;
58				GlobalTestContext*	context;
59				thread_id			thread;
60
61				ThreadEntry(GlobalTestContext* context)
62					:
63					globalNext(NULL),
64					contextNext(NULL),
65					context(context),
66					thread(find_thread(NULL))
67				{
68				}
69			};
70
71			struct ThreadCookie;
72
73private:
74	static	void				_SetCurrent(ThreadEntry* entry);
75	static	void				_UnsetCurrent(ThreadEntry* entry);
76	static	status_t			_ThreadEntry(void* data);
77
78private:
79	static	ThreadEntry*		sGlobalThreads;
80			ThreadEntry*		fThreads;
81			ThreadEntry			fThreadEntry;
82			TestOutput&			fOutput;
83			TestOptions&		fOptions;
84			TestContext*		fCurrentContext;
85			int32				fTotalTests;
86			int32				fFailedTests;
87};
88
89
90class TestContext {
91public:
92								TestContext(GlobalTestContext* globalContext);
93								TestContext(TestContext& parent, Test* test);
94								~TestContext();
95
96	static	TestContext*		Current();
97
98			GlobalTestContext*	GlobalContext() const { return fGlobalContext; }
99			TestContext*		Parent() const	{ return fParent; }
100			int32				Level() const	{ return fLevel; }
101			TestOutput&			Output() const
102									{ return fGlobalContext->Output(); }
103			TestOptions&		Options() const
104									{ return fGlobalContext->Options(); }
105
106	inline	int					PrintArgs(const char* format, va_list args);
107	inline	int					Print(const char* format,...);
108
109			void				ErrorArgs(const char* format, va_list args);
110	inline	void				Error(const char* format,...);
111
112	inline	void				AssertFailed(const char* file, int line,
113									const char* function,
114									const char* condition);
115	inline	void				AssertFailed(const char* file, int line,
116									const char* function,
117									const char* condition,
118									const char* format,...);
119
120			void				TestDone(bool success);
121
122private:
123			GlobalTestContext*	fGlobalContext;
124			TestContext*		fParent;
125			Test*				fTest;
126			TestError*			fErrors;
127			int32				fLevel;
128};
129
130
131/*static*/ inline TestContext*
132TestContext::Current()
133{
134	return GlobalTestContext::Current()->CurrentContext();
135}
136
137
138int
139TestContext::PrintArgs(const char* format, va_list args)
140{
141	return Output().PrintArgs(format, args);
142}
143
144
145int
146TestContext::Print(const char* format,...)
147{
148	va_list args;
149	va_start(args, format);
150	int result = Output().PrintArgs(format, args);
151	va_end(args);
152
153	return result;
154}
155
156
157void
158TestContext::Error(const char* format,...)
159{
160	va_list args;
161	va_start(args, format);
162	ErrorArgs(format, args);
163	va_end(args);
164}
165
166
167void
168TestContext::AssertFailed(const char* file, int line, const char* function,
169	const char* condition)
170{
171	Error("ASSERT FAILED at %s:%d %s: %s\n", file, line, function, condition);
172}
173
174
175void
176TestContext::AssertFailed(const char* file, int line, const char* function,
177	const char* condition, const char* format,...)
178{
179	char buffer[256];
180
181	va_list args;
182	va_start(args, format);
183	vsnprintf(buffer, sizeof(buffer), format, args);
184	va_end(args);
185
186	Error("ASSERT FAILED at %s:%d %s: %s; %s\n", file, line, function,
187		condition, buffer);
188}
189
190
191#endif	// TEST_CONTEXT_H
192