2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 * @file test_runner.cpp
18 * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
19 * @author Lukasz Wrzosek (l.wrzosek@samsung.com)
21 * @brief This file is the implementation file of test runner
24 #include <dpl/test/test_runner.h>
25 #include <dpl/test/test_results_collector.h>
26 #include <dpl/exception.h>
27 #include <dpl/scoped_free.h>
28 #include <dpl/foreach.h>
29 #include <dpl/log/log.h>
30 #include <dpl/colors.h>
38 #include <dpl/utils/wrt_global_settings.h>
40 #include <dpl/singleton_impl.h>
41 IMPLEMENT_SINGLETON(DPL::Test::TestRunner)
45 namespace // anonymous
47 std::string BaseName(std::string aPath)
49 ScopedFree<char> path(strdup(aPath.c_str()));
50 if (NULL == path.Get()) {
51 throw std::bad_alloc();
53 char* baseName = basename(path.Get());
54 std::string retValue = baseName;
57 } // namespace anonymous
59 //! \brief Failed test message creator
61 //! \param[in] aTest string for tested expression
62 //! \param[in] aFile source file name
63 //! \param[in] aLine source file line
64 //! \param[in] aMessage error message
65 TestRunner::TestFailed::TestFailed(const char* aTest,
68 const std::string &aMessage)
70 std::ostringstream assertMsg;
71 assertMsg << "[" << BaseName(aFile) << ":" << aLine
72 << "] Assertion failed ("
73 << aTest << ") " << aMessage;
74 m_message = assertMsg.str();
77 TestRunner::TestFailed::TestFailed(const std::string &message)
82 void TestRunner::RegisterTest(const char *testName, TestCase proc)
84 m_testGroups[m_currentGroup].push_back(TestCaseStruct(testName, proc));
87 void TestRunner::InitGroup(const char* name)
89 m_currentGroup = name;
92 TestRunner::Status TestRunner::RunTestCase(const TestCaseStruct& testCase)
96 } catch (const TestFailed &e) {
97 // Simple test failure
98 CollectResult(testCase.name,
100 TestResultsCollectorBase::FailStatus::FAILED,
103 } catch (const Ignored &e) {
105 // Simple test have to be implemented
106 CollectResult(testCase.name,
108 TestResultsCollectorBase::FailStatus::IGNORED,
113 } catch (const DPL::Exception &e) {
114 // DPL exception failure
115 CollectResult(testCase.name,
117 TestResultsCollectorBase::FailStatus::INTERNAL,
118 "DPL exception:" + e.GetMessage());
121 } catch (const std::exception &) {
122 // std exception failure
123 CollectResult(testCase.name,
125 TestResultsCollectorBase::FailStatus::INTERNAL,
130 // Unknown exception failure
131 CollectResult(testCase.name,
133 TestResultsCollectorBase::FailStatus::INTERNAL,
134 "unknown exception");
139 CollectResult(testCase.name,
141 TestResultsCollectorBase::FailStatus::NONE);
147 void TestRunner::RunTests()
149 using namespace DPL::Colors::Text;
152 std::for_each(m_collectors.begin(),
154 [] (const TestResultsCollectors::value_type & collector)
156 collector.second->Start();
159 fprintf(stderr, "%s%s%s\n", GREEN_BEGIN, "Running tests...", GREEN_END);
160 FOREACH(group, m_testGroups) {
161 TestCaseStructList list = group->second;
164 m_collectors.begin(),
166 [&group](const TestResultsCollectors::value_type & collector)
169 CollectCurrentTestGroupName(group->first);
173 for (TestCaseStructList::const_iterator iterator = list.begin();
174 iterator != list.end();
177 TestCaseStruct test = *iterator;
178 if (m_startTestId == test.name) {
182 if (m_startTestId.empty()) {
185 if (m_terminate == true) {
186 // Terminate quietly without any logs
193 std::for_each(m_collectors.begin(),
195 [] (const TestResultsCollectors::value_type & collector)
197 collector.second->Finish();
201 fprintf(stderr, "%s%s%s\n\n", GREEN_BEGIN, "Finished", GREEN_END);
204 void TestRunner::CollectResult(
205 const std::string& id,
206 const std::string& description,
207 const TestResultsCollectorBase::FailStatus::Type status,
208 const std::string& reason)
210 std::for_each(m_collectors.begin(),
212 [&](const TestResultsCollectors::value_type & collector)
214 collector.second->CollectResult(id,
221 void TestRunner::Banner()
223 using namespace DPL::Colors::Text;
237 void TestRunner::InvalidArgs(const std::string& message)
239 using namespace DPL::Colors::Text;
247 void TestRunner::Usage()
249 fprintf(stderr, "Usage: runner [options]\n\n");
250 fprintf(stderr, "Output type:\n");
251 fprintf(stderr, " --output=<output type> --output=<output type> ...\n");
252 fprintf(stderr, "\n possible output types:\n");
253 FOREACH(type, TestResultsCollectorBase::GetCollectorsNames()) {
254 fprintf(stderr, " --output=%s\n", type->c_str());
256 fprintf(stderr, "\n example:\n");
258 " test-binary --output=text --output=xml --file=output.xml\n\n");
259 fprintf(stderr, "Other parameters:\n");
261 " --regexp='regexp'\t Only selected tests"
262 " which names match regexp run\n\n");
263 fprintf(stderr, " --start=<test id>\tStart from concrete test id");
264 fprintf(stderr, " --group=<group name>\t Run tests only from one group\n");
265 fprintf(stderr, " --runignored\t Run also ignored tests\n");
266 fprintf(stderr, " --list\t Show a list of Test IDs\n");
267 fprintf(stderr, " --listgroups\t Show a list of Test Group names \n");
270 " --listingroup=<group name>\t Show a list of Test IDS in one group\n");
271 fprintf(stderr, " --help\t This help\n\n");
272 std::for_each(m_collectors.begin(),
274 [] (const TestResultsCollectors::value_type & collector)
277 "Output %s has specific args:\n",
278 collector.first.c_str());
282 CollectorSpecificHelp().c_str());
284 fprintf(stderr, "For bug reporting, please write to:\n");
285 fprintf(stderr, "<p.dobrowolsk@samsung.com>\n");
288 int TestRunner::ExecTestRunner(int argc, char *argv[])
290 std::vector<std::string> args;
291 for (int i = 0; i < argc; ++i) {
292 args.push_back(argv[i]);
294 return ExecTestRunner(args);
297 void TestRunner::MarkAssertion()
302 int TestRunner::ExecTestRunner(const ArgsList& value)
304 m_runIgnored = false;
305 ArgsList args = value;
306 // Parse command line
307 if (args.size() == 1) {
313 args.erase(args.begin());
315 bool showHelp = false;
317 TestResultsCollectorBasePtr currentCollector;
319 // Parse each argument
322 std::string arg = *it;
323 const std::string regexp = "--regexp=";
324 const std::string output = "--output=";
325 const std::string groupId = "--group=";
326 const std::string runIgnored = "--runignored";
327 const std::string listCmd = "--list";
328 const std::string startCmd = "--start=";
329 const std::string listGroupsCmd = "--listgroups";
330 const std::string listInGroup = "--listingroup=";
332 if (currentCollector) {
333 if (currentCollector->ParseCollectorSpecificArg(arg)) {
338 if (arg.find(startCmd) == 0) {
339 arg.erase(0, startCmd.length());
340 FOREACH(group, m_testGroups) {
341 FOREACH(tc, group->second) {
342 if (tc->name == arg) {
347 if (!m_startTestId.empty()) {
351 if (!m_startTestId.empty()) {
355 fprintf(stderr, "Start test id has not been found\n");
358 } else if (arg.find(groupId) == 0) {
359 arg.erase(0, groupId.length());
360 TestCaseGroupMap::iterator found = m_testGroups.find(arg);
361 if (found != m_testGroups.end()) {
362 std::string name = found->first;
363 TestCaseStructList newList = found->second;
364 m_testGroups.clear();
365 m_testGroups[name] = newList;
367 fprintf(stderr, "Group %s not found\n", arg.c_str());
372 } else if (arg == runIgnored) {
374 } else if (arg == listCmd) {
375 FOREACH(group, m_testGroups) {
376 FOREACH(test, group->second) {
377 printf("ID:%s:%s\n", group->first.c_str(), test->name.c_str());
381 } else if (arg == listGroupsCmd) {
382 FOREACH(group, m_testGroups) {
383 printf("GR:%s\n", group->first.c_str());
386 } else if (arg.find(listInGroup) == 0) {
387 arg.erase(0, listInGroup.length());
388 FOREACH(test, m_testGroups[arg]) {
389 printf("ID:%s\n", test->name.c_str());
392 } else if (arg == "--help") {
394 } else if (arg.find(output) == 0) {
395 arg.erase(0, output.length());
396 if (m_collectors.find(arg) != m_collectors.end()) {
398 "Multiple outputs of the same type are not supported!");
402 currentCollector.reset(TestResultsCollectorBase::Create(arg));
403 if (!currentCollector) {
404 InvalidArgs("Unsupported output type!");
408 m_collectors[arg] = currentCollector;
409 } else if (arg.find(regexp) == 0) {
410 arg.erase(0, regexp.length());
411 if (arg.length() == 0) {
417 if (arg[0] == '\'' && arg[arg.length() - 1] == '\'') {
419 arg.erase(arg.length() - 1);
422 if (arg.length() == 0) {
428 pcrecpp::RE re(arg.c_str());
429 FOREACH(group, m_testGroups) {
430 TestCaseStructList newList;
431 FOREACH(iterator, group->second)
433 if (re.PartialMatch(iterator->name)) {
434 newList.push_back(*iterator);
437 group->second = newList;
446 currentCollector.reset();
454 if (m_collectors.empty()) {
455 TestResultsCollectorBasePtr collector(
456 TestResultsCollectorBase::Create("text"));
457 m_collectors["text"] = collector;
460 for (auto it = m_collectors.begin(); it != m_collectors.end(); ++it) {
461 if (!it->second->Configure()) {
462 fprintf(stderr, "Could not configure selected output");
473 bool TestRunner::getRunIgnored() const
478 void TestRunner::terminate()