1/*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "TestSuite.h"
8
9#include <new>
10
11#include <string.h>
12
13#include "TestVisitor.h"
14
15
16TestSuite::TestSuite(const char* name)
17	:
18	Test(name),
19	fTests(NULL),
20	fTestCount(0)
21{
22}
23
24
25TestSuite::~TestSuite()
26{
27	for (int32 i = 0; i < fTestCount; i++)
28		delete fTests[i];
29	delete[] fTests;
30}
31
32
33int32
34TestSuite::CountTests() const
35{
36	return fTestCount;
37}
38
39
40Test*
41TestSuite::TestAt(int32 index) const
42{
43	return index >= 0 && index < fTestCount ? fTests[index] : NULL;
44}
45
46
47Test*
48TestSuite::FindTest(const char* name, int32 nameLength) const
49{
50	if (nameLength < 0)
51		nameLength = strlen(name);
52
53	for (int32 i = 0; Test* test = TestAt(i); i++) {
54		if (strlen(test->Name()) == (size_t)nameLength
55			&& strncmp(test->Name(), name, nameLength) == 0) {
56			return test;
57		}
58	}
59
60	return NULL;
61}
62
63
64bool
65TestSuite::AddTest(Test* test)
66{
67	if (test == NULL)
68		return test;
69
70	Test** tests = new(std::nothrow) Test*[fTestCount + 1];
71	if (tests == NULL) {
72		delete test;
73		return false;
74	}
75
76	if (fTestCount > 0)
77		memcpy(tests, fTests, sizeof(Test*) * fTestCount);
78
79	delete[] fTests;
80
81	fTests = tests;
82	fTests[fTestCount++] = test;
83
84	test->SetSuite(this);
85
86	return true;
87}
88
89
90bool
91TestSuite::IsLeafTest() const
92{
93	return false;
94}
95
96
97bool
98TestSuite::Run(TestContext& context)
99{
100	for (int32 i = 0; Test* test = TestAt(i); i++) {
101		bool result = _Run(context, test, NULL);
102		if (!result && context.Options().quitAfterFailure)
103			return false;
104	}
105
106	return true;
107}
108
109
110bool
111TestSuite::Run(TestContext& context, const char* name)
112{
113	const char* separator = strstr(name, "::");
114	Test* test = FindTest(name, separator != NULL ? separator - name : -1);
115	if (test == NULL) {
116		context.Print("No such test: \"%.*s\"\n",
117			int(separator != NULL ? separator - name : strlen(name)), name);
118		return !context.Options().quitAfterFailure;
119	}
120
121	return _Run(context, test, separator != NULL ? separator + 2 : NULL)
122		|| !context.Options().quitAfterFailure;
123}
124
125
126Test*
127TestSuite::Visit(TestVisitor& visitor)
128{
129	if (visitor.VisitTestSuitePre(this))
130		return this;
131
132	for (int32 i = 0; Test* test = TestAt(i); i++) {
133		if (Test* foundTest = test->Visit(visitor))
134			return foundTest;
135	}
136
137	return visitor.VisitTestSuitePost(this) ? this : NULL;
138}
139
140
141bool
142TestSuite::_Run(TestContext& context, Test* test, const char* name)
143{
144	TestContext subContext(context, test);
145
146	status_t error = test->Setup(subContext);
147	if (error != B_OK) {
148		subContext.Error("setup failed\n");
149		test->Cleanup(subContext, false);
150		subContext.TestDone(false);
151		return false;
152	}
153
154	bool result = name != NULL
155		? test->Run(subContext, name) : test->Run(subContext);
156	test->Cleanup(subContext, true);
157
158	subContext.TestDone(result);
159
160	return result;
161}
162