Add init and finish functionality
[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
236     std::string initReason;
237     TestResult::FailStatus initStatus = TryCatch(std::bind(&TestCase::Init, testCase),
238                                                  initReason);
239     if (initStatus != TestResult::FailStatus::NONE) {
240         CollectResult(testCase->GetName(),
241                       TestResult(initStatus, getConcatedFailReason(initReason), testCase->GetPerformance()));
242         setCurrentTestCase(nullptr);
243         return;
244     }
245
246     std::string testReason;
247     TestResult::FailStatus testStatus = TryCatch(std::bind(&TestCase::Test, testCase),
248                                                  testReason);
249     testReason = getConcatedFailReason(testReason);
250     std::string finishReason;
251     TestResult::FailStatus finishStatus = TryCatch(std::bind(&TestCase::Finish, testCase),
252                                                    finishReason);
253     finishReason = getConcatedFailReason(finishReason);
254
255     switch (finishStatus) {
256         case TestResult::FailStatus::FAILED:
257             testStatus = TestResult::FailStatus::FAILED;
258             if (!testReason.empty())
259                 testReason += "\n";
260             testReason += finishReason;
261             break;
262         case TestResult::FailStatus::IGNORED:
263             if (testStatus == TestResult::FailStatus::NONE)
264                 testStatus = TestResult::FailStatus::IGNORED;
265             if (!testReason.empty())
266                 testReason += "\n";
267             testReason += finishReason;
268         case TestResult::FailStatus::NONE:
269             break;
270         default:
271             Assert(false && "Unhandled fail status");
272     }
273
274     CollectResult(testCase->GetName(),
275                   TestResult(testStatus, testReason, testCase->GetPerformance()));
276     setCurrentTestCase(nullptr);
277 }
278
279 void TestRunner::RunTests()
280 {
281     using namespace DPL::Colors::Text;
282
283     Banner();
284     for (auto &collector : m_collectors) {
285         collector.second->Start();
286     }
287
288     unsigned count = 0;
289     for (auto &group : m_testGroups) {
290         count += group.second.size();
291     }
292     fprintf(stderr, "%sFound %d testcases...%s\n", GREEN_BEGIN, count, GREEN_END);
293     fprintf(stderr, "%s%s%s\n", GREEN_BEGIN, "Running tests...", GREEN_END);
294     for (auto &group : m_testGroups) {
295         TestCaseList list = group.second;
296         if (!list.empty()) {
297             for (auto &collector : m_collectors) {
298                 collector.second->CollectCurrentTestGroupName(group.first);
299             }
300             list.sort();
301
302             for (TestCaseList::const_iterator iterator = list.begin();
303                  iterator != list.end();
304                  ++iterator)
305             {
306                 TestCasePtr test = *iterator;
307                 if (m_startTestId == test->GetName()) {
308                     m_startTestId = "";
309                 }
310
311                 if (m_startTestId.empty()) {
312                     RunTestCase(test);
313                 }
314                 if (m_terminate == true) {
315                     // Terminate quietly without any logs
316                     return;
317                 }
318             }
319         }
320     }
321
322     std::for_each(m_collectors.begin(),
323                   m_collectors.end(),
324                   [] (const TestResultsCollectors::value_type & collector)
325                   {
326                       collector.second->Finish();
327                   });
328
329     // Finished
330     fprintf(stderr, "%s%s%s\n\n", GREEN_BEGIN, "Finished", GREEN_END);
331 }
332
333 TestCasePtr TestRunner::getCurrentTestCase()
334 {
335     return m_currentTestCase;
336 }
337
338 void TestRunner::setCurrentTestCase(TestCasePtr testCase)
339 {
340     m_currentTestCase = testCase;
341 }
342
343 void TestRunner::beginPerformance(std::chrono::system_clock::duration maxDurationInMicroseconds)
344 {
345     TestCasePtr testCase = getCurrentTestCase();
346     if (!testCase)
347         return;
348
349     if (!testCase->GetPerformance())
350         testCase->SetPerformance(
351             std::unique_ptr<PerformanceResult>                  \
352             (new PerformanceResult(maxDurationInMicroseconds)));
353 }
354
355 void TestRunner::endPerformance()
356 {
357     TestCasePtr testCase = getCurrentTestCase();
358     if (!testCase)
359         return;
360
361     testCase->GetPerformance()->Finish();
362 }
363
364 ConstPerformanceResultPtr TestRunner::getCurrentTestCasePerformanceResult()
365 {
366     TestCasePtr testCase = getCurrentTestCase();
367     if (!testCase)
368         return nullptr;
369
370     return testCase->GetPerformance();
371 }
372
373 void TestRunner::setCurrentTestCasePerformanceResult(const PerformanceResultPtr &performance)
374 {
375     TestCasePtr testCase = getCurrentTestCase();
376     if (!testCase)
377         return;
378
379     testCase->SetPerformance(performance);
380 }
381
382 void TestRunner::addFailReason(const std::string &reason)
383 {
384     m_failReason.push(reason);
385 }
386
387 std::string TestRunner::getConcatedFailReason(const std::string &reason)
388 {
389     std::string ret;
390     while (!m_failReason.empty())
391     {
392         ret += m_failReason.front();
393         m_failReason.pop();
394     }
395     return reason + ret;
396 }
397
398 TestRunner::~TestRunner()
399 {
400     for(auto &t : m_testCaseSet)
401         delete t;
402 }
403
404 void TestRunner::CollectResult(const std::string& id, const TestResult& result)
405 {
406     if (result.GetFailStatus() == TestResult::FailStatus::IGNORED && m_runIgnored)
407         return;
408
409     std::for_each(m_collectors.begin(),
410                   m_collectors.end(),
411                   [&](const TestResultsCollectors::value_type & collector)
412                   {
413                       collector.second->CollectResult(id, result);
414                   });
415 }
416
417 void TestRunner::Banner()
418 {
419     using namespace DPL::Colors::Text;
420     fprintf(stderr,
421             "%s%s%s\n",
422             BOLD_GREEN_BEGIN,
423             "DPL tests runner",
424             BOLD_GREEN_END);
425     fprintf(stderr,
426             "%s%s%s%s\n\n",
427             GREEN_BEGIN,
428             "Build: ",
429             __TIMESTAMP__,
430             GREEN_END);
431 }
432
433 void TestRunner::InvalidArgs(const std::string& message)
434 {
435     using namespace DPL::Colors::Text;
436     fprintf(stderr,
437             "%s%s%s\n",
438             BOLD_RED_BEGIN,
439             message.c_str(),
440             BOLD_RED_END);
441 }
442
443 void TestRunner::Usage()
444 {
445     fprintf(stderr, "Usage: runner [options]\n\n");
446     fprintf(stderr, "Output type:\n");
447     fprintf(stderr, "  --output=<output type> --output=<output type> ...\n");
448     fprintf(stderr, "\n  possible output types:\n");
449     for (std::string &type : TestResultsCollectorBase::GetCollectorsNames()) {
450         fprintf(stderr, "    --output=%s\n", type.c_str());
451     }
452     fprintf(stderr, "\n  example:\n");
453     fprintf(stderr,
454             "    test-binary --output=text --output=xml --file=output.xml\n\n");
455     fprintf(stderr, "Other parameters:\n");
456     fprintf(stderr,
457             "  --regexp='regexp'\t Only selected tests"
458             " which names match regexp run\n\n");
459     fprintf(stderr, "  --start=<test id>\tStart from concrete test id");
460     fprintf(stderr, "  --group=<group name>\t Run tests only from one group\n");
461     fprintf(stderr, "  --runignored\t Run also ignored tests\n");
462     fprintf(stderr, "  --list\t Show a list of Test IDs\n");
463     fprintf(stderr, "  --listgroups\t Show a list of Test Group names \n");
464     fprintf(stderr, "  --only-from-xml=<xml file>\t Run only testcases specified in XML file \n"
465                     "       XML name is taken from attribute id=\"part1_part2\" as whole.\n"
466                     "       If part1 is not found (no _) then it is implicitily "
467                            "set according to suite part1 from binary tests\n");
468     fprintf(
469         stderr,
470         "  --listingroup=<group name>\t Show a list of Test IDS in one group\n");
471     fprintf(stderr, "  --allowchildlogs\t Allow to print logs from child process on screen.\n");
472     fprintf(stderr, "       When active child process will be able to print logs on stdout and stderr.\n");
473     fprintf(stderr, "       Both descriptors will be closed after test.\n");
474     fprintf(stderr, "  --help\t This help\n\n");
475     std::for_each(m_collectors.begin(),
476                   m_collectors.end(),
477                   [] (const TestResultsCollectors::value_type & collector)
478                   {
479                       fprintf(stderr,
480                               "Output %s has specific args:\n",
481                               collector.first.c_str());
482                       fprintf(stderr,
483                               "%s\n",
484                               collector.second->
485                                   CollectorSpecificHelp().c_str());
486                   });
487     fprintf(stderr, "For bug reporting, please write to:\n");
488     fprintf(stderr, "<p.dobrowolsk@samsung.com>\n");
489 }
490
491 int TestRunner::ExecTestRunner(int argc, char *argv[])
492 {
493     std::vector<std::string> args;
494     for (int i = 0; i < argc; ++i) {
495         args.push_back(argv[i]);
496     }
497     return ExecTestRunner(args);
498 }
499
500 int TestRunner::ExecTestRunner(ArgsList args)
501 {
502     m_runIgnored = false;
503     // Parse command line
504
505     args.erase(args.begin());
506
507     bool showHelp = false;
508     bool justList = false;
509     std::vector<std::string> xmlFiles;
510
511     TestResultsCollectorBasePtr currentCollector;
512
513     // Parse each argument
514     for(std::string &arg : args)
515     {
516         const std::string regexp = "--regexp=";
517         const std::string output = "--output=";
518         const std::string groupId = "--group=";
519         const std::string runIgnored = "--runignored";
520         const std::string listCmd = "--list";
521         const std::string startCmd = "--start=";
522         const std::string listGroupsCmd = "--listgroups";
523         const std::string listInGroup = "--listingroup=";
524         const std::string allowChildLogs = "--allowchildlogs";
525         const std::string onlyFromXML = "--only-from-xml=";
526
527         if (currentCollector) {
528             if (currentCollector->ParseCollectorSpecificArg(arg)) {
529                 continue;
530             }
531         }
532
533         if (arg.find(startCmd) == 0) {
534             arg.erase(0, startCmd.length());
535             for (auto &group : m_testGroups) {
536                 for (auto &tc : group.second) {
537                     if (tc->GetName() == arg) {
538                         m_startTestId = arg;
539                         break;
540                     }
541                 }
542                 if (!m_startTestId.empty()) {
543                     break;
544                 }
545             }
546             if (!m_startTestId.empty()) {
547                 continue;
548             }
549             InvalidArgs();
550             fprintf(stderr, "Start test id has not been found\n");
551             Usage();
552             return 0;
553         } else if (arg.find(groupId) == 0) {
554             arg.erase(0, groupId.length());
555             TestCaseGroupMap::iterator found = m_testGroups.find(arg);
556             if (found != m_testGroups.end()) {
557                 std::string name = found->first;
558                 TestCaseList newList = found->second;
559                 m_testGroups.clear();
560                 m_testGroups[name] = newList;
561             } else {
562                 fprintf(stderr, "Group %s not found\n", arg.c_str());
563                 InvalidArgs();
564                 Usage();
565                 return -1;
566             }
567         } else if (arg == runIgnored) {
568             m_runIgnored = true;
569         } else if (arg == listCmd) {
570             justList = true;
571         } else if (arg == listGroupsCmd) {
572             for (auto &group : m_testGroups) {
573                 printf("GR:%s\n", group.first.c_str());
574             }
575             return 0;
576         } else if (arg.find(listInGroup) == 0) {
577             arg.erase(0, listInGroup.length());
578             for (auto &test : m_testGroups[arg]) {
579                 printf("ID:%s\n", test->GetName().c_str());
580             }
581             return 0;
582         } else if (arg.find(allowChildLogs) == 0) {
583             arg.erase(0, allowChildLogs.length());
584             m_allowChildLogs = true;
585         } else if (arg == "--help") {
586             showHelp = true;
587         } else if (arg.find(output) == 0) {
588             arg.erase(0, output.length());
589             if (m_collectors.find(arg) != m_collectors.end()) {
590                 InvalidArgs(
591                     "Multiple outputs of the same type are not supported!");
592                 Usage();
593                 return -1;
594             }
595             currentCollector.reset(TestResultsCollectorBase::Create(arg));
596             if (!currentCollector) {
597                 InvalidArgs("Unsupported output type!");
598                 Usage();
599                 return -1;
600             }
601             m_collectors[arg] = currentCollector;
602         } else if (arg.find(regexp) == 0) {
603             arg.erase(0, regexp.length());
604             if (arg.length() == 0) {
605                 InvalidArgs();
606                 Usage();
607                 return -1;
608             }
609
610             if (arg[0] == '\'' && arg[arg.length() - 1] == '\'') {
611                 arg.erase(0);
612                 arg.erase(arg.length() - 1);
613             }
614
615             if (arg.length() == 0) {
616                 InvalidArgs();
617                 Usage();
618                 return -1;
619             }
620
621             pcrecpp::RE re(arg.c_str());
622             for (auto &group : m_testGroups) {
623                 TestCaseList newList;
624                 for (auto &tc : group.second)
625                 {
626                     if (re.PartialMatch(tc->GetName())) {
627                         newList.push_back(tc);
628                     }
629                 }
630                 group.second = newList;
631             }
632         } else if(arg.find(onlyFromXML) == 0) {
633             arg.erase(0, onlyFromXML.length());
634             if (arg.length() == 0) {
635                 InvalidArgs();
636                 Usage();
637                 return -1;
638             }
639
640             if (arg[0] == '\'' && arg[arg.length() - 1] == '\'') {
641                 arg.erase(0);
642                 arg.erase(arg.length() - 1);
643             }
644
645             if (arg.length() == 0) {
646                 InvalidArgs();
647                 Usage();
648                 return -1;
649             }
650
651             xmlFiles.push_back(arg);
652         } else {
653             InvalidArgs();
654             Usage();
655             return -1;
656         }
657     }
658
659     if(!xmlFiles.empty())
660     {
661         if(!filterGroupsByXmls(xmlFiles))
662         {
663             fprintf(stderr, "XML file is not correct\n");
664             return 0;
665         }
666     }
667
668     if(justList)
669     {
670         for (auto &group : m_testGroups) {
671             for (auto &tc : group.second) {
672                 printf("ID:%s:%s\n", group.first.c_str(), tc->GetName().c_str());
673             }
674         }
675         return 0;
676     }
677
678     currentCollector.reset();
679
680     // Show help
681     if (showHelp) {
682         Usage();
683         return 0;
684     }
685
686     if (m_collectors.empty()) {
687         TestResultsCollectorBasePtr collector(
688             TestResultsCollectorBase::Create("text"));
689         m_collectors["text"] = collector;
690     }
691
692     for (auto &collector : m_collectors) {
693         if (!collector.second->Configure()) {
694             fprintf(stderr, "Could not configure selected output");
695             return 0;
696         }
697     }
698
699     // Run tests
700     RunTests();
701
702     return 0;
703 }
704
705 void TestRunner::Terminate()
706 {
707     m_terminate = true;
708 }
709
710 bool TestRunner::GetAllowChildLogs()
711 {
712     return m_allowChildLogs;
713 }
714
715 void TestRunner::deferFailedException(const DPL::Test::TestFailed &ex)
716 {
717     if (m_deferDeepness <= 0)
718         throw ex;
719
720     if (m_deferredExceptionsMessages.empty()) {
721         m_firstDeferredFail = ex;
722         m_firstDeferredExceptionType = DeferredExceptionType::DEFERRED_FAILED;
723     }
724     m_deferredExceptionsMessages.push_back(ex.GetMessage());
725 }
726
727 void TestRunner::deferIgnoredException(const DPL::Test::TestIgnored &ex)
728 {
729     if (m_deferDeepness <= 0)
730         throw ex;
731
732     if (m_deferredExceptionsMessages.empty()) {
733         m_firstDeferredIgnore = ex;
734         m_firstDeferredExceptionType = DeferredExceptionType::DEFERRED_IGNORED;
735     }
736     m_deferredExceptionsMessages.push_back(ex.GetMessage());
737 }
738
739 void TestRunner::deferBegin()
740 {
741     m_deferDeepness++;
742 }
743
744 void TestRunner::deferEnd()
745 {
746     if (m_deferDeepness > 0)
747         m_deferDeepness--;
748
749     if (m_deferDeepness > 0)
750         return;
751
752     bool oops = std::uncaught_exception();
753     size_t additionalExceptions = oops ? 0 : 1;
754     for (size_t i = additionalExceptions; i < m_deferredExceptionsMessages.size(); ++i)
755         addFailReason(m_deferredExceptionsMessages[i]);
756
757     if (!oops && !m_deferredExceptionsMessages.empty())
758     {
759         m_deferredExceptionsMessages.clear();
760         switch (m_firstDeferredExceptionType) {
761             case DeferredExceptionType::DEFERRED_FAILED:
762                 throw m_firstDeferredFail;
763             case DeferredExceptionType::DEFERRED_IGNORED:
764                 throw m_firstDeferredIgnore;
765         }
766     }
767     m_deferredExceptionsMessages.clear();
768 }
769
770 } // namespace Test
771 } // namespace DPL