From 3297885d2bf018c20e8ef4c293ed01fa0bfaf55c Mon Sep 17 00:00:00 2001 From: Magnus Jacobsson Date: Thu, 28 Jul 2022 13:56:26 +0200 Subject: [PATCH] tests: SvgAnalyzer: add an svg_string method --- tests/svg_analyzer.cpp | 6 ++++ tests/svg_analyzer.h | 2 ++ tests/svg_element.cpp | 66 +++++++++++++++++++++++++++++++++++++ tests/svg_element.h | 10 ++++++ tests/test_svg_analyzer.cpp | 34 ++++++++++++++++++- 5 files changed, 117 insertions(+), 1 deletion(-) diff --git a/tests/svg_analyzer.cpp b/tests/svg_analyzer.cpp index a69591a40..552075c57 100644 --- a/tests/svg_analyzer.cpp +++ b/tests/svg_analyzer.cpp @@ -82,3 +82,9 @@ void SVGAnalyzer::enter_element(SVG::SVGElementType type) { element.children.emplace_back(type); m_elements_in_process.push_back(&element.children.back()); } + +std::string SVGAnalyzer::svg_string(std::size_t indent_size) const { + std::string output{}; + output += m_svg.to_string(indent_size); + return output; +} diff --git a/tests/svg_analyzer.h b/tests/svg_analyzer.h index 124c1d7df..4c779a6f6 100644 --- a/tests/svg_analyzer.h +++ b/tests/svg_analyzer.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include "svg_analyzer_interface.h" @@ -34,6 +35,7 @@ public: std::size_t num_polylines() const { return m_num_polylines; }; std::size_t num_rects() const { return m_num_rects; }; std::size_t num_titles() const { return m_num_titles; }; + std::string svg_string(std::size_t indent_size = 2) const; private: /// Get the current element being processed by the SVG document traverser diff --git a/tests/svg_element.cpp b/tests/svg_element.cpp index 719430c73..20bac09e0 100644 --- a/tests/svg_element.cpp +++ b/tests/svg_element.cpp @@ -1,3 +1,69 @@ +#include + #include "svg_element.h" +#include SVG::SVGElement::SVGElement(SVGElementType type) : type(type) {} + +std::string SVG::SVGElement::to_string(std::size_t indent_size = 2) const { + std::string output; + output += R"()" + "\n"; + output += R"()" + "\n"; + to_string_impl(output, indent_size, 0); + return output; +} + +void SVG::SVGElement::to_string_impl(std::string &output, + std::size_t indent_size, + std::size_t current_indent) const { + const auto indent_str = std::string(current_indent, ' '); + output += indent_str; + + output += "<"; + output += tag(type); + + if (children.empty()) { + output += "/>\n"; + } else { + output += ">\n"; + for (const auto &child : children) { + child.to_string_impl(output, indent_size, current_indent + indent_size); + } + output += indent_str; + output += "\n"; + } +} + +std::string_view SVG::tag(SVGElementType type) { + switch (type) { + case SVG::SVGElementType::Circle: + return "circle"; + case SVG::SVGElementType::Ellipse: + return "ellipse"; + case SVG::SVGElementType::Group: + return "g"; + case SVG::SVGElementType::Line: + return "line"; + case SVG::SVGElementType::Path: + return "path"; + case SVG::SVGElementType::Polygon: + return "polygon"; + case SVG::SVGElementType::Polyline: + return "polyline"; + case SVG::SVGElementType::Rect: + return "rect"; + case SVG::SVGElementType::Svg: + return "svg"; + case SVG::SVGElementType::Text: + return "text"; + case SVG::SVGElementType::Title: + return "title"; + } + UNREACHABLE(); +} diff --git a/tests/svg_element.h b/tests/svg_element.h index 0e8acc848..cd9cc4ecc 100644 --- a/tests/svg_element.h +++ b/tests/svg_element.h @@ -1,5 +1,7 @@ #pragma once +#include +#include #include namespace SVG { @@ -18,6 +20,8 @@ enum class SVGElementType { Title, }; +std::string_view tag(SVG::SVGElementType type); + /** * @brief The SVGElement class represents an SVG element */ @@ -27,9 +31,15 @@ public: SVGElement() = delete; explicit SVGElement(SVG::SVGElementType type); + std::string to_string(std::size_t indent_size) const; + std::vector children; /// The type of SVG element const SVGElementType type; + +private: + void to_string_impl(std::string &output, std::size_t indent_size, + std::size_t current_indent) const; }; } // namespace SVG diff --git a/tests/test_svg_analyzer.cpp b/tests/test_svg_analyzer.cpp index 33e5f7211..20ce416c5 100644 --- a/tests/test_svg_analyzer.cpp +++ b/tests/test_svg_analyzer.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -12,7 +13,8 @@ TEST_CASE( "SvgAnalyzer", "The SvgAnalyzer parses an SVG produced by Graphviz to an internal data " - "structure and supports retrieval of information about that graph") { + "structure, supports retrieval of information about that graph and " + "recreation of the original SVG from that data structure") { const auto shape_char_ptr = GENERATE(from_range(all_node_shapes)); const std::string shape{shape_char_ptr}; @@ -102,5 +104,35 @@ TEST_CASE( CHECK(svgAnalyzer.num_polylines() == expected_num_polylines); CHECK(svgAnalyzer.num_rects() == expected_num_rects); CHECK(svgAnalyzer.num_titles() == expected_num_titles); + + const auto indent_size = 0; + auto recreated_svg = svgAnalyzer.svg_string(indent_size); + + // compare the initial lines of the recreated SVG that we can fully recreate + // with the original SVG + std::vector original_svg_lines; + boost::split(original_svg_lines, original_svg, boost::is_any_of("\n")); + std::vector recreated_svg_lines; + boost::split(recreated_svg_lines, recreated_svg, boost::is_any_of("\n")); + for (std::size_t i = 0; i < original_svg_lines.size(); i++) { + REQUIRE(i < recreated_svg_lines.size()); + if (recreated_svg_lines[i] == "") { + // stop comparison here since we do not yet handle the Graphviz version + // and build date comment and the graph title comment that comes before + // the 'svg' element + break; + } + REQUIRE(recreated_svg_lines[i] == original_svg_lines[i]); + } + + // do some sanity checks of the parts of the recreated SVG that we cannot + // yet compare with the original SVG + CHECK(recreated_svg.find("") != std::string::npos); + CHECK(recreated_svg.find("") != std::string::npos); + CHECK(recreated_svg.find("") != std::string::npos); + CHECK(recreated_svg.find("") != std::string::npos); + CHECK(recreated_svg.find("") != std::string::npos); + CHECK(recreated_svg.find("") != std::string::npos); + CHECK(recreated_svg.find("") != std::string::npos); } } -- 2.40.0