/**
  * \brief Initializes object
  * Resets counters and clears all stored test results.
  */
 virtual void init()
 {
     ok_count = 0;
     exceptions_count = 0;
     failures_count = 0;
     terminations_count = 0;
     warnings_count = 0;
     all_tests.clear();
 }
 /**
  * \brief Callback function
  * This function is called before the first test is executed. It initializes counters.
  */
 virtual void run_started()
 {
     ok_count = 0;
     exceptions_count = 0;
     failures_count = 0;
     terminations_count = 0;
     warnings_count = 0;
     all_tests_.clear();
 }
    /**
     * \brief Callback function
     * This function is called when all tests are completed. It generates XML output
     * to file(s). File name base can be set with constructor.
     */
    virtual void run_completed()
    {
        /* *********************** header ***************************** */
        *stream_ << "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" << std::endl;
        *stream_ << "<testsuites>" << std::endl;

        // iterate over all test groups
        for (TestGroups::const_iterator tgi = all_tests_.begin(); tgi != all_tests_.end(); ++tgi)
        {
            /* per-group statistics */
            int passed = 0;         // passed in single group
            int exceptions = 0;     // exceptions in single group
            int failures = 0;       // failures in single group
            int terminations = 0;   // terminations in single group
            int warnings = 0;       // warnings in single group
            int errors = 0;         // errors in single group


            // output is written to string stream buffer, because JUnit format <testsuite> tag
            // contains statistics, which aren't known yet
            std::ostringstream out;

            // iterate over all test cases in the current test group
            const TestResults &results = tgi->second;
            for (TestResults::const_iterator tri = results.begin(); tri != results.end(); ++tri)
            {
                std::string failure_type;    // string describing the failure type
                std::string failure_msg;     // a string with failure message

                switch (tri->result)
                {
                    case test_result::ok:
                    case test_result::skipped:
                        passed++;
                        break;
                    case test_result::fail:
                        failure_type = "Assertion";
                        failure_msg  = "";
                        failures++;
                        break;
                    case test_result::ex:
                        failure_type = "Assertion";
                        failure_msg  = "Thrown exception: " + tri->exception_typeid + '\n';
                        exceptions++;
                        break;
                    case test_result::warn:
                        failure_type = "Assertion";
                        failure_msg  = "Destructor failed.\n";
                        warnings++;
                        break;
                    case test_result::term:
                        failure_type = "Error";
                        failure_msg  = "Test application terminated abnormally.\n";
                        terminations++;
                        break;
                    case test_result::ex_ctor:
                        failure_type = "Assertion";
                        failure_msg  = "Constructor has thrown an exception: " + tri->exception_typeid + ".\n";
                        exceptions++;
                        break;
                    case test_result::rethrown:
                        failure_type = "Assertion";
                        failure_msg  = "Child failed.\n";
                        failures++;
                        break;
                    default:
                        failure_type = "Error";
                        failure_msg  = "Unknown test status, this should have never happened. "
                                       "You may just have found a bug in TUT, please report it immediately.\n";
                        errors++;
                        break;
                } // switch

#if defined(TUT_USE_POSIX)
                out << xml_build_testcase(*tri, failure_type, failure_msg, tri->pid) << std::endl;
#else
                out << xml_build_testcase(*tri, failure_type, failure_msg) << std::endl;
#endif
            } // iterate over all test cases

            // calculate per-group statistics
            int stat_errors = terminations + errors;
            int stat_failures = failures + warnings + exceptions;
            int stat_all = stat_errors + stat_failures + passed;

            *stream_ << xml_build_testsuite(stat_errors, stat_failures, stat_all, (*tgi).first/* name */, out.str()/* testcases */) << std::endl;
        } // iterate over all test groups

        *stream_ << "</testsuites>" << std::endl;
    }
    /**
     * \brief Callback function
     * This function is called when all tests are completed. It generates XML output
     * to file(s). File name base can be set with \ref setFilenameBase.
     */
    virtual void run_completed()
    {
        using std::endl;
        using std::string;

        static int number = 1;  // results file sequence number (testResult_<number>.xml)

        // iterate over all test groups
        TestGroups::const_iterator tgi;
        for (tgi = all_tests.begin(); tgi != all_tests.end(); ++tgi) {
            /* per-group statistics */
            int passed = 0;         // passed in single group
            int exceptions = 0;     // exceptions in single group
            int failures = 0;       // failures in single group
            int terminations = 0;   // terminations in single group
            int warnings = 0;       // warnings in single group
            int errors = 0;     // errors in single group

            /* generate output filename */
            char fn[256];
            sprintf(fn, "%s_%d.xml", filename.c_str(), number++);

            std::ofstream xmlfile;
            xmlfile.open(fn, std::ios::in | std::ios::trunc);
            if (!xmlfile.is_open()) {
                throw (std::runtime_error("Cannot open file for output"));
            }

            /* *********************** header ***************************** */
            xmlfile << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl;

            // output is written to string stream buffer, because JUnit format <testsuite> tag
            // contains statistics, which aren't known yet
            std::ostringstream out;

            // iterate over all test cases in the current test group
            TestResults::const_iterator tri;
            for (tri = (*tgi).second.begin(); tri != (*tgi).second.end(); ++tri) {
                string failure_type;    // string describing the failure type
                string failure_msg;     // a string with failure message

                switch ((*tri).result) {
                    case test_result::ok:
                        passed++;
                        break;
                    case test_result::fail:
                        failure_type = "Assertion";
                        failure_msg  = "";
                        failures++;
                        break;
                    case test_result::ex:
                        failure_type = "Assertion";
                        failure_msg  = "Thrown exception: " + (*tri).exception_typeid + '\n';
                        exceptions++;
                        break;
                    case test_result::warn:
                        failure_type = "Assertion";
                        failure_msg  = "Destructor failed.\n";
                        warnings++;
                        break;
                    case test_result::term:
                        failure_type = "Error";
                        failure_msg  = "Test application terminated abnormally.\n";
                        terminations++;
                        break;
                    case test_result::ex_ctor:
                        failure_type = "Assertion";
                        failure_msg  = "Constructor has thrown an exception: " + (*tri).exception_typeid + '\n';
                        exceptions++;
                        break;
                    case test_result::rethrown:
                        failure_type = "Assertion";
                        failure_msg  = "Child failed";
                        failures++;
                        break;
                    default:
                        failure_type = "Error";
                        failure_msg  = "Unknown test status, this should have never happened. "
                                "You may just have found a BUG in TUT XML reporter, please report it immediately.\n";
                        errors++;
                        break;
                } // switch

#if defined(TUT_USE_POSIX)
                out << xml_build_testcase(*tri, failure_type, failure_msg, (*tri).pid) << endl;
#else
                out << xml_build_testcase(*tri, failure_type, failure_msg) << endl;
#endif

            } // iterate over all test cases

            // calculate per-group statistics
            int stat_errors = terminations + errors;
            int stat_failures = failures + warnings + exceptions;
            int stat_all = stat_errors + stat_failures + passed;

            xmlfile << xml_build_testsuite(stat_errors, stat_failures, stat_all, (*tgi).first/* name */, out.str()/* testcases */) << endl;
            xmlfile.close();
        } // iterate over all test groups
    }