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