Fix casting from and to void*
[platform/core/test/security-tests.git] / src / framework / src / test_runner.cpp
1 /*
2  * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 /**
17  * @file        test_runner.cpp
18  * @author      Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
19  * @author      Lukasz Wrzosek (l.wrzosek@samsung.com)
20  * @version     1.0
21  * @brief       This file is the implementation file of test runner
22  */
23 #include <stddef.h>
24 #include <dpl/test/test_failed.h>
25 #include <dpl/test/test_ignored.h>
26 #include <dpl/test/test_runner.h>
27 #include <dpl/test/test_results_collector.h>
28 #include <dpl/exception.h>
29 #include <dpl/scoped_free.h>
30 #include <dpl/log/log.h>
31 #include <dpl/colors.h>
32 #include <pcrecpp.h>
33 #include <algorithm>
34 #include <cstdio>
35 #include <memory.h>
36
37 #include <libxml/xpath.h>
38 #include <libxml/xpathInternals.h>
39 #include <libxml/parser.h>
40 #include <libxml/tree.h>
41
42 #include <dpl/singleton_impl.h>
43 IMPLEMENT_SINGLETON(DPL::Test::TestRunner)
44
45 namespace {
46
47 std::string getXMLNode(xmlNodePtr node)
48 {
49     std::string ret;
50     xmlChar * value = xmlNodeGetContent(node);
51     ret = std::string(reinterpret_cast<char*>(value));
52     xmlFree(value);
53     return ret;
54 }
55
56 }
57
58
59 namespace DPL {
60 namespace Test {
61
62 void TestRunner::RegisterTest(const char *testName, TestCase proc)
63 {
64     m_testGroups[m_currentGroup].push_back(TestCaseStruct(testName, proc));
65 }
66
67 void TestRunner::InitGroup(const char* name)
68 {
69     m_currentGroup = name;
70 }
71
72 void TestRunner::normalizeXMLTag(std::string& str, const std::string& testcase)
73 {
74     //Add testcase if missing
75     std::string::size_type pos = str.find(testcase);
76     if(pos != 0)
77     {
78         str = testcase + "_" + str;
79     }
80
81     //dpl test runner cannot have '-' character in name so it have to be replaced
82     // for TCT case to make comparision works
83     std::replace(str.begin(), str.end(), '-', '_');
84 }
85
86 bool TestRunner::filterGroupsByXmls(const std::vector<std::string> & files)
87 {
88     DECLARE_EXCEPTION_TYPE(DPL::Exception, XMLError)
89
90     const std::string idPath = "/test_definition/suite/set/testcase/@id";
91
92     bool success = true;
93     std::map<std::string, bool> casesMap;
94
95     std::string testsuite;
96     if(!m_testGroups.empty())
97     {
98         for(TestCaseGroupMap::const_iterator cit = m_testGroups.begin(); cit != m_testGroups.end(); ++cit)
99         {
100             if(!cit->second.empty())
101             {
102                 for(TestCaseStructList::const_iterator cj = cit->second.begin(); cj != cit->second.end(); ++cj)
103                 {
104                     std::string name = cj->name;
105                     std::string::size_type st = name.find('_');
106                     if(st != std::string::npos)
107                     {
108                         name = name.substr(0, st);
109                         testsuite = name;
110                         break;
111                     }
112                 }
113                 if(!testsuite.empty()) break;
114             }
115         }
116     }
117
118     xmlInitParser();
119     LIBXML_TEST_VERSION
120     xmlXPathInit();
121
122     Try
123     {
124         for (const std::string &file : files)
125         {
126             xmlDocPtr doc;
127             xmlXPathContextPtr xpathCtx;
128
129             doc = xmlReadFile(file.c_str(), nullptr, 0);
130             if (doc == nullptr) {
131                 ThrowMsg(XMLError, "File Problem");
132             } else {
133                 //context
134                 xpathCtx = xmlXPathNewContext(doc);
135                 if (xpathCtx == nullptr) {
136                     ThrowMsg(XMLError,
137                              "Error: unable to create new XPath context\n");
138                 }
139                 xpathCtx->node = xmlDocGetRootElement(doc);
140             }
141
142             std::string result;
143             xmlXPathObjectPtr xpathObject;
144             //get requested node's values
145             xpathObject = xmlXPathEvalExpression(BAD_CAST idPath.c_str(), xpathCtx);
146             if (xpathObject == nullptr)
147             {
148                 ThrowMsg(XMLError, "XPath evaluation failure: " << idPath);
149             }
150             xmlNodeSetPtr nodes = xpathObject->nodesetval;
151             unsigned size = (nodes) ? nodes->nodeNr : 0;
152             LogDebug("Found " << size << " nodes matching xpath");
153             for(unsigned i = 0; i < size; ++i)
154             {
155                 LogPedantic("Type: " << nodes->nodeTab[i]->type);
156                 if (nodes->nodeTab[i]->type == XML_ATTRIBUTE_NODE) {
157                     xmlNodePtr curNode = nodes->nodeTab[i];
158                     result = getXMLNode(curNode);
159                     LogPedantic("Result: " << result);
160                     normalizeXMLTag(result, testsuite);
161                     casesMap.insert(make_pair(result, false));
162                 }
163             }
164             //Cleanup of XPath data
165             xmlXPathFreeObject(xpathObject);
166             xmlXPathFreeContext(xpathCtx);
167             xmlFreeDoc(doc);
168         }
169     }
170     Catch(XMLError)
171     {
172         LogError("Libxml error: " << _rethrown_exception.DumpToString());
173         success = false;
174     }
175     xmlCleanupParser();
176
177     if(!filterByXML(casesMap))
178     {
179         success = false;
180     }
181
182     return success;
183 }
184
185 bool TestRunner::filterByXML(std::map<std::string, bool> & casesMap)
186 {
187     for (auto &group : m_testGroups) {
188         TestCaseStructList newList;
189         for (auto &tc : group.second)
190         {
191             if (casesMap.find(tc.name) != casesMap.end()) {
192                 casesMap[tc.name] = true;
193                 newList.push_back(tc);
194             }
195         }
196         group.second = newList;
197     }
198     for (auto &cs : casesMap)
199     {
200         if(cs.second == false)
201         {
202             LogError("Cannot find testcase from XML file: " << cs.first);
203             return false;
204         }
205     }
206     return true;
207 }
208
209 TestRunner::Status TestRunner::RunTestCase(const TestCaseStruct& testCase)
210 {
211     setCurrentTestCase(&(const_cast<TestCaseStruct &>(testCase)));
212     m_deferDeepness = 0U;
213     try {
214         testCase.proc();
215     } catch (const TestFailed &e) {
216         // Simple test failure
217         CollectResult(testCase.name,
218                       TestResultsCollectorBase::FailStatus::FAILED,
219                       getConcatedFailReason(e.GetMessage()));
220
221         setCurrentTestCase(nullptr);
222         return FAILED;
223     } catch (const TestIgnored &e) {
224         if (m_runIgnored) {
225             // Simple test have to be implemented
226             CollectResult(testCase.name,
227                           TestResultsCollectorBase::FailStatus::IGNORED,
228                           e.GetMessage());
229         }
230
231         setCurrentTestCase(nullptr);
232         return IGNORED;
233     } catch (const std::exception &) {
234         // std exception failure
235         CollectResult(testCase.name,
236                       TestResultsCollectorBase::FailStatus::FAILED,
237                       "std exception");
238
239         setCurrentTestCase(nullptr);
240         return FAILED;
241     } catch (...) {
242         // Unknown exception failure
243         CollectResult(testCase.name,
244                       TestResultsCollectorBase::FailStatus::FAILED,
245                       "unknown exception");
246
247         setCurrentTestCase(nullptr);
248         return FAILED;
249     }
250
251     CollectResult(testCase.name,
252                   TestResultsCollectorBase::FailStatus::NONE,
253                   "",
254                   testCase.m_isPerformanceTest,
255                   testCase.m_performanceTestDurationTime,
256                   testCase.m_performanceMaxTime);
257     setCurrentTestCase(nullptr);
258
259     // Everything OK
260     return PASS;
261 }
262
263 void TestRunner::RunTests()
264 {
265     using namespace DPL::Colors::Text;
266
267     Banner();
268     for (auto &collector : m_collectors) {
269         collector.second->Start();
270     }
271
272     unsigned count = 0;
273     for (auto &group : m_testGroups) {
274         count += group.second.size();
275     }
276     fprintf(stderr, "%sFound %d testcases...%s\n", GREEN_BEGIN, count, GREEN_END);
277     fprintf(stderr, "%s%s%s\n", GREEN_BEGIN, "Running tests...", GREEN_END);
278     for (auto &group : m_testGroups) {
279         TestCaseStructList list = group.second;
280         if (!list.empty()) {
281             for (auto &collector : m_collectors) {
282                 collector.second->CollectCurrentTestGroupName(group.first);
283             }
284             list.sort();
285
286             for (TestCaseStructList::const_iterator iterator = list.begin();
287                  iterator != list.end();
288                  ++iterator)
289             {
290                 TestCaseStruct test = *iterator;
291                 if (m_startTestId == test.name) {
292                     m_startTestId = "";
293                 }
294
295                 if (m_startTestId.empty()) {
296                     RunTestCase(test);
297                 }
298                 if (m_terminate == true) {
299                     // Terminate quietly without any logs
300                     return;
301                 }
302             }
303         }
304     }
305
306     std::for_each(m_collectors.begin(),
307                   m_collectors.end(),
308                   [] (const TestResultsCollectors::value_type & collector)
309                   {
310                       collector.second->Finish();
311                   });
312
313     // Finished
314     fprintf(stderr, "%s%s%s\n\n", GREEN_BEGIN, "Finished", GREEN_END);
315 }
316
317 TestRunner::TestCaseStruct *TestRunner::getCurrentTestCase()
318 {
319     return m_currentTestCase;
320 }
321
322 void TestRunner::setCurrentTestCase(TestCaseStruct* testCase)
323 {
324     m_currentTestCase = testCase;
325 }
326
327 void TestRunner::beginPerformanceTestTime(std::chrono::system_clock::duration maxTimeInMicroseconds)
328 {
329     TestCaseStruct* testCase = getCurrentTestCase();
330     if (!testCase)
331         return;
332
333     testCase->m_isPerformanceTest = true;
334     testCase->m_performanceMaxTime = maxTimeInMicroseconds;
335     testCase->m_performanceTestStartTime = std::chrono::system_clock::now();
336
337     // Set result to 0 microseconds. Display 0ms result when end macro is missing.
338     testCase->m_performanceTestDurationTime = std::chrono::microseconds::zero();
339 }
340
341 void TestRunner::endPerformanceTestTime()
342 {
343     TestCaseStruct* testCase = getCurrentTestCase();
344     if (!testCase)
345         return;
346
347     testCase->m_performanceTestDurationTime = std::chrono::system_clock::now() -
348             testCase->m_performanceTestStartTime;
349 }
350
351 void TestRunner::getCurrentTestCasePerformanceResult(bool& isPerformanceTest,
352                                                      std::chrono::system_clock::duration& result,
353                                                      std::chrono::system_clock::duration& resultMax)
354 {
355     TestCaseStruct* testCase = getCurrentTestCase();
356     if (!testCase || !(testCase->m_isPerformanceTest)){
357         isPerformanceTest = false;
358         return;
359     }
360
361     isPerformanceTest = testCase->m_isPerformanceTest;
362     result = testCase->m_performanceTestDurationTime;
363     resultMax = testCase->m_performanceMaxTime;
364 }
365
366 void TestRunner::setCurrentTestCasePerformanceResult(bool isPerformanceTest,
367                                                      std::chrono::system_clock::duration result,
368                                                      std::chrono::system_clock::duration resultMax)
369 {
370     TestCaseStruct* testCase = getCurrentTestCase();
371     if (!testCase)
372         return;
373
374     testCase->m_isPerformanceTest = isPerformanceTest;
375     testCase->m_performanceTestDurationTime = result;
376     testCase->m_performanceMaxTime = resultMax;
377 }
378
379 void TestRunner::addFailReason(const std::string &reason)
380 {
381     m_failReason.push(reason);
382 }
383
384 std::string TestRunner::getConcatedFailReason(const std::string &reason)
385 {
386     std::string ret;
387     while (!m_failReason.empty())
388     {
389         ret += m_failReason.front();
390         m_failReason.pop();
391     }
392     return reason + ret;
393 }
394
395 void TestRunner::CollectResult(
396     const std::string& id,
397     const TestResultsCollectorBase::FailStatus status,
398     const std::string& reason,
399     const bool& isPerformanceTest,
400     const std::chrono::system_clock::duration& performanceTestDurationTime,
401     const std::chrono::system_clock::duration& performanceMaxTime)
402 {
403     std::for_each(m_collectors.begin(),
404                   m_collectors.end(),
405                   [&](const TestResultsCollectors::value_type & collector)
406                   {
407                       collector.second->CollectResult(id,
408                                                       status,
409                                                       reason,
410                                                       isPerformanceTest,
411                                                       performanceTestDurationTime,
412                                                       performanceMaxTime);
413                   });
414 }
415
416 void TestRunner::Banner()
417 {
418     using namespace DPL::Colors::Text;
419     fprintf(stderr,
420             "%s%s%s\n",
421             BOLD_GREEN_BEGIN,
422             "DPL tests runner",
423             BOLD_GREEN_END);
424     fprintf(stderr,
425             "%s%s%s%s\n\n",
426             GREEN_BEGIN,
427             "Build: ",
428             __TIMESTAMP__,
429             GREEN_END);
430 }
431
432 void TestRunner::InvalidArgs(const std::string& message)
433 {
434     using namespace DPL::Colors::Text;
435     fprintf(stderr,
436             "%s%s%s\n",
437             BOLD_RED_BEGIN,
438             message.c_str(),
439             BOLD_RED_END);
440 }
441
442 void TestRunner::Usage()
443 {
444     fprintf(stderr, "Usage: runner [options]\n\n");
445     fprintf(stderr, "Output type:\n");
446     fprintf(stderr, "  --output=<output type> --output=<output type> ...\n");
447     fprintf(stderr, "\n  possible output types:\n");
448     for (std::string &type : TestResultsCollectorBase::GetCollectorsNames()) {
449         fprintf(stderr, "    --output=%s\n", type.c_str());
450     }
451     fprintf(stderr, "\n  example:\n");
452     fprintf(stderr,
453             "    test-binary --output=text --output=xml --file=output.xml\n\n");
454     fprintf(stderr, "Other parameters:\n");
455     fprintf(stderr,
456             "  --regexp='regexp'\t Only selected tests"
457             " which names match regexp run\n\n");
458     fprintf(stderr, "  --start=<test id>\tStart from concrete test id");
459     fprintf(stderr, "  --group=<group name>\t Run tests only from one group\n");
460     fprintf(stderr, "  --runignored\t Run also ignored tests\n");
461     fprintf(stderr, "  --list\t Show a list of Test IDs\n");
462     fprintf(stderr, "  --listgroups\t Show a list of Test Group names \n");
463     fprintf(stderr, "  --only-from-xml=<xml file>\t Run only testcases specified in XML file \n"
464                     "       XML name is taken from attribute id=\"part1_part2\" as whole.\n"
465                     "       If part1 is not found (no _) then it is implicitily "
466                            "set according to suite part1 from binary tests\n");
467     fprintf(
468         stderr,
469         "  --listingroup=<group name>\t Show a list of Test IDS in one group\n");
470     fprintf(stderr, "  --allowchildlogs\t Allow to print logs from child process on screen.\n");
471     fprintf(stderr, "       When active child process will be able to print logs on stdout and stderr.\n");
472     fprintf(stderr, "       Both descriptors will be closed after test.\n");
473     fprintf(stderr, "  --help\t This help\n\n");
474     std::for_each(m_collectors.begin(),
475                   m_collectors.end(),
476                   [] (const TestResultsCollectors::value_type & collector)
477                   {
478                       fprintf(stderr,
479                               "Output %s has specific args:\n",
480                               collector.first.c_str());
481                       fprintf(stderr,
482                               "%s\n",
483                               collector.second->
484                                   CollectorSpecificHelp().c_str());
485                   });
486     fprintf(stderr, "For bug reporting, please write to:\n");
487     fprintf(stderr, "<p.dobrowolsk@samsung.com>\n");
488 }
489
490 int TestRunner::ExecTestRunner(int argc, char *argv[])
491 {
492     std::vector<std::string> args;
493     for (int i = 0; i < argc; ++i) {
494         args.push_back(argv[i]);
495     }
496     return ExecTestRunner(args);
497 }
498
499 void TestRunner::MarkAssertion()
500 {
501     ++m_totalAssertions;
502 }
503
504 int TestRunner::ExecTestRunner(ArgsList args)
505 {
506     m_runIgnored = false;
507     // Parse command line
508
509     args.erase(args.begin());
510
511     bool showHelp = false;
512     bool justList = false;
513     std::vector<std::string> xmlFiles;
514
515     TestResultsCollectorBasePtr currentCollector;
516
517     // Parse each argument
518     for(std::string &arg : args)
519     {
520         const std::string regexp = "--regexp=";
521         const std::string output = "--output=";
522         const std::string groupId = "--group=";
523         const std::string runIgnored = "--runignored";
524         const std::string listCmd = "--list";
525         const std::string startCmd = "--start=";
526         const std::string listGroupsCmd = "--listgroups";
527         const std::string listInGroup = "--listingroup=";
528         const std::string allowChildLogs = "--allowchildlogs";
529         const std::string onlyFromXML = "--only-from-xml=";
530
531         if (currentCollector) {
532             if (currentCollector->ParseCollectorSpecificArg(arg)) {
533                 continue;
534             }
535         }
536
537         if (arg.find(startCmd) == 0) {
538             arg.erase(0, startCmd.length());
539             for (auto &group : m_testGroups) {
540                 for (auto &tc : group.second) {
541                     if (tc.name == arg) {
542                         m_startTestId = arg;
543                         break;
544                     }
545                 }
546                 if (!m_startTestId.empty()) {
547                     break;
548                 }
549             }
550             if (!m_startTestId.empty()) {
551                 continue;
552             }
553             InvalidArgs();
554             fprintf(stderr, "Start test id has not been found\n");
555             Usage();
556             return 0;
557         } else if (arg.find(groupId) == 0) {
558             arg.erase(0, groupId.length());
559             TestCaseGroupMap::iterator found = m_testGroups.find(arg);
560             if (found != m_testGroups.end()) {
561                 std::string name = found->first;
562                 TestCaseStructList newList = found->second;
563                 m_testGroups.clear();
564                 m_testGroups[name] = newList;
565             } else {
566                 fprintf(stderr, "Group %s not found\n", arg.c_str());
567                 InvalidArgs();
568                 Usage();
569                 return -1;
570             }
571         } else if (arg == runIgnored) {
572             m_runIgnored = true;
573         } else if (arg == listCmd) {
574             justList = true;
575         } else if (arg == listGroupsCmd) {
576             for (auto &group : m_testGroups) {
577                 printf("GR:%s\n", group.first.c_str());
578             }
579             return 0;
580         } else if (arg.find(listInGroup) == 0) {
581             arg.erase(0, listInGroup.length());
582             for (auto &test : m_testGroups[arg]) {
583                 printf("ID:%s\n", test.name.c_str());
584             }
585             return 0;
586         } else if (arg.find(allowChildLogs) == 0) {
587             arg.erase(0, allowChildLogs.length());
588             m_allowChildLogs = true;
589         } else if (arg == "--help") {
590             showHelp = true;
591         } else if (arg.find(output) == 0) {
592             arg.erase(0, output.length());
593             if (m_collectors.find(arg) != m_collectors.end()) {
594                 InvalidArgs(
595                     "Multiple outputs of the same type are not supported!");
596                 Usage();
597                 return -1;
598             }
599             currentCollector.reset(TestResultsCollectorBase::Create(arg));
600             if (!currentCollector) {
601                 InvalidArgs("Unsupported output type!");
602                 Usage();
603                 return -1;
604             }
605             m_collectors[arg] = currentCollector;
606         } else if (arg.find(regexp) == 0) {
607             arg.erase(0, regexp.length());
608             if (arg.length() == 0) {
609                 InvalidArgs();
610                 Usage();
611                 return -1;
612             }
613
614             if (arg[0] == '\'' && arg[arg.length() - 1] == '\'') {
615                 arg.erase(0);
616                 arg.erase(arg.length() - 1);
617             }
618
619             if (arg.length() == 0) {
620                 InvalidArgs();
621                 Usage();
622                 return -1;
623             }
624
625             pcrecpp::RE re(arg.c_str());
626             for (auto &group : m_testGroups) {
627                 TestCaseStructList newList;
628                 for (auto &tc : group.second)
629                 {
630                     if (re.PartialMatch(tc.name)) {
631                         newList.push_back(tc);
632                     }
633                 }
634                 group.second = newList;
635             }
636         } else if(arg.find(onlyFromXML) == 0) {
637             arg.erase(0, onlyFromXML.length());
638             if (arg.length() == 0) {
639                 InvalidArgs();
640                 Usage();
641                 return -1;
642             }
643
644             if (arg[0] == '\'' && arg[arg.length() - 1] == '\'') {
645                 arg.erase(0);
646                 arg.erase(arg.length() - 1);
647             }
648
649             if (arg.length() == 0) {
650                 InvalidArgs();
651                 Usage();
652                 return -1;
653             }
654
655             xmlFiles.push_back(arg);
656         } else {
657             InvalidArgs();
658             Usage();
659             return -1;
660         }
661     }
662
663     if(!xmlFiles.empty())
664     {
665         if(!filterGroupsByXmls(xmlFiles))
666         {
667             fprintf(stderr, "XML file is not correct\n");
668             return 0;
669         }
670     }
671
672     if(justList)
673     {
674         for (auto &group : m_testGroups) {
675             for (auto &tc : group.second) {
676                 printf("ID:%s:%s\n", group.first.c_str(), tc.name.c_str());
677             }
678         }
679         return 0;
680     }
681
682     currentCollector.reset();
683
684     // Show help
685     if (showHelp) {
686         Usage();
687         return 0;
688     }
689
690     if (m_collectors.empty()) {
691         TestResultsCollectorBasePtr collector(
692             TestResultsCollectorBase::Create("text"));
693         m_collectors["text"] = collector;
694     }
695
696     for (auto &collector : m_collectors) {
697         if (!collector.second->Configure()) {
698             fprintf(stderr, "Could not configure selected output");
699             return 0;
700         }
701     }
702
703     // Run tests
704     RunTests();
705
706     return 0;
707 }
708
709 bool TestRunner::getRunIgnored() const
710 {
711     return m_runIgnored;
712 }
713
714 void TestRunner::Terminate()
715 {
716     m_terminate = true;
717 }
718
719 bool TestRunner::GetAllowChildLogs()
720 {
721     return m_allowChildLogs;
722 }
723
724 void TestRunner::deferFailedException(const DPL::Test::TestFailed &ex)
725 {
726     if (m_deferDeepness <= 0)
727         throw ex;
728
729     if (m_deferredExceptionsMessages.empty()) {
730         m_firstDeferredFail = ex;
731         m_firstDeferredExceptionType = DeferredExceptionType::DEFERRED_FAILED;
732     }
733     m_deferredExceptionsMessages.push_back(ex.GetMessage());
734 }
735
736 void TestRunner::deferIgnoredException(const DPL::Test::TestIgnored &ex)
737 {
738     if (m_deferDeepness <= 0)
739         throw ex;
740
741     if (m_deferredExceptionsMessages.empty()) {
742         m_firstDeferredIgnore = ex;
743         m_firstDeferredExceptionType = DeferredExceptionType::DEFERRED_IGNORED;
744     }
745     m_deferredExceptionsMessages.push_back(ex.GetMessage());
746 }
747
748 void TestRunner::deferBegin()
749 {
750     m_deferDeepness++;
751 }
752
753 void TestRunner::deferEnd()
754 {
755     if (m_deferDeepness > 0)
756         m_deferDeepness--;
757
758     if (m_deferDeepness > 0)
759         return;
760
761     bool oops = std::uncaught_exception();
762     size_t additionalExceptions = oops ? 0 : 1;
763     for (size_t i = additionalExceptions; i < m_deferredExceptionsMessages.size(); ++i)
764         addFailReason(m_deferredExceptionsMessages[i]);
765
766     if (!oops && !m_deferredExceptionsMessages.empty())
767     {
768         m_deferredExceptionsMessages.clear();
769         switch (m_firstDeferredExceptionType) {
770             case DeferredExceptionType::DEFERRED_FAILED:
771                 throw m_firstDeferredFail;
772             case DeferredExceptionType::DEFERRED_IGNORED:
773                 throw m_firstDeferredIgnore;
774         }
775     }
776     m_deferredExceptionsMessages.clear();
777 }
778
779 } // namespace Test
780 } // namespace DPL