Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r83557 - in trunk/tools/regression: build src/report xsl_reports
From: steven_at_[hidden]
Date: 2013-03-25 11:47:19


Author: steven_watanabe
Date: 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
New Revision: 83557
URL: http://svn.boost.org/trac/boost/changeset/83557

Log:
Initial replacement for the xsl report generation.
Added:
   trunk/tools/regression/src/report/
   trunk/tools/regression/src/report/add_expected_results.cpp (contents, props changed)
   trunk/tools/regression/src/report/add_expected_results.hpp (contents, props changed)
   trunk/tools/regression/src/report/boost_report.cpp (contents, props changed)
   trunk/tools/regression/src/report/common.cpp (contents, props changed)
   trunk/tools/regression/src/report/common.hpp (contents, props changed)
   trunk/tools/regression/src/report/html.cpp (contents, props changed)
   trunk/tools/regression/src/report/html.hpp (contents, props changed)
   trunk/tools/regression/src/report/html_writer.hpp (contents, props changed)
   trunk/tools/regression/src/report/issues_page.cpp (contents, props changed)
   trunk/tools/regression/src/report/issues_page.hpp (contents, props changed)
   trunk/tools/regression/src/report/links_page.cpp (contents, props changed)
   trunk/tools/regression/src/report/links_page.hpp (contents, props changed)
   trunk/tools/regression/src/report/produce_expected_results.cpp (contents, props changed)
   trunk/tools/regression/src/report/produce_expected_results.hpp (contents, props changed)
   trunk/tools/regression/src/report/result_page.cpp (contents, props changed)
   trunk/tools/regression/src/report/result_page.hpp (contents, props changed)
   trunk/tools/regression/src/report/runners.cpp (contents, props changed)
   trunk/tools/regression/src/report/runners.hpp (contents, props changed)
   trunk/tools/regression/src/report/summary_page.cpp (contents, props changed)
   trunk/tools/regression/src/report/summary_page.hpp (contents, props changed)
   trunk/tools/regression/src/report/xml.cpp (contents, props changed)
   trunk/tools/regression/src/report/xml.hpp (contents, props changed)
   trunk/tools/regression/src/report/zip.hpp (contents, props changed)
Text files modified:
   trunk/tools/regression/build/Jamroot.jam | 17 +++++++++++++++++
   trunk/tools/regression/xsl_reports/boost_wide_report.py | 29 +++++++++++++++++++++++++++++
   trunk/tools/regression/xsl_reports/build_results.sh | 22 +++++++++++++++-------
   3 files changed, 61 insertions(+), 7 deletions(-)

Modified: trunk/tools/regression/build/Jamroot.jam
==============================================================================
--- trunk/tools/regression/build/Jamroot.jam (original)
+++ trunk/tools/regression/build/Jamroot.jam 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
@@ -82,3 +82,20 @@
     release
     ;
 explicit library_status ;
+
+exe boost_report
+ :
+ [ glob report/*.cpp ]
+ /boost/filesystem//boost_filesystem/<link>static
+ /boost//filesystem/<link>static
+ /boost//date_time/<link>static
+ /boost//regex/<link>static
+ /boost//program_options/<link>static
+ /boost//iostreams/<link>static
+ :
+ <define>BOOST_ALL_NO_LIB=1
+ <use>/boost//headers
+ :
+ release
+ ;
+explicit boost_report ;

Added: trunk/tools/regression/src/report/add_expected_results.cpp
==============================================================================
--- (empty file)
+++ trunk/tools/regression/src/report/add_expected_results.cpp 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
@@ -0,0 +1,213 @@
+// Copyright MetaCommunications, Inc. 2003-2007.
+// Copyright Steven Watanabe 2010
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "add_expected_results.hpp"
+#include "common.hpp"
+#include "xml.hpp"
+#include <string>
+#include <boost/foreach.hpp>
+#include <boost/functional/hash.hpp>
+
+using namespace boost::regression;
+
+bool target_result(const test_structure_t::test_log_t& test_log, const std::string& name) {
+ boost::unordered_map<std::string, test_structure_t::target_t>::const_iterator pos = test_log.targets.find(name);
+ if(pos != test_log.targets.end()) {
+ return pos->second.result;
+ } else {
+ return false;
+ }
+}
+
+bool is_test_log_complete(const test_structure_t::test_log_t& test_log) {
+ // FIXME: The original XSL function is buggy and
+ // Boost.Build relies on its behavior
+ return true;
+ if(test_log.test_type == "compile" || test_log.test_type == "compile_fail" ||
+ !target_result(test_log, "compile")) {
+ return test_log.targets.count("compile") == 1 &&
+ test_log.targets.count("link") == 0 &&
+ test_log.targets.count("run") == 0;
+ } else if(test_log.test_type == "link" || test_log.test_type == "link_fail" ||
+ test_log.test_type == "" || test_log.test_type == "lib" ||
+ !target_result(test_log, "link")) {
+ return test_log.targets.count("compile") == 1 &&
+ test_log.targets.count("link") == 1 &&
+ test_log.targets.count("run") == 0;
+ } else if(test_log.test_type == "run" || test_log.test_type == "run_fail" ||
+ test_log.test_type == "run_pyd" || test_log.test_type == "run_mpi") {
+ return test_log.targets.count("compile") == 1 &&
+ test_log.targets.count("link") == 1 &&
+ test_log.targets.count("run") == 1;
+ } else {
+ throw std::runtime_error("Unknown test type " + test_log.test_type);
+ }
+}
+
+std::string get_toolset_name(const std::string& toolset, const expected_results_t& expected_results) {
+ expected_results_t::toolset_aliases_t::const_iterator pos = expected_results.toolset_aliases.find(toolset);
+ if(pos != expected_results.toolset_aliases.end()) {
+ return pos->second;
+ } else {
+ return toolset;
+ }
+}
+
+void add_note(test_structure_t::test_log_t& test_log, const std::string& text, const std::string& class_name = "auto-note") {
+ test_log.notes.push_back("<span class=\"" + class_name + "\">" + text + "</span>");
+}
+
+void process_test_log(test_structure_t::test_log_t& test_log,
+ const failures_markup_t& failures_markup,
+ const expected_results_t& expected_results) {
+
+ bool is_complete = is_test_log_complete(test_log);
+
+ bool has_failures = false;
+ typedef boost::unordered_map<std::string, test_structure_t::target_t>::const_reference target_ref;
+ BOOST_FOREACH(target_ref target, test_log.targets) {
+ if(!target.second.result) {
+ has_failures = true;
+ break;
+ }
+ }
+
+ bool actual_result = !(has_failures || !is_complete);
+
+ std::string toolset_name = get_toolset_name(test_log.toolset, expected_results);
+
+ const bool* expected_results_test_case = 0;
+ {
+ test_case_t test_id;
+ test_id.library = test_log.library;
+ test_id.test_name = test_log.test_name;
+ test_id.toolset_name = toolset_name;
+ expected_results_t::tests_t::const_iterator pos = expected_results.tests.find(test_id);
+ if(pos != expected_results.tests.end()) {
+ expected_results_test_case = &pos->second;
+ }
+ }
+
+ std::string category = "0";
+ node_ptr test_failures_markup = 0;
+ {
+ boost::unordered_map<std::string, node_ptr>::const_iterator pos = failures_markup.libraries.find(test_log.library);
+ if(pos != failures_markup.libraries.end()) {
+ node_ptr library_markup = pos->second;
+ FOR_EACH_ELEMENT(elem, library_markup) {
+ if(check_name(elem, "test")) {
+ std::string test_name;
+ if(lookup_attr(elem, "name", test_name) && re_match(test_name, test_log.test_name)) {
+ lookup_attr(elem, "category", category);
+ FOR_EACH_ELEMENT(mark_failure, elem) {
+ FOR_EACH_ELEMENT(toolset, mark_failure) {
+ std::string toolset_name;
+ if(lookup_attr(toolset, "name", toolset_name) && re_match(toolset_name, test_log.toolset)) {
+ test_failures_markup = mark_failure;
+ goto found_explicit_failure_markup;
+ }
+ }
+ }
+ }
+ } else if(check_name(elem, "mark-expected-failures")) {
+ bool has_test = false;
+ bool has_toolset = false;
+ FOR_EACH_ELEMENT(subelem, elem) {
+ std::string name;
+ bool has_name = lookup_attr(subelem, "name", name);
+ if(has_name && check_name(subelem, "test") && re_match(name, test_log.test_name)) {
+ has_test = true;
+ } else if(has_name && check_name(subelem, "toolset") && re_match(name, test_log.toolset)) {
+ has_toolset = true;
+ }
+ if(has_toolset && has_test) {
+ test_failures_markup = elem;
+ goto found_explicit_failure_markup;
+ }
+ }
+ }
+ }
+ }
+ found_explicit_failure_markup:;
+ }
+
+ bool is_new = (expected_results_test_case == 0);
+ bool has_explicit_markup = (test_failures_markup != 0);
+
+ bool expected_result = !(has_explicit_markup || (expected_results_test_case && !*expected_results_test_case));
+
+ bool status = (expected_result == actual_result);
+
+ bool unexpected_success = (expected_result == false && actual_result == true);
+ std::string expected_reason;
+ lookup_attr(test_failures_markup, "reason", expected_reason);
+
+ if(unexpected_success && has_explicit_markup) {
+ add_note(test_log,
+ "This test case was explicitly marked up in \n"
+ "<a href=\"http://svn.boost.org/svn/boost/{$source}/status/explicit-failures-markup.xml\">\n"
+ " status/explicit-failures-markup.xml</a> file in the Boost SVN as \"expected to fail\",\n"
+ "but is passing. Please consult the notes/output below for more details.\n");
+ }
+ if(has_explicit_markup && lookup_element(test_failures_markup, "note") == 0) {
+ if(unexpected_success) {
+ add_note(test_log,
+ "No explanation was provided for this markup. Please contact the library \n"
+ "author(s)/maintainer(s) for more details.\n");
+ } else {
+ add_note(test_log,
+ "This failure was explicitly marked as expected in \n"
+ "<a href=\"http://svn.boost.org/svn/boost/{$source}/status/explicit-failures-markup.xml\">\n"
+ "status/explicit-failures-markup.xml</a> file in the Boost SVN. \n"
+ "Please contact the library author(s)/maintainer(s) for the explanation of this markup.\n");
+ }
+ }
+ if(node_ptr elem = lookup_element(test_failures_markup, "note")) {
+ test_log.notes.push_back(elem);
+ }
+
+ if(expected_results_test_case && !*expected_results_test_case) {
+ if(unexpected_success) {
+ add_note(test_log,
+ "This test case used to fail in the reference (\"last-known-good\") release.\n");
+ } else {
+ add_note(test_log,
+ "This failure was present in the reference (\"last-known-good\") release.\n");
+ }
+ }
+
+ if(!is_complete && !has_failures) {
+ add_note(test_log,
+ "<b>[Reporting Tools Internal Error]</b> This test case's XML is missing one or more log entries\n"
+ "of the regression run's steps associated with the test case's type (\"" + test_log.test_type + "\").\n"
+ "Please <a href=\"mailto:mailto:boost-testing_at_[hidden]\">contact reporting tools \n"
+ "maintainers</a> about this problem.\n", "internal-error-note");
+ }
+
+ test_log.result = actual_result;
+ test_log.expected_result = expected_result;
+ test_log.expected_reason = expected_reason;
+ test_log.status = status;
+ test_log.is_new = is_new;
+ test_log.category = category;
+}
+
+void boost::regression::add_expected_results(
+ test_structure_t::run_t& tests,
+ const failures_markup_t& failures_markup,
+ const expected_results_t& expected_results)
+{
+ BOOST_FOREACH(test_structure_t::toolset_group_t::reference toolset, tests.toolsets) {
+ BOOST_FOREACH(test_structure_t::toolset_t::reference library, toolset.second) {
+ BOOST_FOREACH(test_structure_t::library_t::reference test_case, library.second) {
+ BOOST_FOREACH(test_structure_t::test_case_t::reference test_log, test_case.second) {
+ process_test_log(test_log, failures_markup, expected_results);
+ }
+ }
+ }
+ }
+}

Added: trunk/tools/regression/src/report/add_expected_results.hpp
==============================================================================
--- (empty file)
+++ trunk/tools/regression/src/report/add_expected_results.hpp 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
@@ -0,0 +1,25 @@
+// add_expected_results.hpp
+//
+// Copyright (c) 2010 Steven Watanabe
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanyiong file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef ADD_EXPECTED_RESULTS_HPP_INCLUDED
+#define ADD_EXPECTED_RESULTS_HPP_INCLUDED
+
+#include "xml.hpp"
+
+namespace boost {
+namespace regression {
+
+void add_expected_results(
+ test_structure_t::run_t& tests,
+ const failures_markup_t& failures_markup,
+ const expected_results_t& expected_results);
+
+}
+}
+
+#endif

Added: trunk/tools/regression/src/report/boost_report.cpp
==============================================================================
--- (empty file)
+++ trunk/tools/regression/src/report/boost_report.cpp 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
@@ -0,0 +1,177 @@
+// boost_report.cpp
+//
+// Copyright (c) 2013
+// Steven Watanabe
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENCE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "issues_page.hpp"
+#include "links_page.hpp"
+#include "result_page.hpp"
+#include "issues_page.hpp"
+#include "summary_page.hpp"
+#include "add_expected_results.hpp"
+#include "produce_expected_results.hpp"
+#include "runners.hpp"
+#include "xml.hpp"
+
+#include <boost/shared_ptr.hpp>
+#include <boost/date_time/posix_time/ptime.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/date_time/posix_time/posix_time_io.hpp>
+#include <boost/foreach.hpp>
+#include <boost/exception/exception.hpp>
+#include <boost/exception/diagnostic_information.hpp>
+#include <boost/program_options.hpp>
+#include <iostream>
+#include <fstream>
+
+using namespace boost::regression;
+
+boost::shared_ptr<boost::zip::zip_archive> global_zip;
+
+int main(int argc, char* argv[]) {
+ boost::program_options::options_description desc;
+ boost::program_options::variables_map vm;
+ desc.add_options()
+ ("input-file", boost::program_options::value<std::vector<std::string> >(), "Runner XML files")
+ ("expected,e", boost::program_options::value<std::string>()->required(), "Expected results file")
+ ("markup,m", boost::program_options::value<std::string>()->required(), "Failures markup file")
+ ("tag", boost::program_options::value<std::string>()->required(), "the tag for the results (i.e. 'trunk')")
+ ("run-date", boost::program_options::value<boost::posix_time::ptime>()->default_value(boost::posix_time::second_clock::universal_time()), "the timestamp of the report")
+ ("reports,r", boost::program_options::value<std::vector<std::string> >(), "The reports to generate")
+ ("css", boost::program_options::value<std::string>(), "The CSS file")
+ ("help,h", "produce a help message")
+ ;
+
+ boost::program_options::positional_options_description p;
+ p.add("input-file", -1);
+
+ try {
+
+ boost::program_options::store(boost::program_options::command_line_parser(argc, argv)
+ .options(desc).positional(p).run(), vm);
+ boost::program_options::notify(vm);
+
+ boost::posix_time::ptime now = vm["run-date"].as<boost::posix_time::ptime>();
+ std::string tag = vm["tag"].as<std::string>();
+ std::set<std::string> reports;
+ if(vm.count("reports")) {
+ BOOST_FOREACH(const std::string& report, vm["reports"].as<std::vector<std::string> >())
+ reports.insert(report);
+ }
+ std::vector<std::string> warnings;
+
+ test_structure_t structure;
+ failures_markup_t markup;
+ expected_results_t expected;
+ std::vector<test_structure_t::run_t*> runs;
+
+ std::cout << "Reading expected results" << std::endl;
+ boost::shared_ptr<document_type> expected_results = read_xml_file(vm["expected"].as<std::string>().c_str());
+ load_expected_results(&*expected_results, expected);
+
+ std::cout << "Reading failures markup" << std::endl;
+ boost::shared_ptr<document_type> failures_markup = read_xml_file(vm["markup"].as<std::string>().c_str());
+ load_failures_markup(&*failures_markup, markup);
+
+ std::ofstream zip_file("report.zip", std::ios_base::binary);
+ zip_file.exceptions(std::ios_base::failbit);
+ global_zip.reset(new boost::zip::zip_archive(zip_file));
+
+ if(vm.count("input-file")) {
+ BOOST_FOREACH(const std::string& file, vm["input-file"].as<std::vector<std::string> >()) {
+ boost::shared_ptr<document_type> test_results;
+ try {
+ std::cout << "Reading " << file << std::endl;
+ test_results = read_xml_file(file.c_str());
+ load_test_structure(&*test_results, structure, runs);
+ test_structure_t::run_t* test_run = runs.back();
+ std::cout << "Merging expected results" << std::endl;
+ add_expected_results(*test_run, markup, expected);
+ std::cout << "Generating links pages" << std::endl;
+ // must be run before test_results is discarded
+ if(reports.count("l"))
+ links_page(now, markup, *test_run);
+ } catch(std::ios_base::failure& e) {
+ std::cerr << e.what() << std::endl;
+ } catch(boost::property_tree::detail::rapidxml::parse_error& e) {
+ std::cerr << e.what() << std::endl;
+ }
+ }
+ }
+
+ std::vector<std::string> modes;
+ modes.push_back("developer");
+ modes.push_back("user");
+
+ if (reports.count("i") != 0) {
+ std::cout << "Generating issues page" << std::endl;
+ issues_list("developer", structure, markup,
+ true, tag, now, warnings, "");
+ }
+
+ BOOST_FOREACH(const std::string& mode, modes) {
+ if(reports.count(mode.substr(0, 1) + "d"))
+ result_page(structure, markup,
+ false, tag, now, warnings, mode, "comment.html");
+ }
+
+ BOOST_FOREACH(const std::string& mode, modes) {
+ if(reports.count(mode.substr(0, 1) + "s"))
+ summary_page(mode, tag, now, std::vector<std::string>(),
+ structure, markup, false);
+ }
+
+ BOOST_FOREACH(const std::string& mode, modes) {
+ if(reports.count(mode.substr(0, 1) + "dr"))
+ result_page(structure, markup,
+ true, tag, now, warnings, mode, "comment.html");
+ }
+
+ BOOST_FOREACH(const std::string& mode, modes) {
+ if(reports.count(mode.substr(0, 1) + "sr"))
+ summary_page(mode, tag, now, std::vector<std::string>(),
+ structure, markup, true);
+ }
+
+ if (reports.count("e")) {
+ produce_expected_results(structure);
+ }
+
+ if(reports.count("n")) {
+ runners(structure);
+ }
+
+ if(vm.count("css")) {
+ std::cout << "Writing file master.css" << std::endl;
+ html_writer css("master.css");
+ std::string filename = vm["css"].as<std::string>();
+ std::ifstream input(filename.c_str());
+ if (input) {
+ std::string data(std::istreambuf_iterator<char>(input.rdbuf()), std::istreambuf_iterator<char>());
+ css << data;
+ } else {
+ std::cerr << "warning: Could not open file: " << filename << std::endl;
+ }
+ }
+
+ global_zip.reset();
+
+ } catch(boost::program_options::error& e) {
+ if(vm.count("help")) {
+ std::cerr << desc << std::endl;
+ } else {
+ std::cerr << e.what() << std::endl;
+ return EXIT_FAILURE;
+ }
+ } catch(boost::exception& e) {
+ std::cerr << boost::diagnostic_information(e) << std::endl;
+ return EXIT_FAILURE;
+ } catch(std::exception& e) {
+ std::cerr << e.what() << std::endl;
+ return EXIT_FAILURE;
+ }
+}

Added: trunk/tools/regression/src/report/common.cpp
==============================================================================
--- (empty file)
+++ trunk/tools/regression/src/report/common.cpp 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
@@ -0,0 +1,659 @@
+// Copyright MetaCommunications, Inc. 2003-2005.
+// Copyright Steven Watanabe 2010
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "common.hpp"
+#include "xml.hpp"
+#include "html.hpp"
+
+#include <boost/regex.hpp>
+#include <boost/foreach.hpp>
+#include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string/classification.hpp>
+#include <boost/date_time/posix_time/posix_time_io.hpp>
+#include <algorithm>
+#include <set>
+
+using namespace boost::regression;
+
+std::string boost::regression::alternate_mode(const std::string& mode) {
+ if(mode == "user") {
+ return "developer";
+ } else {
+ return "user";
+ }
+}
+
+std::string boost::regression::release_postfix(bool is_release) {
+ if(is_release) {
+ return "_release";
+ } else {
+ return "";
+ }
+}
+
+// safe
+void boost::regression::get_libraries(const test_structure_t& test_structure, std::set<std::string>& out) {
+ typedef boost::unordered_map<std::string, test_structure_t::platform_t>::const_reference outer_elem;
+ BOOST_FOREACH(outer_elem platform, test_structure.platforms) {
+ BOOST_FOREACH(test_structure_t::platform_t::const_reference run, platform.second) {
+ BOOST_FOREACH(test_structure_t::toolset_group_t::const_reference toolset, run.toolsets) {
+ BOOST_FOREACH(test_structure_t::toolset_t::const_reference library, toolset.second) {
+ out.insert(library.first);
+ }
+ }
+ }
+ }
+}
+
+#if 0
+
+ <func:function name="meta:test_case_status">
+ <xsl:param name="explicit_markup"/>
+ <xsl:param name="test_log"/>
+
+ <xsl:variable name="status">
+ <xsl:choose>
+ <xsl:when test="meta:is_unusable( $explicit_markup, $test_log/@library, $test_log/@toolset )">
+ <xsl:text>unusable</xsl:text>
+ </xsl:when>
+ <xsl:when test="$test_log/@result='fail' and $test_log/@status='unexpected' and $test_log/@is-new='no'">
+ <xsl:text>fail-unexpected</xsl:text>
+ </xsl:when>
+ <xsl:when test="$test_log/@result='fail' and $test_log/@status='unexpected' and $test_log/@is-new='yes'">
+ <xsl:text>fail-unexpected-new</xsl:text>
+ </xsl:when>
+ <xsl:when test="$test_log/@result='success' and $test_log/@status='unexpected'">
+ <xsl:text>success-unexpected</xsl:text>
+ </xsl:when>
+ <xsl:when test="$test_log/@status='expected'">
+ <xsl:text>expected</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>other</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <func:result select="$status"/>
+ </func:function>
+
+ <func:function name="meta:is_toolset_required">
+ <xsl:param name="toolset"/>
+ <func:result select="count( $explicit_markup/explicit-failures-markup/mark-toolset[ @name = $toolset and @status='required' ] ) > 0"/>
+ </func:function>
+
+#endif
+
+bool boost::regression::is_library_beta(const failures_markup_t& explicit_markup, const std::string& library) {
+ boost::unordered_map<std::string, node_ptr>::const_iterator pos = explicit_markup.libraries.find(library);
+ if(pos != explicit_markup.libraries.end()) {
+ return check_attr(pos->second, "status", "beta");
+ }
+ return false;
+}
+
+bool boost::regression::is_test_log_a_test_case(const test_structure_t::test_log_t& test_log) {
+ const std::string& type = test_log.test_type;
+ return type == "compile" || type == "compile_fail" || type == "link" || type == "link_fail" ||
+ type == "run" || type == "run_fail" || type == "run_pyd" || type == "run_mpi";
+}
+
+// Does not assume any constraints on contents of the strings
+bool boost::regression::is_unusable(const failures_markup_t& markup, const std::string& library, const std::string& toolset) {
+ boost::unordered_map<std::string, node_ptr>::const_iterator pos = markup.libraries.find(library);
+ if(pos != markup.libraries.end()) {
+ FOR_EACH_ELEMENT(mark_unusable, pos->second) {
+ if(check_name(mark_unusable, "mark-unusable")) {
+ FOR_EACH_ELEMENT(toolset_node, mark_unusable) {
+ std::string name;
+ if(lookup_attr(toolset_node, "name", name) && re_match(name, toolset)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+void boost::regression::get_unusable(const failures_markup_t& markup,
+ const std::string& library,
+ const test_structure_t& test_structure,
+ boost::unordered_map<std::string, std::size_t>& out,
+ std::vector<node_ptr>& notes) {
+ boost::unordered_map<std::string, node_ptr>::const_iterator pos = markup.libraries.find(library);
+ if(pos != markup.libraries.end()) {
+ FOR_EACH_ELEMENT(mark_unusable, pos->second) {
+ if(check_name(mark_unusable, "mark-unusable")) {
+ node_ptr note = 0;
+ std::vector<std::string> toolsets;
+ FOR_EACH_ELEMENT(toolset_node, mark_unusable) {
+ std::string name;
+ if(check_name(toolset_node, "toolset") && lookup_attr(toolset_node, "name", name)) {
+ BOOST_FOREACH(test_structure_t::platform_group_t::const_reference platform, test_structure.platforms) {
+ BOOST_FOREACH(test_structure_t::platform_t::const_reference run, platform.second) {
+ BOOST_FOREACH(test_structure_t::toolset_group_t::const_reference toolset, run.toolsets) {
+ if(re_match(name, toolset.first)) {
+ toolsets.push_back(toolset.first);
+ }
+ }
+ }
+ }
+ } else if(check_name(toolset_node, "note")) {
+ note = toolset_node;
+ }
+ }
+ if(note != 0 && !toolsets.empty()) {
+ notes.push_back(note);
+ BOOST_FOREACH(const std::string& toolset, toolsets) {
+ out[toolset] = notes.size();
+ }
+ }
+ }
+ }
+ }
+}
+
+// There are no restrictions on the pattern or the
+// string. The only special character in the pattern
+// is '*', which matches any number of consecutive characters.
+bool boost::regression::re_match(const std::string& pattern, const std::string& text) {
+ std::string regex_str;
+ std::string special(".[{()\\+?|^$");
+ for(std::size_t i = 0; i < pattern.size(); ++i) {
+ if(pattern[i] == '*') {
+ regex_str += '.';
+ } else if(special.find(pattern[i]) != std::string::npos) {
+ regex_str += '\\';
+ }
+ regex_str += pattern[i];
+ }
+ boost::regex regex(regex_str);
+ return(boost::regex_match(text, regex));
+}
+
+// date-time
+
+// The result is clamped to the range [0,30]
+int boost::regression::timestamp_difference(const boost::posix_time::ptime& x, const boost::posix_time::ptime& y) {
+ boost::posix_time::time_duration diff = y - x;
+ int result = diff.hours() / 24;
+ if(result < 0) return 0;
+ else if(result > 30) return 30;
+ else return result;
+}
+
+std::string boost::regression::format_timestamp(const boost::posix_time::ptime& timestamp) {
+ std::ostringstream stream;
+ stream.imbue(std::locale(std::locale::classic(), new boost::posix_time::time_facet("%a, %d %b %Y %H:%M:%S +0000")));
+ stream << timestamp;
+ return stream.str();
+}
+
+// path
+
+// FIXME: The result MUST be a valid filesystem path.
+std::string boost::regression::encode_path(const std::string& path) {
+ std::string result;
+ BOOST_FOREACH(char ch, path) {
+ if(ch == '.' || ch == '/') {
+ ch = '-';
+ }
+ // FIXME: allow only characters from the following set:
+ // "[a-z][A-Z][0-9][-+_. ,()$!~?]...
+ result += ch;
+ }
+ return result;
+}
+
+std::string boost::regression::escape_uri(const std::string& path) {
+ std::string result;
+ BOOST_FOREACH(char ch, path) {
+ if (('a' <= ch && ch <= 'z') ||
+ ('A' <= ch && ch <= 'Z') ||
+ ('0' <= ch && ch <= '9') ||
+ ch == '-' || ch == '_' || ch == '~' || ch == '.' ||
+ // We're intentionally allowing '/' to go through.
+ // to escape it as well, use escape_literal_uri
+ ch == '/' ||
+ // FIXME: reserved characters
+ ch == '+')
+ result += ch;
+ else {
+ unsigned digit = ch;
+ ch &= 0xFF;
+ const char * xdigits = "0123456789ABCDEF";
+ result += '%';
+ result += xdigits[digit >> 4];
+ result += xdigits[digit & 0xF];
+ }
+ }
+ return result;
+}
+
+std::string boost::regression::escape_literal_uri(const std::string& path) {
+ std::string result;
+ BOOST_FOREACH(char ch, path) {
+ // FIXME: Assumes UTF-8
+ if (('a' <= ch && ch <= 'z') ||
+ ('A' <= ch && ch <= 'Z') ||
+ ('0' <= ch && ch <= '9') ||
+ ch == '-' || ch == '_' || ch == '~' || ch == '.')
+ result += ch;
+ else {
+ unsigned digit = ch;
+ ch &= 0xFF;
+ const char * xdigits = "0123456789ABCDEF";
+ result += '%';
+ result += xdigits[digit >> 4];
+ result += xdigits[digit & 0xF];
+ }
+ }
+ return result;
+}
+
+// okay
+std::string boost::regression::output_file_path(const std::string& path) {
+ return("output/" + (encode_path(path) + ".html"));
+}
+
+// okay
+std::string boost::regression::log_file_path(
+ const failures_markup_t& explicit_markup,
+ const test_structure_t::test_log_t& test_log,
+ const std::string& runner,
+ const std::string& release_postfix)
+{
+ if(show_output(explicit_markup, test_log)) {
+ return output_file_path(runner + "-" + test_log.target_directory + release_postfix);
+ } else {
+ return "";
+ }
+}
+
+bool boost::regression::show_library(const failures_markup_t& explicit_markup, const std::string& library, bool release) {
+ return !release || !is_library_beta(explicit_markup, library);
+}
+
+bool boost::regression::show_output(const failures_markup_t& explicit_markup, const test_structure_t::test_log_t& test_log) {
+ return ((!test_log.result || test_log.show_run_output) ||
+ (test_log.result && !test_log.status))
+ && !(is_unusable(explicit_markup, test_log.library, test_log.toolset));
+}
+
+bool boost::regression::show_toolset(const failures_markup_t& explicit_markup, const std::string& toolset, bool release) {
+ return !release || explicit_markup.required_toolsets.find(toolset) != explicit_markup.required_toolsets.end();
+}
+
+// safe: no assumptions, enumerated result
+std::string boost::regression::result_cell_class(const failures_markup_t& explicit_markup,
+ const std::string& library,
+ const std::string& toolset,
+ const test_log_group_t& test_logs) {
+ if(is_unusable(explicit_markup, library, toolset)) {
+ return "unusable";
+ }
+ if(test_logs.empty()) {
+ return "missing";
+ }
+ BOOST_FOREACH(test_log_group_t::value_type log, test_logs) {
+ if(!log->result && log->expected_result && !log->is_new) {
+ return "fail-unexpected";
+ }
+ }
+ BOOST_FOREACH(test_log_group_t::value_type log, test_logs) {
+ if(!log->result && log->expected_result && log->is_new) {
+ return "fail-unexpected-new";
+ }
+ }
+ BOOST_FOREACH(test_log_group_t::value_type log, test_logs) {
+ if(!log->result && log->expected_reason != "") {
+ return "fail-expected-unreasearched";
+ }
+ }
+ BOOST_FOREACH(test_log_group_t::value_type log, test_logs) {
+ if(!log->result) {
+ return "fail-expected";
+ }
+ }
+ BOOST_FOREACH(test_log_group_t::value_type log, test_logs) {
+ if(log->result && !log->expected_result) {
+ return "success-unexpected";
+ }
+ }
+ BOOST_FOREACH(test_log_group_t::value_type log, test_logs) {
+ if(log->result && log->expected_result) {
+ return "success-expected";
+ }
+ }
+ return "unknown";
+}
+// safe
+std::string boost::regression::result_cell_class(const failures_markup_t& explicit_markup,
+ const std::string& library,
+ const std::string& toolset,
+ const test_structure_t::library_t& test_logs)
+{
+ test_log_group_t tmp;
+ BOOST_FOREACH(test_structure_t::library_t::const_reference test_case, test_logs) {
+ BOOST_FOREACH(test_structure_t::test_case_t::const_reference log, test_case.second) {
+ tmp.push_back(&log);
+ }
+ }
+ return result_cell_class(explicit_markup, library, toolset, tmp);
+}
+
+void boost::regression::insert_report_header(
+ html_writer& document,
+ const boost::posix_time::ptime& run_date,
+ const std::vector<std::string>& warnings,
+ const std::string& purpose)
+{
+ document << "<div class=\"report-info\">\n";
+ document << " <div>\n";
+ document << " <b>Report Time: </b> " << format_timestamp(run_date) << "\n";
+ document << " </div>\n";
+
+ if(!purpose.empty()) {
+ document << " <div>\n";
+ document << " <b>Purpose: </b> " << escape_xml(purpose) << "\n";
+ document << " </div>\n";
+ }
+
+ BOOST_FOREACH(const std::string& warning, warnings) {
+ document << " <div class=\"report-warning\">\n";
+ document << " <b>Warning: </b>\n";
+ document << " <a href=\"mailto:boost-testing_at_[hidden]?subject=[Report Pages]%20" << escape_literal_uri(warning) << " (" << format_timestamp(run_date) << ")\" class=\"warning-link\">\n";
+ document << " " << escape_xml(warning) << "\n";
+ document << " </a>\n";
+ document << " </div>\n";
+ }
+
+ document << "</div>\n";
+}
+
+// requires class_ is enumerated
+void boost::regression::insert_view_link(html_writer& out, const std::string& page, const std::string& class_, bool release) {
+ if(release) {
+ out << "<a href=\"" << escape_uri(page) << ".html\" class=\"" << class_ << "\" target=\"_top\">"
+ "Full View"
+ "</a>\n";
+ } else {
+ out << "<a href=\"" << escape_uri(page) << "_release.html\" class=\"" << class_ << "\" target=\"_top\">"
+ "Release View"
+ "</a>";
+ }
+
+}
+
+// requires: mode = developer | user (Should be the opposite of the current page)
+// requires: page is the base name of the current page. It should be valid
+// according to encode_path, but should not be URI escaped.
+void boost::regression::insert_page_links(html_writer& document,
+ const std::string& page,
+ bool release,
+ const std::string& mode) {
+ document << "<div class=\"links\">\n"
+ << make_tinyurl
+ << "&#160;|&#160;";
+
+ // yes, really. The class is set to ""
+ insert_view_link(document, page, "", release);
+
+ std::string release_postfix(release? "_release" : "");
+
+ document << "&#160;|&#160;"
+ "<a href=\"../" << mode << "/" << escape_uri(page) << release_postfix << ".html\" class=\"view-link\" target=\"_top\">"
+ << mode << " View"
+ "</a>"
+ "&#160;|&#160;"
+ "<a href=\"" << escape_uri(page) << release_postfix << "_.html#legend\">Legend</a>\n"
+
+ "</div>\n";
+
+}
+
+// requires: mode = summary | details
+// requires: top_or_bottom = top | bottom
+void boost::regression::insert_runners_rows(html_writer& document,
+ const std::string& mode,
+ const std::string& top_or_bottom,
+ const test_structure_t& test_structure,
+ const boost::posix_time::ptime& run_date) {
+ std::string colspan = (mode == "summary") ? "1" : "2";
+
+ if(top_or_bottom == "top") {
+ document << "<tr>\n"
+ " <td colspan=\"" << colspan << "\">&#160;</td>\n";
+ BOOST_FOREACH(test_structure_t::platform_group_t::const_reference platform, test_structure.platforms) {
+ std::size_t count = 0;
+ BOOST_FOREACH(test_structure_t::platform_t::const_reference run, platform.second) {
+ count += run.toolsets.size();
+ }
+ if(count > 0) {
+ document << " <td colspan=\"" << count << "\" class=\"runner\">\n"
+ " " << escape_xml(platform.first) << "\n"
+ " </td>\n";
+ }
+ }
+ document << " <td colspan=\"" << colspan << "\">&#160;</td>\n"
+ "</tr>\n";
+ }
+
+ document << "<tr>\n"
+ " <td colspan=\"" << colspan << "\">&#160;</td>\n";
+ BOOST_FOREACH(test_structure_t::platform_group_t::const_reference platform, test_structure.platforms) {
+ BOOST_FOREACH(test_structure_t::platform_t::const_reference run, platform.second) {
+ if(run.toolsets.size() > 0) {
+ document << " <td colspan=\"" << run.toolsets.size() << "\" class=\"runner\">\n"
+ " <a href=\"../" << escape_uri(encode_path(run.runner)) << ".html\">\n"
+ " " << escape_xml(run.runner) << "\n"
+ " </a>\n"
+ " </td>\n";
+ }
+ }
+ }
+ document << " <td colspan=\"" << colspan << "\">&#160;</td>\n"
+ "</tr>\n";
+
+ document << "<tr>\n"
+ "<td colspan=\"" << colspan << "\">&#160;</td>\n";
+ BOOST_FOREACH(test_structure_t::platform_group_t::const_reference platform, test_structure.platforms) {
+ BOOST_FOREACH(test_structure_t::platform_t::const_reference run, platform.second) {
+ if(run.toolsets.size() > 0) {
+ document << " <td colspan=\"" << run.toolsets.size() << "\" class=\"revision\">\n"
+ " rev " << run.revision << "\n"
+ " </td>\n";
+ }
+ }
+ }
+ document << " <td colspan=\"" << colspan << "\">&#160;</td>\n"
+ "</tr>\n";
+
+ document << "<tr>\n"
+ " <td colspan=\"" << colspan << "\">&#160;</td>\n";
+ BOOST_FOREACH(test_structure_t::platform_group_t::const_reference platform, test_structure.platforms) {
+ BOOST_FOREACH(test_structure_t::platform_t::const_reference run, platform.second) {
+ if(run.toolsets.size() > 0) {
+ int age = timestamp_difference(run.timestamp, run_date);
+ document << " <td colspan=\"" << run.toolsets.size() << "\" class=\"timestamp\">\n"
+ " <span class=\"timestamp-" << age << "\">" << format_timestamp(run.timestamp) << "</span>";
+ if(run.run_type != "full") {
+ document << "<span class=\"run-type-" << run.run_type << "\">" << run.run_type[0] << "</span>\n";
+ }
+ document << " </td>\n";
+ }
+ }
+ }
+ document << " <td colspan=\"" << colspan << "\">&#160;</td>\n"
+ "</tr>\n";
+
+ if(top_or_bottom == "bottom") {
+ document << "<tr>\n"
+ " <td colspan=\"" << colspan << "\">&#160;</td>\n";
+ BOOST_FOREACH(test_structure_t::platform_group_t::const_reference platform, test_structure.platforms) {
+ std::size_t count = 0;
+ BOOST_FOREACH(test_structure_t::platform_t::const_reference run, platform.second) {
+ count += run.toolsets.size();
+ }
+ if(count > 0) {
+ document << " <td colspan=\"" << count << "\" class=\"runner\">\n"
+ " " << escape_xml(platform.first) << "\n"
+ " </td>\n";
+ }
+ }
+ document << " <td colspan=\"" << colspan << "\">&#160;</td>\n"
+ "</tr>\n";
+ }
+}
+
+// requires mode = summary | details
+void boost::regression::insert_toolsets_row(html_writer& document,
+ const test_structure_t& test_structure,
+ const failures_markup_t& explicit_markup,
+ const std::string& mode,
+ const boost::posix_time::ptime& run_date,
+ const std::string& library,
+ const boost::unordered_map<std::string, std::size_t>& library_marks) {
+
+ document << "<tr valign=\"middle\">\n";
+
+ std::string colspan = (mode == "summary") ? "1" : "2";
+ std::string title = (mode == "summary") ?
+ "&#160;library&#160;/&#160;toolset&#160;" :
+ "&#160;test&#160;/&#160;toolset&#160;";
+
+ document << " <td class=\"head\" colspan=\"" << colspan << "\" width=\"1%\">" << title << "</td>\n";
+ BOOST_FOREACH(const test_structure_t::platform_group_t::const_reference platform, test_structure.platforms) {
+ BOOST_FOREACH(const test_structure_t::platform_t::const_reference run, platform.second) {
+ BOOST_FOREACH(const test_structure_t::toolset_group_t::const_reference toolset, run.toolsets) {
+ std::string name = toolset.first;
+ std::string class_ = (explicit_markup.required_toolsets.find(name) != explicit_markup.required_toolsets.end())?
+ "required-toolset-name" :
+ "toolset-name";
+
+ document << "<td class=\"" << class_ << "\">\n";
+ int age = timestamp_difference(run.timestamp, run_date);
+
+ document << "<span class=\"timestamp-" << age << "\">\n";
+
+ // break toolset names into words
+ BOOST_FOREACH(char ch, name) {
+ document << ch;
+ if(ch == '-') {
+ document << ' ';
+ }
+ }
+
+ if(mode == "details") {
+ // <!-- prepare toolset notes -->
+ std::set<std::size_t> toolset_notes;
+ typedef boost::unordered_map<std::string, std::size_t>::const_reference ref_type;
+ BOOST_FOREACH(ref_type toolset_markup, library_marks.equal_range(name)) {
+ toolset_notes.insert(toolset_markup.second);
+ }
+ if(!toolset_notes.empty()) {
+ document << "<span class=\"super\">\n";
+ bool first = true;
+ BOOST_FOREACH(std::size_t note_index, toolset_notes) {
+ if(!first) document << ", "; else first = false;
+ document << "<a href=\"#" << escape_uri(library) << "-note-" << note_index << "\" title=\"Note " << note_index << "\">\n"
+ " " << note_index << "\n"
+ "</a>\n";
+ }
+ document << "</span>\n";
+ }
+ }
+
+ document << "</span>\n"
+ "</td>\n";
+ }
+ }
+ }
+ document << "<td class=\"head\" width=\"1%\">" << title << "</td>\n"
+ "</tr>\n";
+}
+
+namespace {
+
+std::string get_note_attr(const test_structure_t::note_t& note, const std::string& name) {
+ if(const node_ptr* node = boost::get<node_ptr>(&note)) {
+ std::string result;
+ lookup_attr(*node, name, result);
+ return result;
+ } else {
+ return std::string();
+ }
+}
+
+}
+
+// requires: if note is a string, it is well-formed html
+void boost::regression::show_note(
+ html_writer& document,
+ const test_structure_t::note_t& note,
+ const std::string& references,
+ const failures_markup_t& explicit_markup)
+{
+ document << "<div class=\"note\">\n";
+
+ std::string author = get_note_attr(note, "author");
+ std::string date = get_note_attr(note, "date");
+
+ document << " <span class=\"note-header\">\n";
+
+ if(author != "" && date != "") {
+ document << " [&#160;" << escape_xml(author) << "&#160;" << escape_xml(date) << "&#160;]\n";
+ } else if(author != "") {
+ document << " [&#160;" << escape_xml(author) << "&#160;]\n";
+ } else if(date != "") {
+ document << " [&#160;" << escape_xml(date) << "&#160;]\n";
+ }
+
+ document << " </span>\n";
+
+ if(references != "") {
+ // lookup references (refid="17,18")
+ std::vector<std::string> refs;
+ boost::algorithm::split(refs, references, boost::is_any_of(","));
+ BOOST_FOREACH(const std::string& refid, refs) {
+ boost::unordered_map<std::string, node_ptr>::const_iterator pos = explicit_markup.notes.find(refid);
+ if(pos != explicit_markup.notes.end()) {
+ write_contents(document, pos->second);
+ } else {
+ document << " " << escape_xml(refid) << "\n";
+ }
+ }
+ }
+ if(const node_ptr* node_note = boost::get<node_ptr>(&note)) {
+ write_contents(document, *node_note);
+ } else if(const std::string* string_note = boost::get<std::string>(&note)) {
+ document << *string_note; // not escaped--can contain html markup
+ }
+
+ document << "</div>\n";
+}
+
+// requires: any note that is a string contains well-formed html
+void boost::regression::show_notes(html_writer& document,
+ const std::vector<test_structure_t::note_t>& notes,
+ const failures_markup_t& explicit_markup)
+{
+ document << "<div class=\"notes\">\n";
+
+ BOOST_FOREACH(const test_structure_t::note_t& note, notes) {
+
+ document << " <div>\n";
+
+ std::string refid = get_note_attr(note, "refid");
+ ::show_note(document, note, refid, explicit_markup);
+
+ document << " </div>\n";
+
+ }
+
+ document << "</div>\n";
+}

Added: trunk/tools/regression/src/report/common.hpp
==============================================================================
--- (empty file)
+++ trunk/tools/regression/src/report/common.hpp 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
@@ -0,0 +1,109 @@
+// common.hpp
+//
+// Copyright (c) 2010 Steven Watanabe
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanyiong file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef COMMON_HPP_INCLUDED
+#define COMMON_HPP_INCLUDED
+
+#include <vector>
+#include <string>
+#include <set>
+#include <boost/filesystem/path.hpp>
+#include <boost/date_time/posix_time/ptime.hpp>
+#include "xml.hpp"
+
+namespace boost {
+namespace regression {
+
+class html_writer;
+typedef std::vector<const test_structure_t::test_log_t*> test_log_group_t;
+
+bool is_library_beta(const failures_markup_t& explicit_markup, const std::string& library);
+bool is_test_log_a_test_case(const test_structure_t::test_log_t& test_log);
+
+bool is_unusable(const failures_markup_t& markup, const std::string& library, const std::string& toolset);
+
+void get_unusable(const failures_markup_t& markup,
+ const std::string& library,
+ const test_structure_t& test_structure,
+ boost::unordered_map<std::string, std::size_t>& out,
+ std::vector<node_ptr>& notes);
+
+bool re_match(const std::string& pattern, const std::string& text);
+
+int timestamp_difference(const boost::posix_time::ptime& x, const boost::posix_time::ptime& y);
+std::string format_timestamp(const boost::posix_time::ptime& timestamp);
+
+std::string encode_path(const std::string& path);
+std::string escape_uri(const std::string& path); // escapes a URI path (leaves '/' alone)
+std::string escape_literal_uri(const std::string& path); // escapes all special characters in a URI
+std::string output_file_path(const std::string& path);
+std::string log_file_path(
+ const failures_markup_t& explicit_markup,
+ const test_structure_t::test_log_t& test_log,
+ const std::string& runner,
+ const std::string& release_postfix = "");
+
+bool show_library(const failures_markup_t& explicit_markup, const std::string& library, bool release);
+bool show_output(const failures_markup_t& markup, const test_structure_t::test_log_t& test_log);
+bool show_toolset(const failures_markup_t& explicit_markup, const std::string& toolset, bool release);
+
+void insert_report_header(html_writer& document,
+ const boost::posix_time::ptime& run_date,
+ const std::vector<std::string>& warnings,
+ const std::string& purpose = "");
+
+void insert_view_link(html_writer& document,
+ const std::string& page,
+ const std::string& class_,
+ bool release);
+
+void insert_page_links(html_writer& document,
+ const std::string& page,
+ bool release,
+ const std::string& mode);
+
+void insert_runners_rows(html_writer& document,
+ const std::string& mode,
+ const std::string& top_or_bottom,
+ const test_structure_t& test_structure,
+ const boost::posix_time::ptime& run_date);
+
+void insert_toolsets_row(html_writer& document,
+ const test_structure_t& test_structure,
+ const failures_markup_t& explicit_markup,
+ const std::string& mode,
+ const boost::posix_time::ptime& run_date,
+ const std::string& library = std::string(),
+ const boost::unordered_map<std::string, std::size_t>& library_marks = boost::unordered_map<std::string, std::size_t>());
+
+void show_note(
+ html_writer& document,
+ const test_structure_t::note_t& note,
+ const std::string& references,
+ const failures_markup_t& explicit_markup);
+void show_notes(html_writer& document, const std::vector<test_structure_t::note_t>& notes, const failures_markup_t& explicit_markup);
+
+std::string result_cell_class(const failures_markup_t& explicit_markup,
+ const std::string& library,
+ const std::string& toolset,
+ const test_log_group_t& test_logs);
+
+std::string result_cell_class(const failures_markup_t& explicit_markup,
+ const std::string& library,
+ const std::string& toolset,
+ const test_structure_t::library_t& test_logs);
+
+std::string alternate_mode(const std::string& mode);
+std::string release_postfix(bool is_release);
+
+void get_libraries(const test_structure_t& test_structure, std::set<std::string>& out);
+
+}
+}
+
+#endif

Added: trunk/tools/regression/src/report/html.cpp
==============================================================================
--- (empty file)
+++ trunk/tools/regression/src/report/html.cpp 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
@@ -0,0 +1,345 @@
+// html.cpp
+//
+// Copyright (c) 2010
+// Steven Watanabe
+//
+// Distributed Under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "html.hpp"
+
+const char* const boost::regression::make_tinyurl =
+ "<span>"
+ "<script type=\"text/javascript\">\n"
+ "<!--\n"
+ "function make_tinyurl()\n"
+ "{\n"
+ " window.open( 'http://tinyurl.com/create.php?url=' + parent.location.href );\n"
+ "}\n"
+ "//-->\n"
+ "</script>\n"
+ "\n"
+ "<a href=\"javascript:make_tinyurl()\">TinyUrl</a>"
+ "</span>\n"
+;
+
+const char* const boost::regression::issues_legend =
+ "<div class=\"legend\">\n"
+ "<table border=\"0\" summary=\"report description\">\n"
+ "<tr>\n"
+ " <td>\n"
+ " <table border=\"0\" summary=\"legend\">\n"
+ " <tr>\n"
+ " <td>\n"
+ " <table width=\"100%\" summary=\"unexpected new fail legend\">\n"
+ " <tr class=\"library-row-single\"><td class=\"library-fail-unexpected-new\">&lt;toolset&gt;</td></tr>\n"
+ " </table>\n"
+ " </td>\n"
+ " <td class=\"legend-item\">Failure on a newly added test/compiler.</td>\n"
+ " </tr>\n"
+ " <tr>\n"
+ " <td>\n"
+ " <table width=\"100%\" summary=\"unexpected fail legend\">\n"
+ " <tr class=\"library-row-single\"><td class=\"library-fail-unexpected\">&lt;toolset&gt;</td></tr>\n"
+ " </table>\n"
+ " </td>\n"
+ " <td class=\"legend-item\">Unexpected failure.</td>\n"
+ " </tr>\n"
+ " </table>\n"
+ " </td>\n"
+ "</tr>\n"
+ "</table>\n"
+ "</div>\n"
+;
+
+const char* const boost::regression::library_user_legend =
+ "<div class=\"legend\">\n"
+ "<table border=\"0\" summary=\"report description\">\n"
+ " <tr>\n"
+ " <td class=\"legend-item\" width=\"50pt\">\n"
+ " <table width=\"100%\" summary=\"success legend\">\n"
+ " <tr class=\"library-row-single\"><td class=\"library-success-expected user-library-success-expected\">pass</td></tr>\n"
+ " </table>\n"
+ " </td>\n"
+ " <td class=\"legend-explanation\">The test successfully passes.</td>\n"
+ " </tr>\n"
+ " <tr>\n"
+ " <td class=\"legend-item\" width=\"50pt\">\n"
+ " <table width=\"100%\" summary=\"expected fail legend\">\n"
+ " <tr class=\"library-row-single\"><td class=\"library-fail-expected user-library-fail-expected\"><u>fail*</u></td></tr>\n"
+ " </table>\n"
+ " </td>\n"
+ " <td class=\"legend-explanation\">\n"
+ " A <b>known failure</b> that the library maintainers are aware about. Please follow the link to \n"
+ " find out how it affects the library's functionality.\n"
+ " </td>\n"
+ " </tr>\n"
+ " <tr>\n"
+ " <td class=\"legend-item\" width=\"50pt\">\n"
+ " <table width=\"100%\" summary=\"unusable legend\">\n"
+ " <tr class=\"library-row-single\"><td class=\"library-unusable user-library-unusable\">unusable</td></tr>\n"
+ " </table>\n"
+ " </td>\n"
+ " <td class=\"legend-explanation\">\n"
+ " The library author marked it as <b>unusable</b> on this particular platform/toolset. Please\n"
+ " see the corresponding footnote.\n"
+ " </td>\n"
+ " </tr>\n"
+ " <tr>\n"
+ " <td class=\"legend-item\" width=\"50pt\">\n"
+ " <table width=\"100%\" summary=\"unresearched legend\">\n"
+ " <tr class=\"library-row-single\"><td class=\"library-fail-expected-unresearched user-library-fail-expected-unresearched\"><u>fail?</u></td></tr>\n"
+ " </table>\n"
+ " </td>\n"
+ " <td class=\"legend-explanation\">\n"
+ " An <b>unsearched failure</b>: the library maintainers are aware of it, but need help with \n"
+ " investigating/addressing it for future releases. Please follow the link to \n"
+ " access the details and find out how it affects library functionality. </td>\n"
+ " </tr>\n"
+ " <tr>\n"
+ " <td class=\"legend-item\" width=\"50pt\">\n"
+ " <table width=\"100%\" summary=\"unexpected new fail legend\">\n"
+ " <tr class=\"library-row-single\"><td class=\"library-fail-unexpected-new user-library-fail-unexpected-new\"><u>fail</u></td></tr>\n"
+ " </table>\n"
+ " </td>\n"
+ " <td class=\"legend-explanation\">\n"
+ " A <b>new failure</b> on the test/compiler added in this release that hasn't been accounted for yet. \n"
+ " Please follow the link to access the details.\n"
+ " </td>\n"
+ " </tr>\n"
+ " <tr>\n"
+ " <td class=\"legend-item\" width=\"50pt\">\n"
+ " <table width=\"100%\" summary=\"unexpected fail legend\">\n"
+ " <tr class=\"library-row-single user-library-row-single\"><td class=\"library-fail-unexpected\"><u>fail</u></td></tr>\n"
+ " </table>\n"
+ " </td>\n"
+ " <td class=\"legend-explanation\">\n"
+ " A <b>regression</b> comparing to the previous release. Please follow the link to \n"
+ " access the details.\n"
+ " </td>\n"
+ " </tr>\n"
+ " <tr>\n"
+ " <td class=\"legend-item\" width=\"50pt\">\n"
+ " </td>\n"
+ " <td class=\"legend-explanation\"></td>\n"
+ " </tr>\n"
+ "</table>\n"
+ "<hr/>\n"
+ "<table border=\"0\" summary=\"report description\">\n"
+ " <tr>\n"
+ " <td><span class=\"run-type-incremental\">i</span></td>\n"
+ " <td class=\"legend-explanation\">An incremental run.</td>\n"
+ " </tr>\n"
+ "</table>\n"
+ "</div>\n"
+;
+
+const char* const boost::regression::library_developer_legend =
+ "<div class=\"legend\">\n"
+ "<table border=\"0\" summary=\"report description\">\n"
+ " <tr>\n"
+ " <td class=\"legend-item\" width=\"50pt\">\n"
+ " <table width=\"100%\" summary=\"success legend\">\n"
+ " <tr class=\"library-row-single\"><td class=\"library-success-expected\">pass</td></tr>\n"
+ " </table>\n"
+ " </td>\n"
+ " <td class=\"legend-explanation\">Success.</td>\n"
+ " </tr>\n"
+ " <tr>\n"
+ " <td class=\"legend-item\" width=\"50pt\">\n"
+ " <table width=\"100%\" summary=\"unexpected pass legend\">\n"
+ " <tr class=\"library-row-single\"><td class=\"library-success-unexpected\">pass</td></tr>\n"
+ " </table>\n"
+ " </td>\n"
+ " <td class=\"legend-explanation\">Unexpected success; follow the link for more details.</td>\n"
+ " </tr>\n"
+ " <tr>\n"
+ " <td class=\"legend-item\" width=\"50pt\">\n"
+ " <table width=\"100%\" summary=\"expected fail legend\">\n"
+ " <tr class=\"library-row-single\"><td class=\"library-fail-expected\">fail*</td></tr>\n"
+ " </table>\n"
+ " </td>\n"
+ " <td class=\"legend-explanation\">Expected failure; follow the link for more details.</td>\n"
+ " </tr>\n"
+ " <tr>\n"
+ " <td class=\"legend-item\" width=\"50pt\">\n"
+ " <table width=\"100%\" summary=\"unusable legend\">\n"
+ " <tr class=\"library-row-single\"><td class=\"library-unusable\">n/a</td></tr>\n"
+ " </table>\n"
+ " </td>\n"
+ " <td class=\"legend-explanation\">The library author marked it as unusable on this particular platform/toolset.</td>\n"
+ " </tr>\n"
+ " <tr>\n"
+ " <td class=\"legend-item\" width=\"50pt\">\n"
+ " <table width=\"100%\" summary=\"unresearched legend\">\n"
+ " <tr class=\"library-row-single\"><td class=\"library-fail-expected-unresearched\">fail?</td></tr>\n"
+ " </table>\n"
+ " </td>\n"
+ " <td class=\"legend-explanation\">Unsearched failure; follow the link for more details.</td>\n"
+ " </tr>\n"
+ " <tr>\n"
+ " <td class=\"legend-item\" width=\"50pt\">\n"
+ " <table width=\"100%\" summary=\"unexpected new fail legend\">\n"
+ " <tr class=\"library-row-single\"><td class=\"library-fail-unexpected-new\">fail</td></tr>\n"
+ " </table>\n"
+ " </td>\n"
+ " <td class=\"legend-explanation\">Failure on a newly added test/compiler.</td>\n"
+ " </tr>\n"
+ " <tr>\n"
+ " <td class=\"legend-item\" width=\"50pt\">\n"
+ " <table width=\"100%\" summary=\"unexpected fail legend\">\n"
+ " <tr class=\"library-row-single\"><td class=\"library-fail-unexpected\">fail</td></tr>\n"
+ " </table>\n"
+ " </td>\n"
+ " <td class=\"legend-explanation\">Unexpected failure/regression.</td>\n"
+ " </tr>\n"
+ " <tr>\n"
+ " <td class=\"legend-item\" width=\"50pt\">\n"
+ " </td>\n"
+ " <td class=\"legend-explanation\"></td>\n"
+ " </tr>\n"
+ "</table>\n"
+ "<hr/>\n"
+ "<table border=\"0\" summary=\"report description\">\n"
+ " <tr>\n"
+ " <td><span class=\"run-type-incremental\">i</span></td>\n"
+ " <td class=\"legend-explanation\">An incremental run.</td>\n"
+ " </tr>\n"
+ "</table>\n"
+ "</div>\n"
+;
+
+const char * const boost::regression::summary_user_legend =
+ "<div class=\"legend\">\n"
+ "<table border=\"0\" summary=\"report description\">\n"
+ " <tr>\n"
+ " <td class=\"legend-item\" width=\"50pt\">\n"
+ " <table width=\"100%\" summary=\"success legend\">\n"
+ " <tr class=\"summary-row-single\"><td class=\"summary-success-expected user-summary-success-expected\">&#160;pass&#160;</td></tr>\n"
+ " </table>\n"
+ " </td>\n"
+ " <td class=\"legend-explanation\">\n"
+ " All library's tests pass.\n"
+ " </td>\n"
+ " </tr>\n"
+ " <tr>\n"
+ " <td class=\"legend-item\" width=\"50pt\">\n"
+ " <table width=\"100%\" summary=\"expected fail legend\">\n"
+ " <tr class=\"summary-row-single\"><td class=\"summary-fail-expected user-summary-fail-expected\"><u>details</u></td></tr>\n"
+ " </table>\n"
+ " </td>\n"
+ " <td class=\"legend-explanation\">\n"
+ " Most of the library's tests pass, but there are some <b>known failures</b> which might affect the library's\n"
+ " functionality. Please follow the link to see the detailed report.\n"
+ " </td>\n"
+ " </tr>\n"
+ " <tr>\n"
+ " <td class=\"legend-item\" width=\"50pt\">\n"
+ " <table width=\"100%\" summary=\"unexpected new fail legend\">\n"
+ " <tr class=\"summary-row-single\"><td class=\"summary-fail-unexpected-new user-summary-fail-unexpected-new\"><u>details</u></td></tr>\n"
+ " </table>\n"
+ " </td>\n"
+ " <td class=\"legend-explanation\">\n"
+ " Some of the <b>newly added</b> library's tests fail, or some of the library's tests fail on\n"
+ " the <b>newly added compiler</b>, or some of the tests fail due to <b>unresearched \n"
+ " reasons</b>. Please follow the link to see the detailed report.\n"
+ " </td>\n"
+ " </tr>\n"
+ " <tr>\n"
+ " <td class=\"legend-item\" width=\"50pt\">\n"
+ " <table width=\"100%\" summary=\"unexpected fail legend\">\n"
+ " <tr class=\"summary-row-single\"><td class=\"summary-fail-unexpected user-summary-fail-unexpected\"><u>regress.</u></td></tr>\n"
+ " </table>\n"
+ " </td>\n"
+ " <td class=\"legend-explanation\">\n"
+ " There are some <b>regressions</b> in the library comparing to the previous release. \n"
+ " Please follow the link to see the detailed report.\n"
+ " </td>\n"
+ " </tr>\n"
+ " <tr>\n"
+ " <td class=\"legend-item\" width=\"50pt\">\n"
+ " <table width=\"100%\" summary=\"unusable legend\">\n"
+ " <tr class=\"summary-row-single\"><td class=\"summary-unusable user-summary-unusable\">unusable</td></tr>\n"
+ " </table>\n"
+ " </td>\n"
+ " <td class=\"legend-explanation\">\n"
+ " The library author marked it as <b>unusable</b> on the particular platform/toolset.\n"
+ " Please follow the link to see the detailed report.\n"
+ " </td>\n"
+ " </tr>\n"
+ "</table>\n"
+ "<hr/>\n"
+ "<table border=\"0\" summary=\"report description\" id=\"Table1\">\n"
+ " <tr>\n"
+ " <td><span class=\"run-type-incremental\">i</span></td>\n"
+ " <td class=\"legend-explanation\">An incremental run.</td>\n"
+ " </tr>\n"
+ "</table>\n"
+ "</div>\n"
+;
+
+const char * const boost::regression::summary_developer_legend =
+ "<div class=\"legend\">\n"
+ "<table border=\"0\" summary=\"report description\">\n"
+ " <tr>\n"
+ " <td class=\"legend-item\" width=\"50pt\">\n"
+ " <table width=\"100%\" summary=\"success legend\">\n"
+ " <tr class=\"summary-row-single\"><td class=\"summary-success-expected\">OK</td></tr>\n"
+ " </table>\n"
+ " </td>\n"
+ " <td class=\"legend-explanation\">\n"
+ " All expected tests pass.\n"
+ " </td>\n"
+ " </tr>\n"
+ " <tr>\n"
+ " <td class=\"legend-item\" width=\"50pt\">\n"
+ " <table width=\"100%\" summary=\"unexpected pass legend\">\n"
+ " <tr class=\"summary-row-single\"><td class=\"summary-success-unexpected\">OK</td></tr>\n"
+ " </table>\n"
+ " </td>\n"
+ " <td class=\"legend-explanation\">\n"
+ " All expected tests pass, and some other tests that were expected to fail \n"
+ " unexpectedly pass as well.\n"
+ " </td>\n"
+ " </tr>\n"
+ " <tr>\n"
+ " <td class=\"legend-item\" width=\"50pt\">\n"
+ " <table width=\"100%\" summary=\"unexpected new fail legend\">\n"
+ " <tr class=\"summary-row-single\"><td class=\"summary-fail-unexpected-new\">fail</td></tr>\n"
+ " </table>\n"
+ " </td>\n"
+ " <td class=\"legend-explanation\">\n"
+ " There are some failures on the newly added tests/compiler(s).\n"
+ " </td>\n"
+ " </tr>\n"
+ " <tr>\n"
+ " <td class=\"legend-item\" width=\"50pt\">\n"
+ " <table width=\"100%\" summary=\"unexpected fail legend\">\n"
+ " <tr class=\"summary-row-single\"><td class=\"summary-fail-unexpected\">broken</td></tr>\n"
+ " </table>\n"
+ " </td>\n"
+ " <td class=\"legend-explanation\">\n"
+ " Tests that the library author expects to pass are currently failing.\n"
+ " </td>\n"
+ " </tr>\n"
+ " <tr>\n"
+ " <td class=\"legend-item\" width=\"50pt\">\n"
+ " <table width=\"100%\" summary=\"unusable legend\">\n"
+ " <tr class=\"summary-row-single\"><td class=\"summary-unusable\">n/a</td></tr>\n"
+ " </table>\n"
+ " </td>\n"
+ " <td class=\"legend-explanation\">\n"
+ " The library author marked it as unusable on particular platform/toolset.\n"
+ " </td>\n"
+ " </tr>\n"
+ "</table>\n"
+ "<hr/>\n"
+ "<table border=\"0\" summary=\"report description\" id=\"Table1\">\n"
+ " <tr>\n"
+ " <td><span class=\"run-type-incremental\">i</span></td>\n"
+ " <td class=\"legend-explanation\">An incremental run.</td>\n"
+ " </tr>\n"
+ "</table>\n"
+ "</div>\n"
+;

Added: trunk/tools/regression/src/report/html.hpp
==============================================================================
--- (empty file)
+++ trunk/tools/regression/src/report/html.hpp 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
@@ -0,0 +1,26 @@
+// html.hpp
+//
+// Copyright (c) 2010
+// Steven Watanabe
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef HTML_HPP_INCLUDED
+#define HTML_HPP_INCLUDED
+
+namespace boost {
+namespace regression {
+
+extern const char* const make_tinyurl;
+extern const char* const issues_legend;
+extern const char* const library_user_legend;
+extern const char* const library_developer_legend;
+extern const char* const summary_user_legend;
+extern const char* const summary_developer_legend;
+
+}
+}
+
+#endif

Added: trunk/tools/regression/src/report/html_writer.hpp
==============================================================================
--- (empty file)
+++ trunk/tools/regression/src/report/html_writer.hpp 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
@@ -0,0 +1,70 @@
+// html_writer.hpp
+//
+// Copyright (c) 2010 Steven Watanabe
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanyiong file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef HTML_WRITER_HPP_INCLUDED
+#define HTML_WRITER_HPP_INCLUDED
+
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/convenience.hpp>
+#include <boost/iostreams/device/file_descriptor.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/shared_ptr.hpp>
+#include "zip.hpp"
+
+#include <cstring>
+
+extern boost::shared_ptr<boost::zip::zip_archive> global_zip;
+
+namespace boost {
+namespace regression {
+
+class html_writer : boost::noncopyable {
+public:
+ // path must be UTF-8 encoded. The separator is '/'
+ explicit html_writer(const std::string& path)
+ : sink(*global_zip, path)
+ {}
+ ~html_writer() {
+ }
+ html_writer& operator<<(const std::string& arg) {
+ sink.write(arg.data(), arg.size());
+ return *this;
+ }
+ html_writer& operator<<(const char* arg) {
+ sink.write(arg, ::std::strlen(arg));
+ return *this;
+ }
+ html_writer& operator<<(char arg) {
+ sink.write(&arg, 1);
+ return *this;
+ }
+ html_writer& operator<<(std::size_t arg) {
+ char buf[30];
+ char* pos = &buf[0] + 30;
+ if(arg == 0) {
+ *--pos = '0';
+ }
+ for(; arg > 0; arg /= 10) {
+ *--pos = static_cast<char>('0' + (arg % 10));
+ }
+ sink.write(pos, buf + 30 - pos);
+ return *this;
+ }
+ html_writer& operator<<(int arg) {
+ if(arg < 0) *this << '-' << std::size_t(-arg);
+ else *this << std::size_t(arg);
+ return *this;
+ }
+private:
+ boost::zip::deflate_sink sink;
+};
+
+}
+}
+
+#endif

Added: trunk/tools/regression/src/report/issues_page.cpp
==============================================================================
--- (empty file)
+++ trunk/tools/regression/src/report/issues_page.cpp 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
@@ -0,0 +1,291 @@
+// issues_page.cpp
+//
+// Copyright MetaCommunications, Inc. 2003-2004.
+// Copyright Steven Watanabe 2010
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "issues_page.hpp"
+#include "html_writer.hpp"
+#include "xml.hpp"
+#include "html.hpp"
+#include "common.hpp"
+
+#include <map>
+#include <string>
+#include <boost/foreach.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/date_time/posix_time/posix_time_io.hpp>
+
+using namespace boost::regression;
+
+typedef std::pair<const test_structure_t::test_log_t*, const std::string*> test_failure_t;
+typedef std::map<std::string, std::map<std::string, std::vector<test_failure_t> > > library_test_names_t;
+typedef std::map<std::string, library_test_names_t> libraries_t;
+
+namespace {
+
+void failing_tests(const test_structure_t& tests,
+ const failures_markup_t& explicit_markup,
+ bool release,
+ libraries_t& out)
+{
+ typedef boost::unordered_map<std::string, test_structure_t::platform_t> test_structure_top;
+ BOOST_FOREACH(test_structure_top::const_reference platform, tests.platforms) {
+ BOOST_FOREACH(const test_structure_t::run_t& runs, platform.second) {
+ BOOST_FOREACH(test_structure_t::toolset_group_t::const_reference toolset, runs.toolsets) {
+ BOOST_FOREACH(test_structure_t::toolset_t::const_reference library, toolset.second) {
+ BOOST_FOREACH(test_structure_t::library_t::const_reference test_case, library.second) {
+ BOOST_FOREACH(test_structure_t::test_case_t::const_reference test_log, test_case.second) {
+ if(test_log.status == false && test_log.result == false &&
+ explicit_markup.required_toolsets.find(test_log.toolset) != explicit_markup.required_toolsets.end() &&
+ is_test_log_a_test_case(test_log) &&
+ show_library(explicit_markup, library.first, release) &&
+ show_toolset(explicit_markup, toolset.first, release) &&
+ !(is_unusable(explicit_markup, library.first, toolset.first))) {
+ out[library.first][test_log.test_name][test_log.toolset].push_back(std::make_pair(&test_log, &runs.runner));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+std::size_t count_failures(const library_test_names_t& library) {
+ std::size_t result = 0;
+ BOOST_FOREACH(library_test_names_t::const_reference test, library) {
+ BOOST_FOREACH(library_test_names_t::mapped_type::const_reference toolset, test.second) {
+ result += toolset.second.size();
+ }
+ }
+ return result;
+}
+
+// okay
+void write_issues_list_reference_file(const std::string& out,
+ const std::string& source,
+ bool release,
+ const std::string& issues_list)
+{
+ html_writer document(out);
+ document << "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n";
+ document << "<html>\n";
+ document << " <head>\n";
+ document << " <link rel=\"stylesheet\" type=\"text/css\" href=\"../master.css\" title=\"master\" />\n";
+ document << " <title>Boost regression unresolved issues: " << source << "</title>\n";
+ document << " </head>\n";
+ document << " <frameset cols=\"190px,*\" frameborder=\"0\" framespacing=\"0\" border=\"0\">\n";
+ document << " <frame name=\"tocframe\" src=\"toc" << release_postfix(release) << ".html\" scrolling=\"auto\"/>\n";
+ document << " <frame name=\"docframe\" src=\"" << issues_list << "\" scrolling=\"auto\"/>\n";
+ document << " </frameset>\n";
+ document << "</html>\n";
+}
+
+void print_failure_cell(html_writer& document,
+ const failures_markup_t& explicit_markup,
+ const std::string& output_directory,
+ const test_structure_t::test_log_t& test_log,
+ const std::string& toolset,
+ const std::string& runner,
+ const std::string& release_postfix)
+{
+ std::string log_link = log_file_path(explicit_markup, test_log, runner, release_postfix);
+
+ const char* class_ = test_log.is_new?
+ "library-fail-unexpected-new" :
+ "library-fail-unexpected";
+
+ document << "<td class=\"" << class_ << "\">\n";
+ document << " <span>\n";
+ document << " <a href=\"" << escape_uri(log_link) << "\" class=\"log-link\" target=\"_top\">\n";
+ document << " " << escape_xml(toolset) << "\n";
+ document << " </a>\n";
+ document << " </span>\n";
+ document << "</td>\n";
+}
+
+void write_issues_list(const std::string& path,
+ const failures_markup_t& explicit_markup,
+ const std::string& output_directory,
+ const libraries_t& libraries,
+ const std::string& source,
+ const boost::posix_time::ptime& run_date,
+ const std::vector<std::string>& warnings,
+ const std::string& purpose,
+ bool release)
+{
+ //utils::log("Writing document " + path);
+
+ const char* release_postfix = release? "_release" : "";
+
+ html_writer document(path);
+
+ document << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\">\n";
+
+ document << "<html>\n";
+ document << " <head>\n";
+ document << " <link rel=\"stylesheet\" type=\"text/css\" href=\"../master.css\" title=\"master\" />\n";
+ document << " </head>\n";
+ document << " <body>\n";
+ document << "\n";
+ document << " <h1 class=\"page-title\">\n";
+ document << " Unresolved Issues: \n";
+ document << " <a class=\"hover-link\" href=\"summary" << release_postfix << ".html\" target=\"_top\">" << source << "</a>\n";
+ document << " </h1>\n";
+ document << "\n";
+
+ insert_report_header(document, run_date, warnings, purpose);
+
+ // Emit the index
+ document << " <h2>Libraries with unresolved failures</h2>\n";
+ document << " <div align=\"center\">\n";
+
+ BOOST_FOREACH(libraries_t::const_reference library, libraries) {
+ document << " <a href=\"#" << escape_uri(library.first) << "\">\n";
+ document << " " << escape_xml(library.first) << "\n";
+ document << " </a>\n";
+ }
+
+ BOOST_FOREACH(libraries_t::const_reference library, libraries) {
+ std::string library_page(encode_path(library.first));
+ const library_test_names_t& library_test_names(library.second);
+ std::size_t failures = count_failures(library.second);
+
+ document << " <h2>\n";
+ document << " <a name=\"" << escape_uri(library.first) << "\"/>\n";
+ document << " <a class=\"hover-link\" href=\"" << escape_uri(library_page)
+ << release_postfix << ".html\" target=\"_top\">\n";
+ document << " " << escape_xml(library.first) << " (" << failures
+ << " failure" << (failures == 1? "":"s") << ")\n";
+ document << " </a>\n";
+ document << " </h2>\n";
+
+ document << " <table class=\"library-issues-table\" summary=\"issues\">\n";
+ document << " <thead>\n";
+ document << " <tr valign=\"middle\">\n";
+ document << " <td class=\"head\">test</td>\n";
+ document << " <td class=\"head\">failures</td>\n";
+ document << " </tr>\n";
+ document << " </thead>\n";
+ document << " <tfoot>\n";
+ document << " <tr valign=\"middle\">\n";
+ document << " <td class=\"head\">test</td>\n";
+ document << " <td class=\"head\">failures</td>\n";
+ document << " </tr>\n";
+ document << " </tfoot>\n";
+
+ document << " <tbody>\n";
+
+ BOOST_FOREACH(library_test_names_t::const_reference test, library_test_names) {
+ const std::string& test_name = test.first;
+ const std::string& test_program = test.second.begin()->second.front().first->test_program;
+
+ document << " <tr>\n";
+ document << " <td class=\"test-name\">\n";
+ document << " <a href=\"http://svn.boost.org/svn/boost/"
+ << source << "/" << escape_uri(test_program) << "\" class=\"test-link\" target=\"_top\">\n";
+ document << " " << escape_xml(test_name) << "\n";
+ document << " </a>\n";
+ document << " </td>\n";
+ document << " <td class=\"failures-row\">\n";
+ document << " <table summary=\"unexpected fail legend\" class=\"issue-box\">\n";
+ document << " <tr class=\"library-row-single\">\n";
+
+ typedef library_test_names_t::mapped_type::const_reference toolset_t;
+ BOOST_FOREACH(toolset_t toolset, test.second) {
+ BOOST_FOREACH(const test_failure_t& failure, toolset.second) {
+ print_failure_cell(document, explicit_markup, output_directory, *failure.first, toolset.first, *failure.second, release_postfix);
+ }
+ }
+
+ document << " </tr>\n";
+ document << " </table>\n";
+ document << " </td>\n";
+ document << " </tr>\n";
+ }
+ document << " </tbody>\n";
+
+ document << " </table>\n";
+ }
+ document << issues_legend;
+ document << make_tinyurl;
+ document << " </body>\n";
+ document << "</html>\n";
+}
+
+// okay
+void write_issues_email(const std::string& path,
+ const boost::posix_time::ptime& run_date,
+ const std::string& source,
+ const libraries_t& libraries)
+{
+ boost::filesystem::ofstream document(path);
+ std::cout << "Writing document " << path << std::endl;
+ //utils::log(boost::format("Writing document %s") % path);
+
+ std::size_t failing_tests = 0;
+ BOOST_FOREACH(libraries_t::const_reference library, libraries) {
+ failing_tests += count_failures(library.second);
+ }
+
+ document << "Boost regression test failures\n"
+"------------------------------\n"
+"Report time: " << run_date << "\n"
+"\n"
+"This report lists all regression test failures on release platforms.\n"
+"\n"
+"Detailed report: \n"
+" http://beta.boost.org/development/tests/" << source << "/developer/issues.html\n"
+"\n"
+<< failing_tests << " failure" << (failing_tests == 1? "" : "s")
+<< " in " << libraries.size() << " librar" << (libraries.size() == 1? "y" : "ies") << ":\n";
+
+ BOOST_FOREACH(libraries_t::const_reference library, libraries) {
+ document << " " << library.first << " (" << count_failures(library.second) << ")\n";
+ }
+
+ BOOST_FOREACH(libraries_t::const_reference library, libraries) {
+
+ std::string library_page = encode_path(library.first);
+ document << "\n"
+ "|" << library.first << "|\n";
+
+ BOOST_FOREACH(libraries_t::mapped_type::const_reference test_name, library.second) {
+ document << " " << test_name.first << ":";
+ BOOST_FOREACH(libraries_t::mapped_type::mapped_type::const_reference toolset, test_name.second) {
+ document << " " << toolset.first;
+ }
+ document << "\n";
+ }
+ }
+}
+
+}
+
+void boost::regression::issues_list(const std::string& output_dir,
+ const test_structure_t& tests,
+ const failures_markup_t& explicit_markup,
+ bool release,
+ const std::string& source,
+ const boost::posix_time::ptime& run_date,
+ const std::vector<std::string>& warnings,
+ const std::string& purpose)
+{
+ ::libraries_t libraries;
+ failing_tests(tests, explicit_markup, release, libraries);
+
+ std::string release_postfix_(release_postfix(release));
+ std::string issues_list("issues" + release_postfix_ + "_.html");
+
+ write_issues_list_reference_file(output_dir + "/issues.html", source, release, issues_list);
+ write_issues_list(output_dir + "/" + issues_list, explicit_markup, output_dir, libraries, source, run_date, warnings, purpose, release);
+
+ write_issues_email(output_dir + "/issues-email.txt",
+ run_date,
+ source,
+ libraries);
+}

Added: trunk/tools/regression/src/report/issues_page.hpp
==============================================================================
--- (empty file)
+++ trunk/tools/regression/src/report/issues_page.hpp 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
@@ -0,0 +1,31 @@
+// issues_page.hpp
+//
+// Copyright (c) 2010
+// Steven Watanabe
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "xml.hpp"
+
+#include <boost/filesystem/path.hpp>
+#include <boost/date_time/posix_time/ptime.hpp>
+
+#include <string>
+#include <vector>
+
+namespace boost {
+namespace regression {
+
+void issues_list(const std::string& output_dir,
+ const test_structure_t& tests,
+ const failures_markup_t& explicit_markup,
+ bool release,
+ const std::string& source,
+ const boost::posix_time::ptime& run_date,
+ const std::vector<std::string>& warnings,
+ const std::string& purpose);
+
+}
+}
\ No newline at end of file

Added: trunk/tools/regression/src/report/links_page.cpp
==============================================================================
--- (empty file)
+++ trunk/tools/regression/src/report/links_page.cpp 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
@@ -0,0 +1,369 @@
+// Copyright MetaCommunications, Inc. 2003-2006.
+// Copyright Steven Watanabe 2010
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "links_page.hpp"
+#include "xml.hpp"
+#include "common.hpp"
+#include "html_writer.hpp"
+#include "html.hpp"
+
+#include <boost/date_time/posix_time/ptime.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/foreach.hpp>
+#include <string>
+#include <vector>
+
+using namespace boost::regression;
+
+namespace {
+
+void links_page(const boost::posix_time::ptime& run_date,
+ const failures_markup_t& explicit_markup,
+ const std::string& runner_id,
+ const std::string& revision,
+ const boost::posix_time::ptime& timestamp,
+ const std::string& library_name,
+ const std::string& toolset_name,
+ const std::string& test_name,
+ const std::vector<test_structure_t::test_log_t>& test_logs);
+void write_variants_reference_file(const std::string& path,
+ const std::string& variants_file_path,
+ const std::string release_postfix);
+std::string output_page_header(node_ptr test_log, const std::string& runner_id);
+void write_variants_file(const boost::posix_time::ptime& run_date,
+ const failures_markup_t& explicit_markup,
+ const std::string& path,
+ const std::vector<test_structure_t::test_log_t>& test_logs,
+ const std::string& runner_id,
+ const std::string& revision,
+ const boost::posix_time::ptime& timestamp);
+void write_test_result_file(const boost::posix_time::ptime& run_date,
+ const failures_markup_t& explicit_markup,
+ const std::string& path,
+ const test_structure_t::test_log_t& test_log,
+ const std::string& runner_id,
+ const std::string& revision,
+ const boost::posix_time::ptime& timestamp);
+void write_test_results_reference_file(const std::string& path, const std::string& log_file_path);
+
+// requires: revision must be a SVN revision. i.e. of the form nnnnn
+void links_page(const boost::posix_time::ptime& run_date,
+ const failures_markup_t& explicit_markup,
+ const std::string& runner_id,
+ const std::string& revision,
+ const boost::posix_time::ptime& timestamp,
+ const std::string& library_name,
+ const std::string& toolset_name,
+ const std::string& test_name,
+ const std::vector<test_structure_t::test_log_t>& test_logs) {
+ //utils::log("Processing test \"" + runner_id + "/" + library_name + "/" + test_name + "/" + toolset_name + "\"");
+
+ const char* postfixes[] = {"", "_release"};
+ const char* dirs[] = { "developer", "user" };
+
+ if(test_logs.size() > 1) {
+ // utils::log(" Processing variants");
+
+ std::string variants_file_path = output_file_path(runner_id + "-" + library_name + "-" + toolset_name + "-" + test_name + "-variants");
+
+ write_variants_file(run_date, explicit_markup, variants_file_path, test_logs, runner_id, revision, timestamp);
+
+ BOOST_FOREACH(const std::string& release_postfix, postfixes) {
+ BOOST_FOREACH(const std::string& directory, dirs) {
+ std::string variants__file_path = directory + "/" + (encode_path(runner_id + "-" + library_name + "-" + toolset_name + "-" + test_name + "-variants_" + release_postfix) + ".html");
+ write_variants_reference_file(variants__file_path, "../" + variants_file_path, release_postfix);
+ }
+ }
+ }
+
+ BOOST_FOREACH(const test_structure_t::test_log_t& test_log, test_logs) {
+ //utils::log(" Processing test-log");
+
+ if(show_output(explicit_markup, test_log)) {
+ std::string log_path = log_file_path(explicit_markup, test_log, runner_id);
+ write_test_result_file(run_date, explicit_markup, log_path, test_log, runner_id, revision, timestamp);
+
+ BOOST_FOREACH(const std::string& release_postfix, postfixes) {
+ BOOST_FOREACH(const std::string& directory, dirs) {
+ std::string reference_file_path = directory + "/" + log_file_path(explicit_markup, test_log, runner_id, release_postfix);
+ write_test_results_reference_file(reference_file_path, log_path);
+ }
+ }
+ }
+ }
+}
+
+// requires: path must be a valid file path.
+// requires: variants_file_path must be the path to the variants file relative to path
+void write_variants_reference_file(const std::string& path,
+ const std::string& variants_file_path,
+ const std::string release_postfix)
+{
+ //utils::log(" Writing variants reference file %s" % path);
+
+ html_writer document(path);
+
+ document << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\">\n"
+ "<html>\n"
+ " <head>\n"
+ " <link rel=\"stylesheet\" type=\"text/css\" href=\"../master.css\" title=\"master\" />\n"
+ " </head>\n"
+ " <frameset cols=\"190px,*\" frameborder=\"0\" framespacing=\"0\" border=\"0\">\n"
+ " <frame name=\"tocframe\" src=\"toc" << release_postfix << ".html\" scrolling=\"auto\"/>\n"
+ " <frame name=\"docframe\" src=\"" << escape_uri(variants_file_path) << "\" scrolling=\"auto\"/>\n"
+ " </frameset>\n"
+ "</html>\n";
+}
+
+// okay. result is unconstrained
+std::string output_page_header(const test_structure_t::test_log_t& test_log, const std::string& runner_id) {
+ if(test_log.test_name != "") {
+ return runner_id + " - " + test_log.library + " - " + test_log.test_name + " / " + test_log.toolset;
+ } else {
+ return test_log.target_directory;
+ }
+}
+
+// requires revision is an SVN revision #
+// requires path is a valid path
+void write_variants_file(const boost::posix_time::ptime& run_date,
+ const failures_markup_t& explicit_markup,
+ const std::string& path,
+ const std::vector<test_structure_t::test_log_t>& test_logs,
+ const std::string& runner_id,
+ const std::string& revision,
+ const boost::posix_time::ptime& timestamp)
+{
+ //utils::log(" Writing variants file " + path.string());
+ html_writer document(path);
+
+ std::string component = output_page_header(test_logs[0], runner_id);
+ int age = timestamp_difference(timestamp, run_date);
+
+ document << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\">\n"
+ "<html>\n"
+ " <head>\n"
+ " <link rel=\"stylesheet\" type=\"text/css\" href=\"../master.css\" title=\"master\" />\n"
+ " <title>Test output: " << escape_xml(component) << "</title>\n"
+ " </head>\n"
+ " <body>\n"
+ " <div class=\"log-test-header\">\n"
+ " <div class=\"log-test-title\">\n"
+ " Test output: " << escape_xml(component) << "\n"
+ " </div>\n"
+ " <div><span class=\"timestamp-" << age << "\">\n"
+ " Rev " << revision << " /\n"
+ " " << format_timestamp(timestamp) << "\n"
+ " </span></div>\n"
+ " </div>\n"
+ "\n"
+ " <div>\n"
+ " <b>Report Time: </b> " << format_timestamp(run_date) << "\n"
+ " </div>\n"
+ "\n"
+ " <p>Output by test variants:</p>\n"
+ " <table>\n";
+
+ BOOST_FOREACH(const test_structure_t::test_log_t& log, test_logs) {
+
+ document << " <tr>\n"
+ " <td>\n";
+
+ std::string log_file = log_file_path(explicit_markup, log, runner_id);
+ if(!log_file.empty()) {
+
+ document << " <a href=\"../" << escape_uri(log_file) << "\">\n"
+ " " << escape_xml(log.target_directory) << "\n"
+ " </a>\n";
+
+ } else {
+
+ document << " " << escape_xml(log.target_directory) << "\n";
+
+ }
+
+ document << " </td>\n"
+ " </tr>\n";
+
+ }
+
+ document << " </table>\n"
+ " </body>\n"
+ "</html>\n";
+}
+
+// okay
+const test_structure_t::target_t* lookup_target(const test_structure_t::test_log_t& test_log, const std::string& name) {
+ boost::unordered_map<std::string, test_structure_t::target_t>::const_iterator pos = test_log.targets.find(name);
+ if(pos != test_log.targets.end()) {
+ return &pos->second;
+ } else {
+ return 0;
+ }
+}
+
+// requires: path is a valid path
+// requires: revision is an SVN revision
+void write_test_result_file(const boost::posix_time::ptime& run_date,
+ const failures_markup_t& explicit_markup,
+ const std::string& path,
+ const test_structure_t::test_log_t& test_log,
+ const std::string& runner_id,
+ const std::string& revision,
+ const boost::posix_time::ptime& timestamp)
+{
+ //utils::log(boost::format(" Writing log file document %s") % path);
+
+ html_writer document(path);
+
+ std::string component = output_page_header(test_log, runner_id);
+ int age = timestamp_difference(timestamp, run_date);
+
+ document << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\">\n"
+ "<html>\n";
+
+ document << " <head>\n"
+ " <link rel=\"stylesheet\" type=\"text/css\" href=\"../master.css\" title=\"master\" />\n"
+ " <title>Test output: " << escape_xml(component) << "</title>\n"
+ " </head>\n";
+
+ document << " <body>\n"
+ " <div class=\"log-test-header\">\n"
+ " <div class=\"log-test-title\">\n"
+ " Test output: " << escape_xml(component) << "\n"
+ " </div>\n"
+ " <div><span class=\"timestamp-" << age << "\">\n"
+ " Rev " << revision << " /\n"
+ " " << format_timestamp(timestamp) << "\n"
+ " </span></div>\n"
+ " </div>\n";
+
+ document << " <div>\n"
+ " <b>Report Time: </b> " << format_timestamp(run_date) << "\n"
+ " </div>\n";
+
+ if(!test_log.notes.empty()) {
+
+ document << " <p>\n"
+ " <div class=\"notes-title\">Notes</div>\n";
+
+ show_notes(document, test_log.notes, explicit_markup);
+
+ document << " </p>\n";
+
+ }
+
+ if(const test_structure_t::target_t* compile = lookup_target(test_log, "compile")) {
+ const char* compile_result = compile->result? "succeed" : "fail";
+ document << " <p>\n";
+ document << " <div class=\"log-compiler-output-title\">Compile [" << escape_xml(compile->timestamp) << "]:"
+ " <span class=\"output-" << compile_result << "\">" << compile_result << "</span></div>\n";
+ document << " <pre>\n";
+ write_contents(document, compile->contents, true);
+ document << " </pre>\n";
+ document << " </p>\n";
+ }
+
+ if(const test_structure_t::target_t* link = lookup_target(test_log, "link")) {
+ const char* link_result = link->result? "succeed" : "fail";
+ document << " <p>\n";
+ document << " <div class=\"log-linker-output-title\">Link [" << escape_xml(link->timestamp) << "]:"
+ " <span class=\"output-" << link_result << "\">" << link_result << "</span></div>\n";
+ document << " <pre>\n";
+ write_contents(document, link->contents, true);
+ document << " </pre>\n";
+ document << " </p>\n";
+ }
+
+ if(const test_structure_t::target_t* lib = lookup_target(test_log, "lib")) {
+ const char* lib_result = lib->result? "succeed" : "fail";
+ std::string lib_name(lib->contents->value(), lib->contents->value_size());
+ document << " <p>\n";
+ document << " <div class=\"log-linker-output-title\">Lib [" << escape_xml(lib->timestamp) << "]:"
+ " <span class=\"output-" << lib_result << "\">" << lib_result << "</span></div>\n";
+ document << " <p>\n";
+ document << " See <a href=\"" << escape_uri(encode_path(runner_id + "-" + lib_name)) << ".html\">\n";
+ document << " " << escape_xml(lib_name) << "\n";
+ document << " </a>\n";
+ document << " </p>\n";
+ document << " </p>\n";
+ }
+
+ if(const test_structure_t::target_t* run = lookup_target(test_log, "run")) {
+ const char* run_result = run->result? "succeed" : "fail";
+ document << " <p>\n";
+ document << " <div class=\"log-linker-output-title\">Run [" << escape_xml(run->timestamp) << "]:"
+ " <span class=\"output-" << run_result << "\">" << run_result << "</span></div>\n";
+ document << " <pre>\n";
+ write_contents(document, run->contents, true);
+ document << " </pre>\n";
+ document << " </p>\n";
+ }
+
+ document << make_tinyurl;
+
+ document << " </body>\n";
+ document << "</html>\n";
+}
+
+// requires path is a valid path
+// requires: log_file_path is the location of the log file relative to path
+void write_test_results_reference_file(const std::string& path, const std::string& log_file_path)
+{
+ html_writer document(path);
+
+ document << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\">\n"
+ "<html>\n"
+ " <head>\n"
+ " <link rel=\"stylesheet\" type=\"text/css\" href=\"../master.css\" title=\"master\" />\n"
+ " </head>\n"
+ " <frameset cols=\"190px,*\" frameborder=\"0\" framespacing=\"0\" border=\"0\">\n"
+ " <frame name=\"tocframe\" src=\"../toc.html\" scrolling=\"auto\"/>\n"
+ " <frame name=\"docframe\" src=\"../../" << escape_uri(log_file_path) << "\" scrolling=\"auto\"/>\n"
+ " </frameset>\n"
+ "</html>\n";
+}
+
+}
+
+// okay
+void boost::regression::links_page(
+ const boost::posix_time::ptime& run_date,
+ const failures_markup_t& explicit_markup,
+ const test_structure_t::run_t& test_run)
+{
+ BOOST_FOREACH(const test_structure_t::toolset_group_t::const_reference toolset, test_run.toolsets) {
+ BOOST_FOREACH(const test_structure_t::toolset_t::const_reference library, toolset.second) {
+ BOOST_FOREACH(const test_structure_t::library_t::const_reference test_case, library.second) {
+ ::links_page(run_date,
+ explicit_markup,
+ test_run.runner,
+ test_run.revision,
+ test_run.timestamp,
+ library.first,
+ toolset.first,
+ test_case.first,
+ test_case.second);
+ }
+ }
+ }
+ BOOST_FOREACH(const test_structure_t::toolset_group_t::const_reference toolset, test_run.non_test_case_targets) {
+ BOOST_FOREACH(const test_structure_t::toolset_t::const_reference library, toolset.second) {
+ BOOST_FOREACH(const test_structure_t::library_t::const_reference test_case, library.second) {
+ ::links_page(run_date,
+ explicit_markup,
+ test_run.runner,
+ test_run.revision,
+ test_run.timestamp,
+ library.first,
+ toolset.first,
+ test_case.first,
+ test_case.second);
+ }
+ }
+ }
+}

Added: trunk/tools/regression/src/report/links_page.hpp
==============================================================================
--- (empty file)
+++ trunk/tools/regression/src/report/links_page.hpp 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
@@ -0,0 +1,26 @@
+// links_page.hpp
+//
+// Copyright (c) 2010 Steven Watanabe
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanyiong file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef LINKS_PAGE_HPP_INCLUDED
+#define LINKS_PAGE_HPP_INCLUDED
+
+#include "xml.hpp"
+#include <boost/filesystem/path.hpp>
+
+namespace boost {
+namespace regression {
+
+void links_page(
+ const boost::posix_time::ptime& run_date,
+ const failures_markup_t& explicit_markup,
+ const test_structure_t::run_t& test_run);
+
+}
+}
+
+#endif

Added: trunk/tools/regression/src/report/produce_expected_results.cpp
==============================================================================
--- (empty file)
+++ trunk/tools/regression/src/report/produce_expected_results.cpp 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
@@ -0,0 +1,28 @@
+// Copyright MetaCommunications, Inc. 2003-2005.
+// Copyright Steven Watanabe 2013
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "produce_expected_results.hpp"
+#include "html_writer.hpp"
+#include <iostream>
+
+void boost::regression::produce_expected_results(const test_structure_t& tests) {
+ std::cout << "Warning: expected results not implemented" << std::endl;
+ return;
+
+ html_writer document("expected_results.xml");
+ document << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
+ document << "<root>\n";
+ document << " <expected-failures>\n";
+#if 0
+ foreach test-log
+ <xsl:if test="meta:is_test_log_a_test_case(.)">
+ <test-result library="{@library}" test-name="{@test-name}" toolset="{@toolset}" result="{@result}" />
+ </xsl:if>
+#endif
+ document << " </expected-failures>\n";
+ document << "</root>\n";
+}

Added: trunk/tools/regression/src/report/produce_expected_results.hpp
==============================================================================
--- (empty file)
+++ trunk/tools/regression/src/report/produce_expected_results.hpp 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
@@ -0,0 +1,22 @@
+// result_page.cpp
+//
+// Copyright Steven Watanabe 2013
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_REGRESSION_PRODUCE_EXPECTED_RESULTS_HPP
+#define BOOST_REGRESSION_PRODUCE_EXPECTED_RESULTS_HPP
+
+#include "xml.hpp"
+
+namespace boost {
+namespace regression {
+
+void produce_expected_results(const test_structure_t& tests);
+
+}
+}
+
+#endif

Added: trunk/tools/regression/src/report/result_page.cpp
==============================================================================
--- (empty file)
+++ trunk/tools/regression/src/report/result_page.cpp 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
@@ -0,0 +1,513 @@
+// result_page.cpp
+//
+// Copyright MetaCommunications, Inc. 2003-2007.
+// Copyright Steven Watanabe 2010-2011
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "result_page.hpp"
+#include "common.hpp"
+#include "html.hpp"
+#include "html_writer.hpp"
+#include "xml.hpp"
+#include <boost/foreach.hpp>
+#include <boost/unordered_map.hpp>
+#include <set>
+#include <map>
+#include <string>
+#include <vector>
+#include <utility>
+#include <iostream>
+#include <fstream>
+
+using namespace boost::regression;
+
+namespace {
+
+// safe: no assumptions, no unconstrained output
+void test_type_col(html_writer& document, const std::string& test_type) {
+ document << "<td class=\"test-type\">\n";
+ document << " <a href=\"http://www.boost.org/status/compiler_status.html#Understanding\" class=\"legend-link\" target=\"_top\">";
+
+ if(test_type == "run_pyd") {
+ document << "r";
+ } else if(test_type == "run_mpi") {
+ document << "r";
+ } else if(test_type == "run") {
+ document << "r";
+ } else if(test_type == "run_fail") {
+ document << "rf";
+ } else if(test_type == "compile") {
+ document << "c";
+ } else if(test_type == "compile_fail") {
+ document << "cf";
+ } else if(test_type == "link") {
+ document << "l";
+ } else if(test_type == "link_fail") {
+ document << "lf";
+ } else {
+ throw std::runtime_error("Incorrect test type \"" + test_type + "\"");
+ }
+
+ document << " </a>\n";
+ document << "</td>\n";
+}
+
+// category/name
+typedef std::pair<std::string, std::string> test_case_id_t;
+// runner/toolset
+typedef std::pair<std::string, std::string> test_toolset_id_t;
+
+typedef std::vector<const test_structure_t::test_log_t*> test_log_group_t;
+typedef boost::unordered_map<test_toolset_id_t, test_log_group_t> test_logs_by_run_t;
+typedef std::map<test_case_id_t, test_logs_by_run_t> test_logs_t;
+
+// requires: result contains no HTML special characters
+// requires: log_link must not contain a '/' derived from the input (This won't actually break anything, though)
+void insert_cell_link(html_writer& document, const std::string& result, const std::string& log_link) {
+ if(log_link != "") {
+ document << "&#160;&#160;"
+ "<a href=\"" << escape_uri(log_link) << "\" class=\"log-link\" target=\"_top\">"
+ << result <<
+ "</a>"
+ "&#160;&#160;";
+ } else {
+ document << "&#160;&#160;" << result << "&#160;&#160;";
+ }
+}
+
+// requires:
+void insert_cell_developer(html_writer& document,
+ const failures_markup_t& explicit_markup,
+ bool release,
+ const std::string& library,
+ const std::string& test_name,
+ const std::string& runner,
+ const std::string& toolset,
+ const test_log_group_t& test_logs) {
+ std::string class_ = "library-" + result_cell_class(explicit_markup, library, toolset, test_logs);
+
+ std::string cell_link = (test_logs.size() > 1)?
+ encode_path(runner + "-" + library + "-" + toolset + "-" + test_logs.front()->test_name + "-variants_" + release_postfix(release)) + ".html" :
+ (test_logs.empty())?
+ std::string("") :
+ log_file_path(explicit_markup, *test_logs.front(), runner, release_postfix(release));
+
+ document << "<td class=\"" << class_ << "\" title=\"" << escape_xml(test_name) << "/" << escape_xml(toolset) << "\">\n";
+
+ if(is_unusable(explicit_markup, library, toolset)) {
+ insert_cell_link(document, "n/a", cell_link);
+ } else if(test_logs.empty()) {
+ document << "&#160;&#160;&#160;&#160;\n";
+ } else {
+ BOOST_FOREACH(test_log_group_t::value_type log, test_logs) {
+ if(!log->result && log->status) {
+ insert_cell_link(document, (log->expected_reason != "")? "fail?" : "fail*", cell_link);
+ goto done;
+ }
+ }
+ BOOST_FOREACH(test_log_group_t::value_type log, test_logs) {
+ if(!log->result && !log->status) {
+ insert_cell_link(document, "fail", cell_link);
+ goto done;
+ }
+ }
+ insert_cell_link(document, "pass", cell_link);
+ }
+done:
+ document << "</td>\n";
+}
+
+// requires:
+void insert_cell_user(html_writer& document,
+ const failures_markup_t& explicit_markup,
+ bool release,
+ const std::string& library,
+ const std::string& test_name,
+ const std::string& runner,
+ const std::string& toolset,
+ const test_log_group_t& test_logs) {
+ std::string class_ = "library-" + result_cell_class(explicit_markup, library, toolset, test_logs);
+
+ std::string cell_link = (test_logs.size() > 1)?
+ encode_path(runner + "-" + library + "-" + toolset + "-" + test_logs.front()->test_name + "-variants_" + release_postfix(release)) + ".html" :
+ (test_logs.empty())?
+ std::string("") :
+ log_file_path(explicit_markup, *test_logs.front(), runner, release_postfix(release));
+
+ document << "<td class=\"" << class_ << " user-" << class_ << "\" title=\"" << escape_xml(test_name) << "/" << escape_xml(toolset) << "\">\n";
+
+ if(is_unusable(explicit_markup, library, toolset)) {
+ insert_cell_link(document, "unusable", cell_link);
+ } else if(test_logs.empty()) {
+ document << "&#160;&#160;&#160;&#160;\n";
+ } else {
+ BOOST_FOREACH(test_log_group_t::value_type log, test_logs) {
+ if(!log->result && log->status) {
+ insert_cell_link(document, (log->expected_reason != "")? "fail?" : "fail*", cell_link);
+ goto done;
+ }
+ }
+ BOOST_FOREACH(test_log_group_t::value_type log, test_logs) {
+ if(!log->result && !log->status) {
+ insert_cell_link(document, "fail", cell_link);
+ goto done;
+ }
+ }
+ insert_cell_link(document, "pass", cell_link);
+ }
+done:
+ document << "</td>\n";
+}
+
+// requires: line_mod should be from an enumerated set
+// requires: source is a branch of svn
+// requires: mode = developer | user
+void insert_test_line(html_writer& document,
+ const failures_markup_t& explicit_markup,
+ bool release,
+ const std::string& library,
+ test_logs_t::const_reference test_results,
+ const std::vector<std::pair<std::string, std::string> >& all_toolsets,
+ const std::string& line_mod,
+ const std::string& source,
+ const std::string& mode) {
+ // This is guaranteed to exist because of the way the nested maps are created
+ const test_structure_t::test_log_t * first_log = (*test_results.second.begin()).second.front();
+ std::string test_program(first_log->test_program);
+
+ std::string test_header =
+ "<td class=\"test-name\">\n"
+ " <a href=\"http://svn.boost.org/svn/boost/" + source + "/" + escape_uri(test_program) + "\" class=\"test-link\" target=\"_top\">\n"
+ " " + escape_xml(test_results.first.second) + "\n" // FIXME: sanitize test name
+ " </a>\n"
+ "</td>\n";
+
+ document << "<tr class=\"library-row" << line_mod << "\">\n"
+ << test_header;
+
+ test_log_group_t empty_test_log;
+ test_type_col(document, first_log->test_type);
+ BOOST_FOREACH(const test_toolset_id_t& run, all_toolsets) {
+ const std::string& toolset = run.second;
+ const std::string& runner = run.first;
+
+ test_logs_by_run_t::const_iterator pos = test_results.second.find(run);
+
+ const test_log_group_t* test_result_for_toolset =
+ (pos != test_results.second.end())?
+ &pos->second :
+ &empty_test_log;
+
+ if(mode == "user") {
+ insert_cell_user(document, explicit_markup, release, library, test_results.first.second, runner, toolset, *test_result_for_toolset);
+ } else {
+ insert_cell_developer(document, explicit_markup, release, library, test_results.first.second, runner, toolset, *test_result_for_toolset);
+ }
+ }
+
+ document << test_header
+ << "</tr>\n";
+}
+
+// requires: source is a branch of svn
+// requires: mode = developer | user
+void insert_test_section(html_writer& document,
+ const test_structure_t& test_structure,
+ const failures_markup_t& explicit_markup,
+ bool release,
+ const std::string& library,
+ const test_logs_t& logs,
+ const std::vector<std::pair<std::string, std::string> >& all_toolsets,
+ const std::string& source,
+ const std::string& mode) {
+ std::size_t category_span = 3;
+ BOOST_FOREACH(test_structure_t::platform_group_t::const_reference platform, test_structure.platforms) {
+ BOOST_FOREACH(test_structure_t::platform_t::const_reference run, platform.second) {
+ category_span += (run.toolsets.size());
+ }
+ }
+
+ for(test_logs_t::const_iterator pos = logs.begin(), end = logs.end(); pos != end; ++pos) {
+ std::string test_name = pos->first.second;
+ bool category_start = (pos == logs.begin()) || (pos->first.first != boost::prior(pos)->first.first);
+ bool category_end = (boost::next(pos) == end) || (pos->first.first != boost::next(pos)->first.first);
+
+ std::string line_mod =
+ (category_start && category_end)? "-single" :
+ category_start? "-first" :
+ category_end? "-last" :
+ "";
+
+ if(category_start && pos->first.first != "0") {
+ document << "<tr>\n"
+ " <td class=\"library-test-category-header\" colspan=\"" << category_span << "\" align=\"center\">\n"
+ " " << escape_xml(pos->first.first) << "\n"
+ " </td>\n"
+ "</tr>\n";
+ }
+
+ insert_test_line(document, explicit_markup, release, library, *pos, all_toolsets, line_mod, source, mode);
+ }
+}
+
+}
+
+// requires: mode = developer | user
+// requires: source = Boost SVN branch name
+void boost::regression::result_page(const test_structure_t& tests,
+ const failures_markup_t& explicit_markup,
+ bool release,
+ const std::string& source,
+ const boost::posix_time::ptime& run_date,
+ const std::vector<std::string>& warnings,
+ const std::string& mode,
+ const boost::filesystem::path& comment_file)
+{
+ // skip debug.xml
+
+ std::string index_path("index" + release_postfix(release) + "_.html");
+
+ {
+
+ std::cout << "Writing document " << "index" << release_postfix(release) << ".html" << std::endl;
+
+ html_writer index(mode + "/" + "index" + release_postfix(release) + ".html");
+ index << "<head>\n"
+ " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n"
+ " <link rel=\"stylesheet\" type=\"text/css\" href=\"../master.css\" title=\"master\" />\n"
+ " <title>Boost regression: " << source << "</title>\n"
+ "</head>\n"
+ "<frameset cols=\"190px,*\" frameborder=\"0\" framespacing=\"0\" border=\"0\">\n"
+ " <frame name=\"tocframe\" src=\"toc" << release_postfix(release) << ".html\" scrolling=\"auto\"/>\n"
+ " <frame name=\"docframe\" src=\"" << index_path << "\" scrolling=\"auto\"/>\n"
+ "</frameset>\n";
+ }
+
+ std::cout << "Writing document " << index_path << std::endl;
+
+ {
+ html_writer index(mode + "/" + index_path);
+ index << "<html>\n"
+ "<head>\n"
+ " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n"
+ " <link rel=\"stylesheet\" type=\"text/css\" href=\"../master.css\" title=\"master\" />\n"
+ "</head>\n"
+ "<body>\n"
+ "\n"
+ " <img border=\"0\" src=\"http://www.boost.org/boost.png\" width=\"277\" height=\"86\" align=\"right\" alt=\"Boost logo\"></img>\n"
+ "\n"
+ " <h1 class=\"page-title\">\n"
+ << mode << " report: "
+ " <a class=\"hover-link\" href=\"summary.html\" target=\"_top\">" << source << "</a>\n"
+ " </h1>\n"
+ "\n";
+
+ std::string purpose = (mode == "user")?
+ "The purpose of this report is to help a user to find out whether a particular library "
+ "works on the particular compiler(s). For SVN \"health report\", see "
+ " <a href=\"../developer/index.html\" target=\"_top\">developer summary</a>."
+ :
+ "Provides Boost developers with visual indication of the SVN \"health\". For user-level "
+ "report, see <a href=\"../user/index.html\" target=\"_top\">user summary</a>.";
+
+ insert_report_header(index, run_date, warnings, purpose);
+
+ index << " <div class=\"comment\">\n";
+ if(comment_file != "") {
+ std::ifstream comment(comment_file.string().c_str());
+ if(!comment) {
+ throw std::ios_base::failure("Could not open file " + comment_file.string());
+ }
+ std::string comment_data(std::istreambuf_iterator<char>(comment.rdbuf()), std::istreambuf_iterator<char>());
+ index << comment_data;
+ }
+
+ index << "</body>\n";
+ index << "</html>\n";
+ }
+
+ std::set<std::string> libraries;
+ get_libraries(tests, libraries);
+
+ if(libraries.size() > 1) {
+ std::string toc_path("toc" + release_postfix(release) + ".html");
+
+ std::cout << "Writing document " << toc_path << std::endl;
+
+ html_writer toc(mode + "/" + toc_path);
+
+ toc << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\">\n"
+ << "<html>\n"
+ << "<head>\n"
+ << " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n"
+ << " <link rel=\"stylesheet\" type=\"text/css\" href=\"../master.css\" title=\"master\"/>\n"
+ << "</head>\n"
+ << "<body class=\"" << mode << "-toc\">\n"
+ << " <div class=\"toc-header-entry\">\n"
+ << " <a href=\"index" << release_postfix(release) << ".html\" class=\"toc-entry\" target=\"_top\">Report info</a>\n"
+ << " </div>\n"
+ << " <div class=\"toc-header-entry\">\n"
+ << " <a href=\"summary" << release_postfix(release) << ".html\" class=\"toc-entry\" target=\"_top\">Summary</a>\n"
+ << " </div>\n";
+
+ if(mode == "developer") {
+ toc << " <div class=\"toc-header-entry\">\n"
+ " <a href=\"issues.html\" class=\"toc-entry\" target=\"_top\">Unresolved issues</a>\n"
+ " </div>\n";
+ }
+
+ toc << " <div class=\"toc-header-entry\">\n";
+
+ insert_view_link(toc, "index", "toc-entry", release);
+
+ toc << " </div>\n";
+
+ toc << " <hr/>\n";
+
+ BOOST_FOREACH(const std::string& library, libraries) {
+ std::string library_page(encode_path(library));
+ toc << " <div class=\"toc-entry\">\n"
+ " <a href=\"" << escape_uri(library_page) << release_postfix(release) << ".html\" class=\"toc-entry\" target=\"_top\">\n"
+ " " << escape_xml(library) << "\n"
+ " </a>\n"
+ " </div>\n";
+ }
+
+ toc << "</body>\n"
+ "</html>\n";
+ }
+
+ BOOST_FOREACH(const std::string& library, libraries) {
+ if(show_library(explicit_markup, library, release)) {
+
+ std::string library_results(encode_path(library) + release_postfix(release) + "_.html");
+ std::string library_page(encode_path(library) + release_postfix(release) + ".html");
+
+ std::cout << "Writing document " << library_page << std::endl;
+
+ {
+ html_writer document(mode + "/" + library_page);
+
+ document << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\">\n"
+ "<html>\n"
+ "<head>\n"
+ " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n"
+ " <link rel=\"stylesheet\" type=\"text/css\" href=\"../master.css\" title=\"master\"/>\n"
+ " <title>Boost regression: " << escape_xml(library) << "/" << source << "</title>\n"
+ "</head>\n"
+ "<frameset cols=\"190px,*\" frameborder=\"0\" framespacing=\"0\" border=\"0\">\n"
+ "<frame name=\"tocframe\" src=\"toc" << release_postfix(release) << ".html\" scrolling=\"auto\"/>\n"
+ "<frame name=\"docframe\" src=\"" << escape_uri(library_results) << "\" scrolling=\"auto\"/>\n"
+ "</frameset>\n"
+ "</html>\n";
+ }
+
+ std::cout << "Writing document " << library_results << std::endl;
+
+ {
+ html_writer document(mode + "/" + library_results);
+
+ document << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\">\n"
+ "<html>\n"
+ "<head>\n"
+ " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n"
+ " <link rel=\"stylesheet\" type=\"text/css\" href=\"../master.css\" title=\"master\" />\n"
+ "</head>\n"
+ "\n"
+ "<body>\n";
+
+ insert_page_links(document, encode_path(library), release, alternate_mode(mode));
+
+ document << "<h1 class=\"page-title\">\n"
+ " <a class=\"hover-link\" name=\"" << escape_xml(library) << "\" href=\"http://www.boost.org/libs/" << escape_uri(library) << "\" target=\"_top\">"
+ << escape_xml(library) << "\n"
+ "</a>"
+ "/"
+ "<a class=\"hover-link\" href=\"summary.html\" target=\"_top\">" << source << "</a>\n"
+ "</h1>\n";
+
+ insert_report_header(document, run_date, warnings);
+
+ // toolset/note/index
+ boost::unordered_map<std::string, std::size_t> library_marks;
+ std::vector<node_ptr> notes;
+ get_unusable(explicit_markup, library, tests, library_marks, notes);
+
+ document << "<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"library-table\" width=\"1%\" summary=\"Library results\">\n"
+ " <thead>\n";
+
+ insert_runners_rows(document, "details", "top", tests, run_date); // okay
+ insert_toolsets_row(document, tests, explicit_markup, "details", run_date, library, library_marks);
+
+ document << " </thead>\n"
+ " <tfoot>\n";
+
+ insert_toolsets_row(document, tests, explicit_markup, "details", run_date, library, library_marks);
+ insert_runners_rows(document, "details", "bottom", tests, run_date);
+ document << " </tfoot>\n"
+ " <tbody>\n";
+
+ test_logs_t lib_tests;
+ std::vector<std::pair<std::string, std::string> > all_toolsets;
+ BOOST_FOREACH(test_structure_t::platform_group_t::const_reference platform, tests.platforms) {
+ BOOST_FOREACH(test_structure_t::platform_t::const_reference run, platform.second) {
+ BOOST_FOREACH(test_structure_t::toolset_group_t::const_reference toolset, run.toolsets) {
+ all_toolsets.push_back(std::make_pair(run.runner, toolset.first));
+ test_structure_t::toolset_t::const_iterator pos = toolset.second.find(library);
+ if(pos != toolset.second.end()) {
+ BOOST_FOREACH(test_structure_t::library_t::const_reference test_case, pos->second) {
+ test_log_group_t test_logs;
+ BOOST_FOREACH(test_structure_t::test_case_t::const_reference log, test_case.second) {
+ if(is_test_log_a_test_case(log)) {
+ test_logs.push_back(&log);
+ }
+ }
+ if(!test_logs.empty()) {
+ std::string category = test_logs.front()->category;
+ lib_tests[std::make_pair(category, test_case.first)][std::make_pair(run.runner, toolset.first)] = test_logs;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ insert_test_section(document, tests, explicit_markup, release, library, lib_tests, all_toolsets, source, mode);
+
+ document << " </tbody>\n"
+ "</table>\n";
+
+ if(!notes.empty()) {
+ document << "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" class=\"library-library-notes\" summary=\"library notes\">\n";
+ for(std::size_t i = 0; i < notes.size(); ++i) {
+ document << "<tr class=\"library-library-note\">\n"
+ " <td valign=\"top\" width=\"3em\">\n"
+ " <a name=\"" << escape_uri(library) << "-note-" << (i + 1) << "\">\n"
+ " <span class=\"super\">" << (i + 1) << "</span>\n"
+ " </a>\n"
+ " </td>\n"
+ " <td>\n";
+ std::string refid;
+ lookup_attr(notes[i], "refid", refid);
+ show_note(document, notes[i], refid, explicit_markup);
+ document << " </td>\n"
+ "</tr>\n";
+ }
+ document << "</table>\n";
+ }
+
+ document << "<div id=\"legend\">\n"
+ << (mode == "developer"? library_developer_legend : library_user_legend) << "\n"
+ "</div>\n";
+
+ insert_page_links(document, encode_path(library), release, alternate_mode(mode));
+
+ document << "</body>\n";
+ document << "</html>\n";
+ }
+ }
+ }
+}

Added: trunk/tools/regression/src/report/result_page.hpp
==============================================================================
--- (empty file)
+++ trunk/tools/regression/src/report/result_page.hpp 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
@@ -0,0 +1,29 @@
+// result_page.cpp
+//
+// Copyright MetaCommunications, Inc. 2003-2007.
+// Copyright Steven Watanabe 2010-2011
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/filesystem/path.hpp>
+#include <boost/date_time/posix_time/ptime.hpp>
+#include <string>
+#include <vector>
+#include "xml.hpp"
+
+namespace boost {
+namespace regression {
+
+void result_page(const test_structure_t& tests,
+ const failures_markup_t& explicit_markup,
+ bool release,
+ const std::string& source,
+ const boost::posix_time::ptime& run_date,
+ const std::vector<std::string>& warnings,
+ const std::string& mode,
+ const boost::filesystem::path& comment_file);
+
+}
+}

Added: trunk/tools/regression/src/report/runners.cpp
==============================================================================
--- (empty file)
+++ trunk/tools/regression/src/report/runners.cpp 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
@@ -0,0 +1,53 @@
+// Copyright MetaCommunications, Inc. 2003-2004.
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "runners.hpp"
+#include "html_writer.hpp"
+#include "common.hpp"
+#include <boost/foreach.hpp>
+#include <iostream>
+
+void boost::regression::runners(const test_structure_t& tests) {
+ {
+ html_writer document("runners.html");
+ document << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\">\n"
+ "<html>\n"
+ " <body bgcolor=\"#FFFFFF\">\n";
+ BOOST_FOREACH(test_structure_t::platform_group_t::const_reference platform, tests.platforms) {
+ BOOST_FOREACH(test_structure_t::platform_t::const_reference run, platform.second) {
+ document << " <table>"
+ "<tr>"
+ "<td>"
+ "<a href=\"" << escape_uri(encode_path(run.runner)) << ".html\">" << escape_xml(run.runner) << "</a>"
+ "</td>"
+ "</tr>"
+ "</table>\n";
+ }
+ }
+ document << " </body>\n"
+ "</html>\n";
+ }
+ BOOST_FOREACH(test_structure_t::platform_group_t::const_reference platform, tests.platforms) {
+ BOOST_FOREACH(test_structure_t::platform_t::const_reference run, platform.second) {
+
+ std::cout << "Writing runner document " << encode_path(run.runner) << ".html" << std::endl;
+
+ html_writer document(encode_path(run.runner) + ".html");
+
+ document << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\">\n"
+ "<html>\n"
+ " <head>\n"
+ "<title>" << escape_xml(run.runner) << "</title>\n"
+ "</head>\n"
+ "<body>\n"
+ "<h1>" << escape_xml(run.runner) << "</h1>\n"
+ "<hr></hr>"
+ << run.comment // Intentionally not escaped--contains html formatting
+ << "</body>\n"
+ "</html>\n";
+ }
+ }
+}

Added: trunk/tools/regression/src/report/runners.hpp
==============================================================================
--- (empty file)
+++ trunk/tools/regression/src/report/runners.hpp 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
@@ -0,0 +1,22 @@
+// result_page.cpp
+//
+// Copyright Steven Watanabe 2013
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_REGRESSION_RUNNERS_HPP
+#define BOOST_REGRESSION_RUNNERS_HPP
+
+#include "xml.hpp"
+
+namespace boost {
+namespace regression {
+
+void runners(const test_structure_t& tests);
+
+}
+}
+
+#endif

Added: trunk/tools/regression/src/report/summary_page.cpp
==============================================================================
--- (empty file)
+++ trunk/tools/regression/src/report/summary_page.cpp 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
@@ -0,0 +1,259 @@
+// Copyright MetaCommunications, Inc. 2003-2004.
+// Copyright Steven Watanabe 2013
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/foreach.hpp>
+#include <boost/next_prior.hpp>
+#include "common.hpp"
+#include "summary_page.hpp"
+#include "html_writer.hpp"
+#include "html.hpp"
+#include <iostream>
+
+using namespace boost::regression;
+
+namespace {
+
+// report developer status
+// safe
+void insert_cell_developer(html_writer& document,
+ const failures_markup_t& explicit_markup,
+ const std::string& library,
+ const std::string& toolset,
+ const test_structure_t::library_t& current_cell,
+ bool release) {
+
+ std::string class_ = "summary-" + result_cell_class(explicit_markup, library, toolset, current_cell);
+
+ std::string library_page = encode_path(library);
+
+ document << "<td class=\"" << class_ << "\" title=\"" << escape_xml(library) << "/" << escape_xml(toolset) << "\">\n";
+
+ if(class_ == "summary-unusable") {
+ document << "&#160;&#160;"
+ "<a href=\"" << escape_uri(library_page) << release_postfix(release) << ".html\" class=\"log-link\" target=\"_top\">"
+ "n/a"
+ "</a>"
+ "&#160;&#160;";
+ } else if(class_ == "summary-missing") {
+ document << "&#160;&#160;&#160;&#160;";
+ } else if(class_ == "summary-fail-unexpected") {
+ document << "<a href=\"" << escape_uri(library_page) << release_postfix(release) << ".html\" class=\"log-link\" target=\"_top\">"
+ "broken"
+ "</a>";
+ } else if(class_ == "summary-fail-unexpected-new") {
+ document << "&#160;&#160;"
+ "<a href=\"" << escape_uri(library_page) << release_postfix(release) << ".html\" class=\"log-link\" target=\"_top\">"
+ "fail"
+ "</a>"
+ "&#160;&#160;";
+ } else {
+ document << "&#160;&#160;OK&#160;&#160;";
+ }
+ document << "</td>\n";
+}
+
+// report user status
+// safe
+void insert_cell_user(html_writer& document,
+ const failures_markup_t& explicit_markup,
+ const std::string& library,
+ const std::string& toolset,
+ const test_structure_t::library_t& current_cell,
+ bool release) {
+ std::string class_ = "summary-" + result_cell_class(explicit_markup, library, toolset, current_cell);
+
+ std::string library_page = encode_path(library);
+
+ document << "<td class=\"" << class_ << " user-" << class_ << "\" title=\"" << escape_xml(library) << "/" << escape_xml(toolset) << "\">\n";
+
+ if(class_ == "summary-unusable") {
+ document << "&#160;"
+ "<a href=\"" << escape_uri(library_page) << release_postfix(release) << ".html\" class=\"log-link\" target=\"_top\">"
+ "unusable"
+ "</a>"
+ "&#160;";
+ } else if(class_ == "summary-missing") {
+ document << "&#160;no&#160;results&#160;";
+ } else if(class_ == "summary-fail-unexpected") {
+ document << "&#160;"
+ "<a href=\"" << escape_uri(library_page) << release_postfix(release) << ".html\" class=\"log-link\" target=\"_top\">"
+ "regress."
+ "</a>"
+ "&#160;";
+ } else if(class_ == "summary-fail-unexpected-new" ||
+ class_ == "summary-fail-expected" ||
+ class_ == "summary-unknown-status" ||
+ class_ == "summary-fail-unexpected-unresearched") {
+ document << "&#160;"
+ "<a href=\"" << escape_uri(library_page) << release_postfix(release) << ".html\" class=\"log-link\" target=\"_top\">"
+ "details"
+ "</a>"
+ "&#160;";
+ } else {
+ document << "&#160;pass&#160;";
+ }
+ document << "</td>\n";
+}
+
+}
+
+// requires: mode = developer | user
+// requires: source is the name of an SVN branch
+void boost::regression::summary_page(const std::string& mode,
+ const std::string& source,
+ const boost::posix_time::ptime& run_date,
+ const std::vector<std::string>& warnings,
+ const test_structure_t& tests,
+ const failures_markup_t & explicit_markup,
+ bool release) {
+
+ std::set<std::string> sorted_libraries;
+ get_libraries(tests, sorted_libraries);
+
+ std::string summary_results("summary" + release_postfix(release) + "_.html");
+
+ std::cout << "Writing document " << "summary" << release_postfix(release) << ".html" << std::endl;
+
+ {
+ html_writer document(mode + "/" + "summary" + release_postfix(release) + ".html");
+
+ document << "<!DOCTYPE html PUBLIC \"-//W3C//DTD html 4.01 Transitional//EN\">\n"
+ "<html>\n"
+ " <head>\n"
+ " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n"
+ " <link rel=\"stylesheet\" type=\"text/css\" href=\"../master.css\" title=\"master\"/>\n"
+ " <title>Boost regression summary: " << source << "</title>\n"
+ " </head>\n"
+ " <frameset cols=\"190px,*\" frameborder=\"0\" framespacing=\"0\" border=\"0\">\n"
+ " <frame name=\"tocframe\" src=\"toc" << release_postfix(release) << ".html\" scrolling=\"auto\"/>\n"
+ " <frame name=\"docframe\" src=\"" << summary_results << "\" scrolling=\"auto\"/>\n"
+ " </frameset>\n"
+ "</html>\n";
+ }
+
+ // Summary results
+ std::cout << "Writing document " << summary_results << std::endl;
+
+ {
+ html_writer document(mode + "/" + summary_results);
+
+ document << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\">\n"
+ "<html>\n"
+ "<head>\n"
+ " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n"
+ " <link rel=\"stylesheet\" type=\"text/css\" href=\"../master.css\" title=\"master\"/>\n"
+ "</head>\n"
+ "<body>\n";
+
+ insert_page_links(document, "summary", release, alternate_mode(mode));
+
+ document << "<h1 class=\"page-title\">\n"
+ " Summary: \n"
+ " <a class=\"hover-link\" href=\"summary" << release_postfix(release) << ".html\" target=\"_top\">" << source << "</a>\n"
+ "</h1>\n";
+
+ insert_report_header(document, run_date, warnings);
+
+ std::size_t num_unusable = 0;
+ std::size_t num_regressions = 0;
+ std::size_t num_new_failures = 0;
+
+ BOOST_FOREACH(test_structure_t::platform_group_t::const_reference platform, tests.platforms) {
+ BOOST_FOREACH(test_structure_t::platform_t::const_reference run, platform.second) {
+ BOOST_FOREACH(test_structure_t::toolset_group_t::const_reference toolset, run.toolsets) {
+ BOOST_FOREACH(test_structure_t::toolset_t::const_reference library, toolset.second) {
+ bool unusable = is_unusable(explicit_markup, library.first, toolset.first);
+ BOOST_FOREACH(test_structure_t::library_t::const_reference test_case, library.second) {
+ BOOST_FOREACH(test_structure_t::test_case_t::const_reference test_log, test_case.second) {
+ if(unusable) ++num_unusable;
+ else if(!test_log.result && !test_log.status) {
+ if(test_log.is_new) ++num_new_failures;
+ else ++num_regressions;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ document << "<div class=\"statistics\">\n"
+ "Unusable: " << num_unusable << "\n"
+ "&#160;|&#160;\n"
+ "Regressions: " << num_regressions << "\n"
+ "&#160;|&#160;\n"
+ "New failures: " << num_new_failures << "\n"
+ "</div>\n";
+
+ // summary table
+
+ document << "<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\" width=\"1%\" class=\"summary-table\" summary=\"Overall summary\">\n";
+
+ document << "<thead>\n";
+ insert_runners_rows(document, "summary", "top", tests, run_date);
+ insert_toolsets_row(document, tests, explicit_markup, "summary", run_date);
+ document << "</thead>\n";
+
+ document << "<tfoot>\n";
+ insert_toolsets_row(document, tests, explicit_markup, "summary", run_date);
+ insert_runners_rows(document, "summary", "bottom", tests, run_date);
+ document << "</tfoot>\n";
+
+ document << "<tbody>\n";
+
+ BOOST_FOREACH(const std::string& library, sorted_libraries) {
+ std::string library_page = encode_path(library);
+
+ std::string library_header =
+ "<td class=\"library-name\">\n"
+ " <a href=\"" + escape_uri(library_page) + release_postfix(release) + ".html\" class=\"library-link\" target=\"_top\">\n"
+ " " + escape_xml(library) + "\n"
+ " </a>\n"
+ "</td>\n";
+
+ std::string line_mod;
+ if(sorted_libraries.size() == 1) line_mod = "-single";
+ else if(library == *sorted_libraries.begin()) line_mod = "-first";
+ else if(library == *boost::prior(sorted_libraries.end())) line_mod = "-last";
+
+ document << "<tr class=\"summary-row" << line_mod << "\">\n";
+ document << library_header;
+
+ test_structure_t::library_t empty_library;
+ BOOST_FOREACH(test_structure_t::platform_group_t::const_reference platform, tests.platforms) {
+ BOOST_FOREACH(test_structure_t::platform_t::const_reference run, platform.second) {
+ BOOST_FOREACH(test_structure_t::toolset_group_t::const_reference toolset, run.toolsets) {
+ test_structure_t::toolset_t::const_iterator pos = toolset.second.find(library);
+ const test_structure_t::library_t * current_cell =
+ (pos != toolset.second.end())?
+ &pos->second : &empty_library;
+ if(mode == "user") {
+ insert_cell_user(document, explicit_markup, library, toolset.first, *current_cell, release);
+ } else {
+ insert_cell_developer(document, explicit_markup, library, toolset.first, *current_cell, release);
+ }
+ }
+ }
+ }
+
+ document << library_header;
+ document << "</tr>\n";
+ }
+
+ document << "</tbody>\n";
+ document << "</table>\n";
+
+ document << "<div id=\"legend\">\n"
+ << (mode == "developer"? summary_developer_legend : summary_user_legend) << "\n"
+ "</div>\n";
+
+ insert_page_links(document, "summary", release, alternate_mode(mode));
+
+ document << "</body>\n";
+ document << "</html>\n";
+ }
+}

Added: trunk/tools/regression/src/report/summary_page.hpp
==============================================================================
--- (empty file)
+++ trunk/tools/regression/src/report/summary_page.hpp 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
@@ -0,0 +1,32 @@
+// result_page.cpp
+//
+// Copyright Steven Watanabe 2013
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_REGRESSION_SUMMARY_PAGE_HPP
+#define BOOST_REGRESSION_SUMMARY_PAGE_HPP
+
+#include <boost/filesystem/path.hpp>
+#include <boost/date_time/posix_time/ptime.hpp>
+#include <string>
+#include <vector>
+#include "xml.hpp"
+
+namespace boost {
+namespace regression {
+
+void summary_page(const std::string& mode,
+ const std::string& source,
+ const boost::posix_time::ptime& run_date,
+ const std::vector<std::string>& warnings,
+ const test_structure_t& tests,
+ const failures_markup_t & explicit_markup,
+ bool release);
+
+}
+}
+
+#endif

Added: trunk/tools/regression/src/report/xml.cpp
==============================================================================
--- (empty file)
+++ trunk/tools/regression/src/report/xml.cpp 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
@@ -0,0 +1,388 @@
+// xml.cpp
+//
+// Copyright (c) 2010 Steven Watanabe
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanyiong file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include "xml.hpp"
+#include "common.hpp"
+
+#include <boost/date_time/posix_time/time_parsers.hpp>
+#include <boost/functional/hash.hpp>
+#include <fstream>
+#include <boost/format.hpp>
+#include <boost/foreach.hpp>
+
+using namespace boost::regression;
+
+std::size_t boost::regression::hash_value(const test_case_t& test_case) {
+ std::size_t result = 0;
+ boost::hash_combine(result, test_case.test_name);
+ boost::hash_combine(result, test_case.library);
+ boost::hash_combine(result, test_case.toolset_name);
+ return result;
+}
+
+bool boost::regression::operator==(const test_case_t& lhs, const test_case_t& rhs) {
+ return lhs.test_name == rhs.test_name &&
+ lhs.library == rhs.library &&
+ lhs.toolset_name == rhs.toolset_name;
+}
+
+boost::regression::node_ptr boost::regression::lookup_element(node_ptr element, const std::string& name);
+
+boost::regression::attr_ptr boost::regression::lookup_attr(node_ptr element, const std::string& name) {
+ if(element == 0) return 0;
+ return element->first_attribute(name.data(), name.size());
+}
+
+bool boost::regression::lookup_attr(node_ptr element, const std::string& name, std::string& result) {
+ if(element == 0) return false;
+ if(attr_ptr attr = lookup_attr(element, name)) {
+ result = std::string(attr->value(), attr->value_size());
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void require_attr(node_ptr element, const std::string& name, std::string& result) {
+ if(!lookup_attr(element, name, result)) {
+ throw xml_error("Missing attribute " + name + " in element " + std::string(element->name(), element->name_size()));
+ }
+}
+
+bool boost::regression::check_attr(node_ptr element, const std::string& name, const std::string& expected) {
+ if(attr_ptr attr = lookup_attr(element, name)) {
+ return std::string(attr->value(), attr->value_size()) == expected;
+ } else {
+ return false;
+ }
+}
+
+bool boost::regression::check_name(node_ptr element, const std::string& name) {
+ return std::string(element->name(), element->name_size()) == name;
+}
+
+bool boost::regression::check_attr(node_ptr element,
+ const std::string& element1,
+ const std::string& attr,
+ const std::string& expected) {
+ if(element == 0) return false;
+ else if(element1 == "*") {
+ FOR_EACH_ELEMENT(nested, element) {
+ if(check_attr(nested, attr, expected)) {
+ return true;
+ }
+ }
+ return false;
+ } else {
+ return check_attr(lookup_element(element, element1), attr, expected);
+ }
+}
+
+boost::regression::node_ptr boost::regression::lookup_element(node_ptr element, const std::string& name) {
+ if(element == 0) {
+ return 0;
+ } else {
+ return element->first_node(name.data(), name.size());
+ }
+}
+
+int boost::regression::count_element(node_ptr element, const std::string& name) {
+ int result = 0;
+ element = element->first_node(name.data(), name.size());
+ while(element != 0) {
+ ++result;
+ element = element->next_sibling(name.data(), name.size());
+ }
+ return result;
+}
+
+std::string boost::regression::value_of(node_ptr element) {
+ if(element && element->value() != 0) {
+ return std::string(element->value(), element->value_size());
+ } else {
+ return std::string();
+ }
+}
+
+void boost::regression::load_failures_markup(node_ptr root, failures_markup_t& failures_markup) {
+ if(check_name(root, "library")) {
+ std::string library;
+ lookup_attr(root, "name", library);
+ failures_markup.libraries.insert(std::make_pair(library, root));
+ } else if(check_name(root, "mark-toolset")) {
+ if(check_attr(root, "status", "required")) {
+ std::string name;
+ if(lookup_attr(root, "name", name)) {
+ failures_markup.required_toolsets.insert(name);
+ }
+ }
+ } else if(check_name(root, "note")) {
+ std::string refid;
+ if(lookup_attr(root, "id", refid)) {
+ failures_markup.notes.insert(std::make_pair(refid, root));
+ }
+ } else {
+ FOR_EACH_ELEMENT(elem, root) {
+ load_failures_markup(elem, failures_markup);
+ }
+ }
+}
+
+namespace {
+
+void load_test_log(node_ptr root, test_structure_t::test_log_t& test_log) {
+ lookup_attr(root, "library", test_log.library);
+ lookup_attr(root, "test-program", test_log.test_program);
+ test_log.show_run_output = check_attr(root, "show-run-output", "true");
+ lookup_attr(root, "toolset", test_log.toolset);
+ lookup_attr(root, "test-type", test_log.test_type);
+ lookup_attr(root, "test-name", test_log.test_name);
+ lookup_attr(root, "target-directory", test_log.target_directory);
+ // these are set by add_expected_results
+ test_log.result = false; // check_attr(root, "result", "success");
+ test_log.expected_result = false; // check_attr(root, "expected-result", "success");
+ // lookup_attr(root, "expected-reason", test_log.expected_reason);
+ test_log.status = check_attr(root, "status", "expected");
+ test_log.is_new = check_attr(root, "is-new", "yes");
+ lookup_attr(root, "category", test_log.category);
+
+ // process compile/run/etc.
+ FOR_EACH_ELEMENT(elem, root) {
+ std::string name(elem->name(), elem->name_size());
+ if(name != "") {
+ test_structure_t::target_t& target = test_log.targets[name];
+ target.type = name;
+ lookup_attr(elem, "timestamp", target.timestamp);
+ target.result = !check_attr(elem, "result", "fail");
+ target.contents = elem;
+ }
+ }
+}
+
+void collect_toolsets(node_ptr root, test_structure_t::toolset_group_t& out, test_structure_t::toolset_group_t& non_test_case_targets) {
+ if(check_name(root, "test-log")) {
+ std::string toolset;
+ if(lookup_attr(root, "toolset", toolset)) {
+ std::string library, test_name;
+ lookup_attr(root, "library", library);
+ lookup_attr(root, "test-name", test_name);
+
+ test_structure_t::test_log_t log;
+ load_test_log(root, log);
+ if(is_test_log_a_test_case(log))
+ out[toolset][library][test_name].push_back(log);
+ else
+ non_test_case_targets[toolset][library][test_name].push_back(log);
+ }
+ } else {
+ FOR_EACH_ELEMENT(elem, root) {
+ collect_toolsets(elem, out, non_test_case_targets);
+ }
+ }
+}
+
+// FIXME: Make sure that Boost.DateTime handles parsing errors correctly
+boost::posix_time::ptime parse_time(std::string arg) {
+ // fix up some formatting problems
+ if(!arg.empty() && arg[arg.size() - 1] == 'Z') arg.resize(arg.size() - 1);
+ std::replace(arg.begin(), arg.end(), 'T', ' ');
+ return boost::posix_time::time_from_string(arg);
+}
+
+void validate_run(const test_structure_t::run_t& run) {
+ if(run.run_type != "incremental" && run.run_type != "full") {
+ BOOST_THROW_EXCEPTION(xml_error("Expected run-type to be \"incremental\" or \"full\""));
+ }
+ BOOST_FOREACH(char ch, run.revision) {
+ if(!('0' <= ch && ch <= '9')) {
+ BOOST_THROW_EXCEPTION(xml_error("Expected revision to be a numeric constant"));
+ }
+ }
+}
+
+}
+
+void boost::regression::load_test_structure(node_ptr root, test_structure_t& structure, std::vector<test_structure_t::run_t*>& runs) {
+ if(check_name(root, "test-run")) {
+ test_structure_t::run_t run;
+ std::string timestamp;
+ require_attr(root, "runner", run.runner);
+ require_attr(root, "platform", run.platform);
+ require_attr(root, "run-type", run.run_type);
+ require_attr(root, "source", run.source);
+ require_attr(root, "revision", run.revision);
+ require_attr(root, "timestamp", timestamp);
+ // "2010-05-11T18:29:17Z"
+ run.timestamp = parse_time(timestamp);
+ run.comment = value_of(lookup_element(root, "comment"));
+ validate_run(run);
+ collect_toolsets(root, run.toolsets, run.non_test_case_targets);
+ structure.platforms[run.platform].push_back(run);
+ runs.push_back(&structure.platforms[run.platform].back());
+ } else {
+ FOR_EACH_ELEMENT(elem, root) {
+ load_test_structure(elem, structure, runs);
+ }
+ }
+}
+
+namespace {
+
+struct escaped {
+ const char* input;
+ std::size_t size;
+ bool trim;
+};
+
+// okay
+void write_characters(html_writer& document, const char* input, std::size_t size) {
+ for(std::size_t i = 0; i < size; ++i) {
+ if(input[i] == '<') {
+ document << "&lt;";
+ } else if(input[i] == '>') {
+ document << "&gt;";
+ } else if(input[i] == '&') {
+ document << "&amp;";
+ } else {
+ document << input[i];
+ }
+ }
+}
+
+// FIXME: do not break in the middle of a code point
+html_writer& operator<<(html_writer& document, const escaped& text) {
+ std::size_t max_size = 1 << 16;
+ if(text.trim && (text.size > max_size)) {
+ write_characters(document, text.input, max_size);
+ document << str(boost::format("...\n\n[The content has been trimmed by the report system because it exceeds %d bytes]") % max_size);
+ } else {
+ write_characters(document, text.input, text.size);
+ }
+ return document;
+}
+
+escaped make_escaped(const char* input, std::size_t size, bool trim) {
+ escaped result = { input, size, trim };
+ return result;
+}
+
+std::string escape_characters(const char* input, std::size_t size) {
+ std::string result;
+ for(std::size_t i = 0; i < size; ++i) {
+ if(input[i] == '<') {
+ result += "&lt;";
+ } else if(input[i] == '>') {
+ result += "&gt;";
+ } else if(input[i] == '&') {
+ result += "&amp;";
+ } else if(input[i] == '\'') {
+ result += "&apos;";
+ } else if(input[i] == '"') {
+ result += "&quot;";
+ } else {
+ result += input[i];
+ }
+ }
+ return result;
+}
+}
+
+std::string boost::regression::escape_xml(const std::string& s) {
+ return escape_characters(s.data(), s.size());
+}
+
+void boost::regression::write_to_stream(html_writer& os, node_ptr node, bool trim) {
+ using namespace boost::property_tree::detail::rapidxml;
+ switch(node->type()) {
+ case node_document:
+ FOR_EACH_ELEMENT(elem, node) {
+ write_to_stream(os, elem);
+ }
+ break;
+ case node_element:
+ os << '<' << escape_characters(node->name(), node->name_size());
+ for(attr_ptr attr = node->first_attribute(); attr != 0; attr = attr->next_attribute()) {
+ os << ' ' << std::string(attr->name(), attr->name_size()) << '=' << '"' << escape_characters(attr->value(), attr->value_size()) << '"';
+ }
+ os << '>';
+ FOR_EACH_ELEMENT(elem, node) {
+ write_to_stream(os, elem);
+ }
+ os << '<' << '/' << escape_characters(node->name(), node->name_size()) << '>';
+ break;
+ case node_data:
+ os << make_escaped(node->value(), node->value_size(), trim);
+ break;
+ default:
+ throw xml_error("Don't know how to handle element type");
+ }
+}
+
+void boost::regression::write_contents(html_writer& os, node_ptr node, bool trim) {
+ FOR_EACH_ELEMENT(elem, node) {
+ write_to_stream(os, elem, trim);
+ }
+}
+
+namespace {
+struct node_storage : document_type {
+ std::vector<char> storage;
+};
+}
+
+boost::shared_ptr<document_type> boost::regression::read_xml_file(const char* filename) {
+ std::ifstream input(filename);
+ if(!input) {
+ throw(std::ios_base::failure(std::string("Could not open file: ") + filename));
+ }
+ boost::shared_ptr<node_storage> result(new node_storage());
+ std::streambuf* buf = input.rdbuf();
+ std::streambuf::int_type ch;
+ while((ch = buf->sbumpc()) != std::char_traits<char>::eof()) {
+ result->storage.push_back(ch);
+ }
+ result->storage.push_back('\0');
+ result->parse<boost::property_tree::detail::rapidxml::parse_default>(&result->storage[0]);
+ return result;
+}
+
+namespace {
+
+void load_expected_results(node_ptr root, test_case_t id, expected_results_t& expected_results) {
+ if(check_name(root, "test-result")) {
+ lookup_attr(root, "test-name", id.test_name);
+ bool result = !check_attr(root, "result", "fail");
+ expected_results.tests.insert(std::make_pair(id, result));
+ } else {
+ if(check_name(root, "toolset")) {
+ std::string name;
+ lookup_attr(root, "name", name);
+ id.toolset_name = name;
+ FOR_EACH_ELEMENT(elem, root) {
+ if(check_name(elem, "toolset-alias")) {
+ std::string alias_name;
+ if(lookup_attr(elem, "name", alias_name)) {
+ expected_results.toolset_aliases.insert(std::make_pair(alias_name, name));
+ }
+ }
+ }
+ } else if(check_name(root, "library")) {
+ lookup_attr(root, "name", id.library);
+ }
+ FOR_EACH_ELEMENT(elem, root) {
+ load_expected_results(elem, id, expected_results);
+ }
+ }
+}
+
+}
+
+void boost::regression::load_expected_results(node_ptr root, expected_results_t& expected_results) {
+ test_case_t id;
+ ::load_expected_results(root, id, expected_results);
+}

Added: trunk/tools/regression/src/report/xml.hpp
==============================================================================
--- (empty file)
+++ trunk/tools/regression/src/report/xml.hpp 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
@@ -0,0 +1,133 @@
+// xml.hpp
+//
+// Copyright (c) 2010 Steven Watanabe
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanyiong file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef XML_HPP_INCLUDED
+#define XML_HPP_INCLUDED
+
+#include <string>
+#include <vector>
+#include <iosfwd>
+#include <boost/unordered_map.hpp>
+#include <boost/unordered_set.hpp>
+#include <boost/property_tree/detail/rapidxml.hpp>
+#include <boost/date_time/posix_time/ptime.hpp>
+#include <boost/variant.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include "html_writer.hpp"
+
+namespace boost {
+namespace regression {
+
+class xml_error : public std::exception {
+public:
+ explicit xml_error(const std::string& m) : message(m) {}
+ virtual ~xml_error() throw() {}
+ virtual const char * what() const throw() { return message.c_str(); }
+private:
+ std::string message;
+};
+
+typedef boost::property_tree::detail::rapidxml::xml_node<> node_type;
+typedef boost::property_tree::detail::rapidxml::xml_attribute<> attr_type;
+typedef boost::property_tree::detail::rapidxml::xml_document<> document_type;
+typedef node_type* node_ptr;
+typedef attr_type* attr_ptr;
+typedef document_type* document_ptr;
+
+struct test_case_t {
+ std::string toolset_name;
+ std::string library;
+ std::string test_name;
+};
+
+std::size_t hash_value(const test_case_t& test_case);
+bool operator==(const test_case_t& lhs, const test_case_t& rhs);
+
+struct expected_results_t {
+ typedef boost::unordered_map<test_case_t, bool> tests_t;
+ typedef boost::unordered_map<std::string, std::string> toolset_aliases_t;
+ tests_t tests;
+ toolset_aliases_t toolset_aliases;
+};
+void load_expected_results(node_ptr root, expected_results_t& expected_results);
+
+struct test_structure_t {
+ struct target_t {
+ std::string type;
+ std::string timestamp;
+ bool result;
+ node_ptr contents;
+ };
+ typedef boost::variant<std::string, node_ptr> note_t;
+ struct test_log_t {
+ std::string library;
+ std::string test_program;
+ bool show_run_output;
+ std::string toolset;
+ std::string test_type;
+ std::string test_name;
+ std::string target_directory;
+ bool result;
+ bool expected_result;
+ std::string expected_reason;
+ bool status;
+ bool is_new;
+ std::string category;
+ boost::unordered_map<std::string, target_t> targets;
+ std::vector<note_t> notes;
+ };
+ typedef std::vector<test_log_t> test_case_t;
+ typedef boost::unordered_map<std::string, test_case_t> library_t;
+ typedef boost::unordered_map<std::string, library_t> toolset_t;
+ typedef std::map<std::string, toolset_t> toolset_group_t;
+ struct run_t {
+ std::string runner;
+ std::string platform;
+ std::string run_type;
+ std::string source;
+ std::string revision;
+ std::string comment;
+ boost::posix_time::ptime timestamp;
+ toolset_group_t toolsets;
+ toolset_group_t non_test_case_targets;
+ };
+ typedef std::vector<run_t> platform_t;
+ typedef std::map<std::string, platform_t> platform_group_t;
+ platform_group_t platforms;
+};
+void load_test_structure(node_ptr root, test_structure_t& structure, std::vector<test_structure_t::run_t*>& runs);
+
+struct failures_markup_t {
+ boost::unordered_map<std::string, node_ptr> libraries;
+ boost::unordered_set<std::string> required_toolsets;
+ boost::unordered_map<std::string, node_ptr> notes;
+};
+void load_failures_markup(node_ptr root, failures_markup_t& failures_markup);
+
+#define FOR_EACH_ELEMENT(name, node)\
+ for(::boost::regression::node_ptr name = (node)->first_node(); name != 0; name = name->next_sibling())
+
+attr_ptr lookup_attr(node_ptr element, const std::string& name);
+bool lookup_attr(node_ptr element, const std::string& name, std::string& result);
+bool check_attr(node_ptr element, const std::string& name, const std::string& expected);
+bool check_name(node_ptr element, const std::string& name);
+bool check_attr(node_ptr element, const std::string& element1, const std::string& attr, const std::string& expected);
+node_ptr lookup_element(node_ptr element, const std::string& name);
+int count_element(node_ptr element, const std::string& name);
+std::string value_of(node_ptr element);
+
+std::string escape_xml(const std::string& s);
+void write_to_stream(html_writer& os, node_ptr node, bool trim=false);
+void write_contents(html_writer& document, node_ptr node, bool trim=false);
+boost::shared_ptr<document_type> read_xml_file(const char* filename);
+
+}
+}
+
+#endif

Added: trunk/tools/regression/src/report/zip.hpp
==============================================================================
--- (empty file)
+++ trunk/tools/regression/src/report/zip.hpp 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
@@ -0,0 +1,733 @@
+// zip.hpp
+//
+// Copyright (c) 2010, 2013
+// Steven Watanabe
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_ZIP_ZIP_HPP_INCLUDED
+#define BOOST_ZIP_ZIP_HPP_INCLUDED
+
+#include <cstring>
+#include <ostream>
+#include <string>
+#include <cstddef>
+#include <vector>
+#include <bitset>
+#include <ios>
+
+#include <boost/array.hpp>
+#include <boost/date_time/posix_time/ptime.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/crc.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/iostreams/categories.hpp>
+#include <boost/iostreams/operations.hpp>
+#include <boost/iostreams/filter/zlib.hpp>
+#include <boost/mpl/integral_c.hpp>
+
+namespace boost {
+namespace zip {
+
+// TODO: Handle endian conversions
+#define BOOST_ZIP_DEFINE_HEADER(name, type, offset) \
+ static const int name##_offset = (offset); \
+ static type get_##name(const char* header) { \
+ type result; \
+ ::std::memcpy(&result, header + (offset), sizeof(type)); \
+ return result; \
+ } \
+ static void set_##name(char* header, type x) { \
+ ::std::memcpy(header + (offset), &x, sizeof(type)); \
+ }
+
+class zip_archive {
+public:
+ zip_archive(std::ostream& file) : output_file(file), current_offset(0), num_files(0) {}
+ ~zip_archive() {
+ close();
+ }
+
+ class file_handle;
+ friend class file_handle;
+ class file_handle {
+ public:
+ typedef char char_type;
+
+ struct category :
+ ::boost::iostreams::sink_tag,
+ ::boost::iostreams::closable_tag
+ {};
+
+ file_handle(zip_archive& archive,
+ const std::string& path,
+ boost::uint16_t creator_version,
+ boost::uint16_t minimum_required_version,
+ boost::uint16_t flags,
+ boost::uint16_t compression_method,
+ const boost::posix_time::ptime& modification_time)
+ {
+ self = 0;
+ archive.open_file(path, creator_version, minimum_required_version, flags, compression_method, modification_time, this);
+ }
+ ::std::streamsize write(const char* data, ::std::streamsize size) {
+ assert(self != 0);
+ self->output_file.write(data, size);
+ compressed_size += size;
+ self->current_offset += size;
+ return size;
+ }
+ void write_uncompressed(const char* data, ::std::streamsize size) {
+ assert(self != 0);
+ crc.process_bytes(data, static_cast<std::size_t>(size));
+ uncompressed_size += size;
+ }
+ void close() {
+ central_directory_entry::set_crc32(&self->central_directory[offset], crc.checksum());
+ // These lines cause a warning. Since the warning is legitimate,
+ // I'm leaving it.
+ central_directory_entry::set_compressed_size(&self->central_directory[offset], compressed_size);
+ central_directory_entry::set_uncompressed_size(&self->central_directory[offset], uncompressed_size);
+
+ boost::array<char, 12> buffer;
+ data_descriptor::set_crc32(&buffer[0], crc.checksum());
+ data_descriptor::set_compressed_size(&buffer[0], compressed_size);
+ data_descriptor::set_uncompressed_size(&buffer[0], uncompressed_size);
+ std::streamsize current_pos = self->output_file.tellp();
+ self->output_file.seekp(pos);
+ self->output_file.write(&buffer[0], 12);
+ self->output_file.seekp(current_pos);
+ self = 0;
+ }
+ private:
+ friend class zip_archive;
+ file_handle(const file_handle&);
+ file_handle& operator=(const file_handle&);
+
+ boost::crc_32_type crc;
+ std::streamsize pos;
+ std::size_t offset;
+ std::streamsize compressed_size;
+ std::streamsize uncompressed_size;
+ zip_archive* self;
+ };
+
+ void open_file(const std::string& path,
+ boost::uint16_t creator_version,
+ boost::uint16_t minimum_required_version,
+ boost::uint16_t flags,
+ boost::uint16_t compression_method,
+ const boost::posix_time::ptime& modification_time,
+ file_handle* out
+ )
+ {
+ boost::uint16_t date =
+ modification_time.date().day() +
+ (modification_time.date().month() << 5) +
+ ((modification_time.date().year() - 1980) << 9);
+ boost::uint16_t time =
+ (modification_time.time_of_day().seconds() / 2) +
+ (modification_time.time_of_day().minutes() << 5) +
+ (modification_time.time_of_day().hours() << 11);
+ open_file(path.data(), path.size(), creator_version, minimum_required_version, flags, compression_method, time, date, out);
+ }
+
+ void open_file(const char* path, std::size_t path_size,
+ boost::uint16_t creator_version,
+ boost::uint16_t minimum_required_version,
+ boost::uint16_t flags,
+ boost::uint16_t compression_method,
+ boost::uint16_t modification_time,
+ boost::uint16_t modification_date,
+ file_handle* handle
+ )
+ {
+ // The file_handle should not be open
+ assert(handle->self == 0);
+
+ handle->pos = static_cast<std::streamsize>(output_file.tellp()) + local_file_header::crc32_offset;
+
+ std::vector<char> header(30);
+ local_file_header::set_signature(&header[0], local_file_header::signature);
+ local_file_header::set_minimum_required_version(&header[0], minimum_required_version);
+ local_file_header::set_flags(&header[0], flags);
+ local_file_header::set_compression_method(&header[0], compression_method);
+
+ local_file_header::set_filename_size(&header[0], path_size);
+ // TODO: handle Zip64
+ header.insert(header.end(), path, path + path_size);
+
+ output_file.write(&header[0], header.size());
+
+ std::size_t offset = central_directory.size();
+ central_directory.resize(offset + 46);
+ central_directory_entry::set_signature(&central_directory[offset], central_directory_entry::signature);
+ central_directory_entry::set_creator_version(&central_directory[offset], creator_version);
+ central_directory_entry::set_minimum_required_version(&central_directory[offset], minimum_required_version);
+ central_directory_entry::set_flags(&central_directory[offset], flags);
+ central_directory_entry::set_compression_method(&central_directory[offset], compression_method);
+ central_directory_entry::set_modification_time(&central_directory[offset], modification_time);
+ central_directory_entry::set_modification_date(&central_directory[offset], modification_date);
+ central_directory_entry::set_filename_size(&central_directory[offset], path_size);
+ central_directory_entry::set_extra_size(&central_directory[offset], 0);
+ central_directory_entry::set_comment_size(&central_directory[offset], 0);
+ central_directory_entry::set_file_start_disk(&central_directory[offset], 0);
+ central_directory_entry::set_internal_attributes(&central_directory[offset], 0);
+ central_directory_entry::set_external_attributes(&central_directory[offset], 0);
+ central_directory_entry::set_local_header_offset(&central_directory[offset], current_offset);
+ central_directory.insert(central_directory.end(), path, path + path_size);
+
+ handle->crc.reset();
+ handle->offset = offset;
+ handle->compressed_size = 0;
+ handle->uncompressed_size = 0;
+ handle->self = this;
+
+ current_offset += header.size();
+ ++num_files;
+ }
+
+ void write_file(const std::string& path, const char* contents, std::size_t size) {
+ std::vector<char> header(30);
+ local_file_header::set_signature(&header[0], local_file_header::signature);
+ local_file_header::set_minimum_required_version(&header[0], 10);
+ local_file_header::set_flags(&header[0], 0);
+ local_file_header::set_compression_method(&header[0], compression_method::none);
+
+ crc_32_type crc;
+ crc.process_bytes(contents, size);
+ local_file_header::set_crc32(&header[0], crc.checksum());
+ local_file_header::set_compressed_size(&header[0], size);
+ local_file_header::set_uncompressed_size(&header[0], size);
+ local_file_header::set_filename_size(&header[0], path.size());
+ // TODO: handle Zip64
+ header.insert(header.end(), path.begin(), path.end());
+
+ output_file.write(&header[0], header.size());
+ output_file.write(contents, size);
+
+ std::size_t offset = central_directory.size();
+ central_directory.resize(offset + 46);
+ central_directory_entry::set_signature(&central_directory[offset], central_directory_entry::signature);
+ central_directory_entry::set_creator_version(&central_directory[offset], 10);
+ central_directory_entry::set_minimum_required_version(&central_directory[offset], 10);
+ central_directory_entry::set_flags(&central_directory[offset], 0);
+ central_directory_entry::set_compression_method(&central_directory[offset], compression_method::none);
+ // FIXME: find correct date and time
+ central_directory_entry::set_modification_time(&central_directory[offset], 0);
+ central_directory_entry::set_modification_date(&central_directory[offset], 0);
+ central_directory_entry::set_crc32(&central_directory[offset], crc.checksum());
+ central_directory_entry::set_compressed_size(&central_directory[offset], size);
+ central_directory_entry::set_uncompressed_size(&central_directory[offset], size);
+ central_directory_entry::set_filename_size(&central_directory[offset], path.size());
+ central_directory_entry::set_extra_size(&central_directory[offset], 0);
+ central_directory_entry::set_comment_size(&central_directory[offset], 0);
+ central_directory_entry::set_file_start_disk(&central_directory[offset], 0);
+ central_directory_entry::set_internal_attributes(&central_directory[offset], 0);
+ central_directory_entry::set_external_attributes(&central_directory[offset], 0);
+ central_directory_entry::set_local_header_offset(&central_directory[offset], current_offset);
+ central_directory.insert(central_directory.end(), path.begin(), path.end());
+ current_offset = current_offset + header.size() + size;
+
+ ++num_files;
+ }
+ void close() {
+ output_file.write(&central_directory[0], central_directory.size());
+
+ if(num_files >= 65536) {
+ boost::array<char, zip64_end_of_central_directory::size> data;
+ zip64_end_of_central_directory::set_signature(&data[0], zip64_end_of_central_directory::signature);
+ zip64_end_of_central_directory::set_size(&data[0], zip64_end_of_central_directory::size - 12);
+ zip64_end_of_central_directory::set_creator_version(&data[0], 45);
+ zip64_end_of_central_directory::set_minimum_required_version(&data[0], 45);
+ zip64_end_of_central_directory::set_disk_number(&data[0], 0);
+ zip64_end_of_central_directory::set_directory_start_disk(&data[0], 0);
+ zip64_end_of_central_directory::set_entries_on_disk(&data[0], num_files);
+ zip64_end_of_central_directory::set_total_entries(&data[0], num_files);
+ zip64_end_of_central_directory::set_directory_size(&data[0], central_directory.size());
+ zip64_end_of_central_directory::set_directory_offset(&data[0], current_offset);
+ output_file.write(&data[0], data.size());
+
+ boost::array<char, zip64_end_of_central_directory_locator::size> locator;
+ zip64_end_of_central_directory_locator::set_signature(&locator[0], zip64_end_of_central_directory_locator::signature);
+ zip64_end_of_central_directory_locator::set_end_of_directory_disk(&locator[0], 0);
+ zip64_end_of_central_directory_locator::set_end_of_directory_offset(&locator[0], current_offset + central_directory.size());
+ zip64_end_of_central_directory_locator::set_total_disks(&locator[0], 1);
+ output_file.write(&locator[0], locator.size());
+
+ std::vector<char> end(22);
+ end_of_central_directory::set_signature(&end[0], end_of_central_directory::signature);
+ end_of_central_directory::set_disk_number(&end[0], 0);
+ end_of_central_directory::set_directory_start_disk(&end[0], 0);
+ end_of_central_directory::set_entries_on_disk(&end[0], 0xFFFFu);
+ end_of_central_directory::set_total_entries(&end[0], 0xFFFFu);
+ end_of_central_directory::set_directory_size(&end[0], central_directory.size());
+ end_of_central_directory::set_directory_offset(&end[0], current_offset);
+ end_of_central_directory::set_comment_length(&end[0], 0);
+ output_file.write(&end[0], end.size());
+ } else {
+ std::vector<char> end(22);
+ end_of_central_directory::set_signature(&end[0], end_of_central_directory::signature);
+ end_of_central_directory::set_disk_number(&end[0], 0);
+ end_of_central_directory::set_directory_start_disk(&end[0], 0);
+ end_of_central_directory::set_entries_on_disk(&end[0], num_files);
+ end_of_central_directory::set_total_entries(&end[0], num_files);
+ end_of_central_directory::set_directory_size(&end[0], central_directory.size());
+ end_of_central_directory::set_directory_offset(&end[0], current_offset);
+ end_of_central_directory::set_comment_length(&end[0], 0);
+ output_file.write(&end[0], end.size());
+ }
+ }
+private:
+
+ std::ostream& output_file;
+ std::vector<char> central_directory;
+ std::streamsize current_offset;
+ std::size_t num_files;
+
+ // little endian
+ struct local_file_header {
+ static const boost::uint32_t signature = 0x04034b50u;
+
+ BOOST_ZIP_DEFINE_HEADER(signature, boost::uint32_t, 0);
+ BOOST_ZIP_DEFINE_HEADER(minimum_required_version, boost::uint16_t, 4);
+ BOOST_ZIP_DEFINE_HEADER(flags, boost::uint16_t, 6);
+ BOOST_ZIP_DEFINE_HEADER(compression_method, boost::uint16_t, 8);
+ BOOST_ZIP_DEFINE_HEADER(modification_time, boost::uint16_t, 10);
+ BOOST_ZIP_DEFINE_HEADER(modification_date, boost::uint16_t, 12);
+ BOOST_ZIP_DEFINE_HEADER(crc32, boost::uint32_t, 14);
+ BOOST_ZIP_DEFINE_HEADER(compressed_size, boost::uint32_t, 18);
+ BOOST_ZIP_DEFINE_HEADER(uncompressed_size, boost::uint32_t, 22);
+ BOOST_ZIP_DEFINE_HEADER(filename_size, boost::uint16_t, 26);
+ BOOST_ZIP_DEFINE_HEADER(extra_size, boost::uint16_t, 28);
+
+ static char* filename(void* header) {
+ return static_cast<char*>(header) + 30;
+ }
+ const char* filename(const void* header) {
+ return static_cast<const char*>(header) + 30;
+ }
+ };
+
+ struct data_descriptor {
+ // The signature may or may not be present
+ static const boost::uint32_t signature = 0x08074b50u;
+ BOOST_ZIP_DEFINE_HEADER(crc32, boost::uint32_t, 0);
+ BOOST_ZIP_DEFINE_HEADER(compressed_size, boost::uint32_t, 4);
+ BOOST_ZIP_DEFINE_HEADER(uncompressed_size, boost::uint32_t, 8);
+ // FIXME: handle skipping the signature automatically
+ };
+
+ // Not implemented Archive decryption header
+ // Not implemented Archive extra data record
+
+ struct central_directory_entry {
+ static const boost::uint32_t signature = 0x02014b50u;
+ BOOST_ZIP_DEFINE_HEADER(signature, boost::uint32_t, 0);
+ BOOST_ZIP_DEFINE_HEADER(creator_version, boost::uint16_t, 4);
+ BOOST_ZIP_DEFINE_HEADER(minimum_required_version, boost::uint16_t, 6);
+ BOOST_ZIP_DEFINE_HEADER(flags, boost::uint16_t, 8);
+ BOOST_ZIP_DEFINE_HEADER(compression_method, boost::uint16_t, 10);
+ BOOST_ZIP_DEFINE_HEADER(modification_time, boost::uint16_t, 12);
+ BOOST_ZIP_DEFINE_HEADER(modification_date, boost::uint16_t, 14);
+ BOOST_ZIP_DEFINE_HEADER(crc32, boost::uint32_t, 16);
+ BOOST_ZIP_DEFINE_HEADER(compressed_size, boost::uint32_t, 20);
+ BOOST_ZIP_DEFINE_HEADER(uncompressed_size, boost::uint32_t, 24);
+ BOOST_ZIP_DEFINE_HEADER(filename_size, boost::uint16_t, 28);
+ BOOST_ZIP_DEFINE_HEADER(extra_size, boost::uint16_t, 30);
+ BOOST_ZIP_DEFINE_HEADER(comment_size, boost::uint16_t, 32);
+ BOOST_ZIP_DEFINE_HEADER(file_start_disk, boost::uint16_t, 34);
+ BOOST_ZIP_DEFINE_HEADER(internal_attributes, boost::uint16_t, 36);
+ BOOST_ZIP_DEFINE_HEADER(external_attributes, boost::uint32_t, 38);
+ BOOST_ZIP_DEFINE_HEADER(local_header_offset, boost::uint32_t, 42);
+
+ // TODO: filename, extra, comment
+ };
+
+ struct digital_signature {
+ static const boost::uint32_t signature = 0x05054b50;
+
+ BOOST_ZIP_DEFINE_HEADER(data_size, boost::uint16_t, 4);
+ // TODO: data
+ };
+
+ struct zip64_end_of_central_directory {
+ static const boost::uint32_t signature = 0x06064b50u;
+ // The value stored into the "size of zip64 end of central
+ // directory record" should be the size of the remaining
+ // record and should not include the leading 12 bytes.
+ BOOST_ZIP_DEFINE_HEADER(signature, boost::uint32_t, 0);
+ BOOST_ZIP_DEFINE_HEADER(size, boost::uint64_t, 4);
+ BOOST_ZIP_DEFINE_HEADER(creator_version, boost::uint16_t, 12);
+ BOOST_ZIP_DEFINE_HEADER(minimum_required_version, boost::uint16_t, 14);
+ BOOST_ZIP_DEFINE_HEADER(disk_number, boost::uint32_t, 16);
+ BOOST_ZIP_DEFINE_HEADER(directory_start_disk, boost::uint32_t, 20);
+ BOOST_ZIP_DEFINE_HEADER(entries_on_disk, boost::uint64_t, 24);
+ BOOST_ZIP_DEFINE_HEADER(total_entries, boost::uint64_t, 32);
+ BOOST_ZIP_DEFINE_HEADER(directory_size, boost::uint64_t, 40);
+ BOOST_ZIP_DEFINE_HEADER(directory_offset, boost::uint64_t, 48);
+
+ static const size_t size = 56;
+ // TODO: data
+ // Header ID - 2 bytes
+ // Data Size - 4 bytes
+ };
+
+ // H
+ struct zip64_end_of_central_directory_locator {
+ static const boost::uint32_t signature = 0x07064b50;
+ BOOST_ZIP_DEFINE_HEADER(signature, boost::uint32_t, 0);
+ BOOST_ZIP_DEFINE_HEADER(end_of_directory_disk, boost::uint32_t, 4);
+ BOOST_ZIP_DEFINE_HEADER(end_of_directory_offset, boost::uint64_t, 8);
+ BOOST_ZIP_DEFINE_HEADER(total_disks, boost::uint32_t, 16);
+
+ static const size_t size = 20;
+ };
+
+ struct end_of_central_directory {
+ static const uint32_t signature = 0x06054b50u;
+ BOOST_ZIP_DEFINE_HEADER(signature, boost::uint32_t, 0);
+ BOOST_ZIP_DEFINE_HEADER(disk_number, boost::uint16_t, 4);
+ BOOST_ZIP_DEFINE_HEADER(directory_start_disk, boost::uint16_t, 6);
+ BOOST_ZIP_DEFINE_HEADER(entries_on_disk, boost::uint16_t, 8);
+ BOOST_ZIP_DEFINE_HEADER(total_entries, boost::uint16_t, 10);
+ BOOST_ZIP_DEFINE_HEADER(directory_size, boost::uint32_t, 12);
+ BOOST_ZIP_DEFINE_HEADER(directory_offset, boost::uint32_t, 16);
+ BOOST_ZIP_DEFINE_HEADER(comment_length, boost::uint16_t, 20);
+ };
+
+public:
+
+ struct version {
+ static const boost::uint16_t system_mask = 0xFF00u;
+ static const boost::uint16_t ms_dos = 0u << 8;
+ static const boost::uint16_t amiga = 1u << 8;
+ static const boost::uint16_t open_vms = 2u << 8;
+ static const boost::uint16_t unix_ = 3u << 8;
+ static const boost::uint16_t vm_cms = 4u << 8;
+ static const boost::uint16_t atari_st = 5u << 8;
+ static const boost::uint16_t os_2_hpfs = 6u << 8;
+ static const boost::uint16_t macintosh = 7u << 8;
+ static const boost::uint16_t z_system = 8u << 8;
+ static const boost::uint16_t cp_m = 9u << 8;
+ static const boost::uint16_t windows_ntfs = 10u << 8;
+ static const boost::uint16_t mvs = 11u << 8;
+ static const boost::uint16_t vse = 12u << 8;
+ static const boost::uint16_t acorn_risc = 13u << 8;
+ static const boost::uint16_t vfat = 14u << 8;
+ static const boost::uint16_t alternate_mvs = 15u << 8;
+ static const boost::uint16_t beos = 16u << 8;
+ static const boost::uint16_t tandem = 17u << 8;
+ static const boost::uint16_t os_400 = 18u << 8;
+ static const boost::uint16_t darwin = 19u << 8;
+
+ // e.g. 62 = ZIP 6.2
+ static const boost::uint16_t zip_version_mask = 0xFFu;
+ static const boost::uint16_t default_ = 10;
+ static const boost::uint16_t file_is_volume_label = 11;
+ static const boost::uint16_t file_is_folder = 20;
+ static const boost::uint16_t file_is_compressed_with_deflate = 20;
+ static const boost::uint16_t zip64 = 45;
+ // TODO: ...
+ };
+
+ struct flags {
+ static const boost::uint16_t encrypted = 0x1u;
+
+ static const boost::uint16_t imploding_8k_dictionary = 0x2u;
+ static const boost::uint16_t imploding_3_shannon_faro = 0x4u;
+ static const boost::uint16_t deflating_options_mask = 0x6u;
+ static const boost::uint16_t deflating_normal = 0x0u;
+ static const boost::uint16_t deflating_maximum = 0x2u;
+ static const boost::uint16_t deflating_fast = 0x4u;
+ static const boost::uint16_t deflating_super_fast = 0x6u;
+ static const boost::uint16_t lzma_eos = 0x2u;
+
+ static const boost::uint16_t has_data_descriptor = 0x8u;
+ static const boost::uint16_t enhanced_deflating = 0x10;
+ static const boost::uint16_t strong_encryption = 0x20;
+ static const boost::uint16_t utf8 = 0x800;
+ static const boost::uint16_t mask_local_header_data = 0x2000;
+ };
+
+ struct compression_method {
+ static const boost::uint16_t none = 0;
+ static const boost::uint16_t shrink = 1;
+ static const boost::uint16_t reduce_1 = 2;
+ static const boost::uint16_t reduce_2 = 3;
+ static const boost::uint16_t reduce_3 = 4;
+ static const boost::uint16_t reduce_4 = 5;
+ static const boost::uint16_t implode = 6;
+ static const boost::uint16_t tokenizing = 7;
+ static const boost::uint16_t deflate = 8;
+ static const boost::uint16_t deflate64 = 9;
+ static const boost::uint16_t pkware_dcli = 10;
+ static const boost::uint16_t bzip2 = 12;
+ static const boost::uint16_t lzma = 14;
+ static const boost::uint16_t ibm_terse = 18;
+ static const boost::uint16_t lz77 = 19;
+ static const boost::uint16_t wavpack = 97;
+ static const boost::uint16_t ppmd_i_1 = 98;
+ };
+
+ struct internal_attributes {
+ static const boost::uint16_t ascii = 0x1;
+ };
+
+ struct header_id {
+ static const boost::uint16_t zip64 = 0x0001;
+ static const boost::uint16_t av_info = 0x0007;
+ //static const boost::uint16_t extended_language_encoding = 0x0008;
+ static const boost::uint16_t os_2 = 0x0009;
+ static const boost::uint16_t ntfs = 0x000a;
+ static const boost::uint16_t open_vms = 0x000c;
+ static const boost::uint16_t unix_ = 0x000d;
+ //static const boost::uint16_t file_stream = 0x000e;
+ static const boost::uint16_t patch_descriptor = 0x000f;
+ static const boost::uint16_t x509_certificate = 0x0014;
+ static const boost::uint16_t x509_certificate_id_file = 0x0015;
+ static const boost::uint16_t x509_certificate_id_directory = 0x0016;
+ static const boost::uint16_t strong_encryption_header = 0x0017;
+ static const boost::uint16_t record_management_controls = 0x0018;
+ static const boost::uint16_t encyption_recipients = 0x0019;
+ static const boost::uint16_t ibm_uncompressed = 0x0065;
+ static const boost::uint16_t ibm_compressed = 0x0066;
+ static const boost::uint16_t poszip4690 = 0x4690;
+
+ // TODO: Third party mappings
+ };
+
+private:
+ struct zip64_extended_information {
+ BOOST_ZIP_DEFINE_HEADER(tag, boost::uint16_t, 0);
+ BOOST_ZIP_DEFINE_HEADER(size, boost::uint16_t, 2);
+ BOOST_ZIP_DEFINE_HEADER(uncompressed_size, boost::uint64_t, 4);
+ BOOST_ZIP_DEFINE_HEADER(compressed_size, boost::uint64_t, 12);
+ BOOST_ZIP_DEFINE_HEADER(local_header_offset, boost::uint64_t, 20);
+ BOOST_ZIP_DEFINE_HEADER(disk_start_number, boost::uint32_t, 28);
+ };
+};
+
+class shrink_filter : ::boost::noncopyable {
+public:
+ typedef char char_type;
+
+ struct category :
+ ::boost::iostreams::output_filter_tag,
+ ::boost::iostreams::closable_tag
+ {};
+
+ shrink_filter()
+ {
+ memory = new lzw_node[1 << 13];
+
+ // no-throw from here on
+ code_size = 9;
+ for(int i = 0; i < (1 << code_size); ++i) {
+ initialize_node(i);
+ }
+ used_codes.set(256);
+ current_node = &root;
+ buf = 0;
+ pos = 0;
+ for(int i = 0; i < 256; ++i) {
+ root.children[i] = make_node(i);
+ }
+ next_code = 257;
+ }
+ ~shrink_filter() {
+ delete[] memory;
+ }
+ template<class Sink>
+ bool put(Sink& sink, char ch) {
+ write_char(static_cast<unsigned char>(ch));
+ return do_write(sink);
+ }
+ template<class Sink>
+ void close(Sink& sink) {
+ if(current_node != &root) {
+ write_code(get_encoding(current_node));
+ current_node = &root;
+ }
+ do_write(sink);
+ if(pos != 0) {
+ ::boost::iostreams::put(sink, buf & 0xFF);
+ pos = 0;
+ }
+ }
+private:
+ template<class Sink>
+ bool do_write(Sink& sink) {
+ while(pos >= 8) {
+ if(!::boost::iostreams::put(sink, static_cast<char>(buf & 0xFF))) {
+ return false;
+ }
+ buf >>= 8;
+ pos -= 8;
+ }
+ return true;
+ }
+ void write_char(unsigned char ch) {
+ if(current_node->children[ch] != 0) {
+ current_node = current_node->children[ch];
+ } else {
+ int encoding = get_encoding(current_node);
+ write_code(encoding);
+ for(;; ++next_code) {
+ if(next_code == (1 << code_size)) {
+ if(code_size == 13) {
+ write_code(256);
+ write_code(2);
+ free_leaves();
+ next_code = 257;
+ } else {
+ write_code(256);
+ write_code(1);
+ increment_code_size();
+ }
+ }
+ if(!used_codes.test(next_code)) {
+ current_node->children[ch] = make_node(next_code);
+ ++next_code;
+ break;
+ }
+ }
+ current_node = root.children[ch];
+ }
+ }
+ void write_code(int code) {
+ buf |= static_cast<boost::uint64_t>(code) << pos;
+ pos += code_size;
+ }
+
+ struct lzw_node {
+ lzw_node* children[256];
+ };
+ int get_encoding(lzw_node* node) const {
+ return node - memory;
+ }
+ bool free_leaves(lzw_node* node) {
+ bool result = true;
+ for(int i = 0; i < 256; ++i) {
+ if(node->children[i] != 0) {
+ result = false;
+ if(free_leaves(node->children[i])) {
+ destroy_node(node->children[i]);
+ node->children[i] = 0;
+ }
+ }
+ }
+ return result;
+ }
+ void increment_code_size() {
+ for(int i = (1 << code_size); i < (1 << (code_size + 1)); ++i) {
+ initialize_node(i);
+ }
+ ++code_size;
+ }
+ void free_leaves() {
+ for(int i = 0; i < 256; ++i) {
+ free_leaves(root.children[i]);
+ }
+ }
+ void initialize_node(int encoding) {
+ lzw_node* result = memory + encoding;
+ for(int i = 0; i < 256; ++i) {
+ result->children[i] = 0;
+ }
+ }
+ lzw_node* make_node(int encoding = 0) {
+ assert(!used_codes.test(encoding));
+ lzw_node* result = memory + encoding;
+ assert(result >= memory);
+ assert(result < memory + (1 << code_size));
+ used_codes.set(encoding);
+ return result;
+ }
+ void destroy_node(lzw_node* node) {
+ used_codes.reset(get_encoding(node));
+ }
+ lzw_node* memory;
+ lzw_node root;
+ lzw_node* current_node;
+ int code_size;
+ int next_code;
+ ::std::bitset<(1 << 13)> used_codes;
+ ::boost::uint64_t buf;
+ int pos;
+};
+
+class deflate_filter : public ::boost::iostreams::zlib_compressor {
+public:
+ deflate_filter() :
+ boost::iostreams::zlib_compressor(boost::iostreams::zlib_params(
+ boost::iostreams::zlib::default_compression,
+ boost::iostreams::zlib::deflated,
+ boost::iostreams::zlib::default_window_bits,
+ boost::iostreams::zlib::default_mem_level,
+ boost::iostreams::zlib::default_strategy,
+ true /* noheader */,
+ false /* crc */))
+ {}
+};
+
+template<class Filter>
+struct compression_method;
+
+template<>
+struct compression_method< ::boost::zip::shrink_filter> :
+ ::boost::mpl::integral_c<
+ ::boost::uint16_t,
+ ::boost::zip::zip_archive::compression_method::shrink
+ >
+{};
+
+template<>
+struct compression_method< ::boost::zip::deflate_filter> :
+ ::boost::mpl::integral_c<
+ ::boost::uint16_t,
+ ::boost::zip::zip_archive::compression_method::deflate
+ >
+{};
+
+template<class Filter>
+class zip_member_sink {
+public:
+ typedef char char_type;
+
+ struct category :
+ ::boost::iostreams::sink_tag,
+ ::boost::iostreams::closable_tag
+ {};
+
+ zip_member_sink(zip_archive& archive, const std::string& path)
+ : file(archive, path, 10, 10, 0,
+ compression_method<Filter>::value,
+ boost::posix_time::second_clock::local_time()) {}
+ ~zip_member_sink() {
+ close();
+ }
+ ::std::streamsize write(const char* data, ::std::streamsize size) {
+ file.write_uncompressed(data, size);
+ ::boost::iostreams::write(filter, file, data, size);
+ return size;
+ }
+ void close() {
+ ::boost::iostreams::close(filter, file, ::std::ios_base::out);
+ ::boost::iostreams::close(file);
+ }
+private:
+ zip_archive::file_handle file;
+ Filter filter;
+};
+
+typedef zip_member_sink<shrink_filter> shrink_sink;
+typedef zip_member_sink<deflate_filter> deflate_sink;
+
+}
+}
+
+#endif

Modified: trunk/tools/regression/xsl_reports/boost_wide_report.py
==============================================================================
--- trunk/tools/regression/xsl_reports/boost_wide_report.py (original)
+++ trunk/tools/regression/xsl_reports/boost_wide_report.py 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
@@ -470,6 +470,7 @@
         , dont_collect_logs
         , expected_results_file
         , failures_markup_file
+ , report_executable
         ):
 
     incoming_dir = os.path.join( results_dir, 'incoming', tag )
@@ -489,6 +490,29 @@
         ftp_task( ftp_site, site_path, incoming_dir )
 
     unzip_archives_task( incoming_dir, processed_dir, utils.unzip )
+
+ if report_executable:
+ if not os.path.exists( merged_dir ):
+ os.makedirs( merged_dir )
+
+ command_line = report_executable
+ command_line += " --expected " + '"%s"' % expected_results_file
+ command_line += " --markup " + '"%s"' % failures_markup_file
+ command_line += " --tag " + tag
+ # command_line += " --run-date " + '"%s"' % run_date
+ command_line += " -rl"
+ for r in reports:
+ command_line += ' -r' + r
+ command_line += " --css " + xsl_path( 'html/master.css' )
+
+ for f in glob.glob( os.path.join( processed_dir, '*.xml' ) ):
+ command_line += ' "%s"' % f
+
+ utils.log("Producing the reports...")
+ os.system(command_line)
+
+ return
+
     merge_xmls_task( incoming_dir, processed_dir, merged_dir, expected_results_file, failures_markup_file, tag )
     make_links_task( merged_dir
                      , output_dir
@@ -696,6 +720,7 @@
         , result_file_prefix
         , dont_collect_logs = 0
         , reports = report_types
+ , report_executable = None
         , warnings = []
         , user = None
         , upload = False
@@ -732,6 +757,7 @@
         , dont_collect_logs
         , expected_results_file
         , failures_markup_file
+ , report_executable
         )
 
     if upload:
@@ -759,6 +785,7 @@
         , 'results-prefix='
         , 'dont-collect-logs'
         , 'reports='
+ , 'boost-report='
         , 'user='
         , 'upload'
         , 'help'
@@ -769,6 +796,7 @@
         , '--expected-results': ''
         , '--failures-markup': ''
         , '--reports': string.join( report_types, ',' )
+ , '--boost-report': None
         , '--tag': None
         , '--user': None
         , 'upload': False
@@ -791,6 +819,7 @@
         , options[ '--results-prefix' ]
         , options.has_key( '--dont-collect-logs' )
         , options[ '--reports' ].split( ',' )
+ , options[ '--boost-report' ]
         , options[ '--user' ]
         , options.has_key( '--upload' )
         )

Modified: trunk/tools/regression/xsl_reports/build_results.sh
==============================================================================
--- trunk/tools/regression/xsl_reports/build_results.sh (original)
+++ trunk/tools/regression/xsl_reports/build_results.sh 2013-03-25 11:47:16 EDT (Mon, 25 Mar 2013)
@@ -92,6 +92,9 @@
     cd ${1}
     root=`pwd`
     boost=${cwd}/boost
+ if [ -x ${cwd}/boost_report ]; then
+ report_opt=--boost-report=${cwd}/boost_report
+ fi
     case ${1} in
         trunk)
         tag=trunk
@@ -114,14 +117,15 @@
         ;;
     esac
     report_info
- python "${boost}/tools/regression/xsl_reports/boost_wide_report.py" \
+ python "/mnt/hgfs/boost/trunk/tools/regression/xsl_reports/boost_wide_report.py" \
         --locate-root="${root}" \
         --tag=${tag} \
         --expected-results="${boost}/status/expected_results.xml" \
         --failures-markup="${boost}/status/explicit-failures-markup.xml" \
         --comment="comment.html" \
         --user="" \
- --reports=${reports}
+ --reports=${reports} \
+ ${report_opt}
     cd "${cwd}"
 }
 
@@ -130,11 +134,15 @@
     cwd=`pwd`
     upload_dir=/home/grafik/www.boost.org/testing
     
- cd ${1}/all
- rm -f ../../${1}.zip*
- #~ zip -q -r -9 ../../${1} * -x '*.xml'
- 7za a -tzip -mx=9 ../../${1}.zip * '-x!*.xml'
- cd "${cwd}"
+ if [ -f ${1}/report.zip ]; then
+ mv ${1}/report.zip ${1}.zip
+ else
+ cd ${1}/all
+ rm -f ../../${1}.zip*
+ #~ zip -q -r -9 ../../${1} * -x '*.xml'
+ 7za a -tzip -mx=9 ../../${1}.zip * '-x!*.xml'
+ cd "${cwd}"
+ fi
     mv ${1}.zip ${1}.zip.uploading
     rsync -vuz --rsh=ssh --stats \
       ${1}.zip.uploading grafik_at_[hidden]:/${upload_dir}/incoming/


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk