From 9e64fc913045fba67cb484ef8f03ba5252a08311 Mon Sep 17 00:00:00 2001 From: Magnus Jacobsson Date: Wed, 10 Aug 2022 09:36:08 +0200 Subject: [PATCH] tests: SVGAnalyzer: add handling of the 'stroke-width' attribute --- tests/CMakeLists.txt | 1 + tests/svg_analyzer.cpp | 4 +++ tests/svg_analyzer.h | 1 + tests/svg_analyzer_interface.h | 1 + tests/svg_element.cpp | 13 +++++++++ tests/svg_element.h | 2 ++ tests/svgpp_context.cpp | 4 +++ tests/svgpp_context.h | 1 + tests/svgpp_document_traverser.cpp | 43 ++++++++++++++++------------ tests/test_svg_analyzer_penwidth.cpp | 23 +++++++++++++++ 10 files changed, 74 insertions(+), 19 deletions(-) create mode 100644 tests/test_svg_analyzer_penwidth.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0b962959b..73daa0e52 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -89,3 +89,4 @@ CREATE_TEST(simple) CREATE_TEST(subgraph_layout) CREATE_TEST(subgraphs) CREATE_TEST(svg_analyzer) +CREATE_TEST(svg_analyzer_penwidth) diff --git a/tests/svg_analyzer.cpp b/tests/svg_analyzer.cpp index 8b1d1ae9f..348275055 100644 --- a/tests/svg_analyzer.cpp +++ b/tests/svg_analyzer.cpp @@ -227,6 +227,10 @@ void SVGAnalyzer::set_stroke(std::string_view stroke) { current_element().attributes.stroke = stroke; } +void SVGAnalyzer::set_stroke_width(double stroke_width) { + current_element().attributes.stroke_width = stroke_width; +} + void SVGAnalyzer::set_id(std::string_view id) { current_element().attributes.id = id; } diff --git a/tests/svg_analyzer.h b/tests/svg_analyzer.h index 8c48dcbe6..f035e312d 100644 --- a/tests/svg_analyzer.h +++ b/tests/svg_analyzer.h @@ -46,6 +46,7 @@ public: void set_ry(double ry) override; void set_class(std::string_view) override; void set_stroke(std::string_view stroke) override; + void set_stroke_width(double stroke_width) override; void set_point(std::pair point) override; void set_text(std::string_view text) override; void set_text_anchor(std::string_view text_anchor) override; diff --git a/tests/svg_analyzer_interface.h b/tests/svg_analyzer_interface.h index 2d147bcf3..0487134cf 100644 --- a/tests/svg_analyzer_interface.h +++ b/tests/svg_analyzer_interface.h @@ -42,6 +42,7 @@ public: virtual void set_ry(double ry) = 0; virtual void set_point(std::pair point) = 0; virtual void set_stroke(std::string_view stroke) = 0; + virtual void set_stroke_width(double stroke_width) = 0; virtual void set_text(std::string_view text) = 0; virtual void set_text_anchor(std::string_view text_anchor) = 0; virtual void set_transform(double a, double b, double c, double d, double e, diff --git a/tests/svg_element.cpp b/tests/svg_element.cpp index 0209e95bf..f2fee723c 100644 --- a/tests/svg_element.cpp +++ b/tests/svg_element.cpp @@ -202,6 +202,15 @@ std::string SVG::SVGElement::stroke_attribute_to_string() const { stroke_to_graphviz_color(attributes.stroke)); } +std::string SVG::SVGElement::stroke_width_attribute_to_string() const { + if (attributes.stroke_width == 1) { + // Graphviz doesn't set `stroke-width` to 1 since that's the default + return ""; + } + + return fmt::format(R"(stroke-width="{}")", attributes.stroke_width); +} + std::string SVG::SVGElement::to_string(std::size_t indent_size = 2) const { std::string output; output += R"()" @@ -242,6 +251,7 @@ void SVG::SVGElement::to_string_impl(std::string &output, case SVG::SVGElementType::Ellipse: append_attribute(attributes_str, fill_attribute_to_string()); append_attribute(attributes_str, stroke_attribute_to_string()); + append_attribute(attributes_str, stroke_width_attribute_to_string()); attributes_str += fmt::format(R"( cx="{}" cy="{}" rx="{}" ry="{}")", attributes.cx, attributes.cy, attributes.rx, attributes.ry); @@ -258,6 +268,7 @@ void SVG::SVGElement::to_string_impl(std::string &output, case SVG::SVGElementType::Path: { append_attribute(attributes_str, fill_attribute_to_string()); append_attribute(attributes_str, stroke_attribute_to_string()); + append_attribute(attributes_str, stroke_width_attribute_to_string()); attributes_str += R"|( d=")|"; auto command = 'M'; for (const auto &point : path_points) { @@ -281,11 +292,13 @@ void SVG::SVGElement::to_string_impl(std::string &output, case SVG::SVGElementType::Polygon: append_attribute(attributes_str, fill_attribute_to_string()); append_attribute(attributes_str, stroke_attribute_to_string()); + append_attribute(attributes_str, stroke_width_attribute_to_string()); append_attribute(attributes_str, points_attribute_to_string()); break; case SVG::SVGElementType::Polyline: append_attribute(attributes_str, fill_attribute_to_string()); append_attribute(attributes_str, stroke_attribute_to_string()); + append_attribute(attributes_str, stroke_width_attribute_to_string()); append_attribute(attributes_str, points_attribute_to_string()); break; case SVG::SVGElementType::Svg: diff --git a/tests/svg_element.h b/tests/svg_element.h index 11c3f5fe4..5aed78a01 100644 --- a/tests/svg_element.h +++ b/tests/svg_element.h @@ -65,6 +65,7 @@ struct SVGAttributes { double rx; double ry; std::string stroke; + double stroke_width = 1; std::string text_anchor; std::optional transform; SVGRect viewBox; @@ -118,6 +119,7 @@ private: std::string fill_attribute_to_string() const; std::string points_attribute_to_string() const; std::string stroke_attribute_to_string() const; + std::string stroke_width_attribute_to_string() const; std::string stroke_to_graphviz_color(const std::string &color) const; SVG::SVGRect text_bbox() const; void to_string_impl(std::string &output, std::size_t indent_size, diff --git a/tests/svgpp_context.cpp b/tests/svgpp_context.cpp index 2b19d03c4..24d321fa5 100644 --- a/tests/svgpp_context.cpp +++ b/tests/svgpp_context.cpp @@ -142,6 +142,10 @@ void SvgppContext::set(svgpp::tag::attribute::stroke, m_svg_analyzer->set_stroke(to_color_string(color)); } +void SvgppContext::set(svgpp::tag::attribute::stroke_width, const double v) { + m_svg_analyzer->set_stroke_width(v); +} + void SvgppContext::transform_matrix(const boost::array &matrix) { double a = matrix.at(0); double b = matrix.at(1); diff --git a/tests/svgpp_context.h b/tests/svgpp_context.h index fdf5da378..69551426c 100644 --- a/tests/svgpp_context.h +++ b/tests/svgpp_context.h @@ -149,6 +149,7 @@ public: throw std::runtime_error{ "this flavor of the 'stroke' attribute is not yet implemented"}; }; + void set(svgpp::tag::attribute::stroke_width, double v); void transform_matrix(const boost::array &matrix); void set(svgpp::tag::attribute::r r, double v); void set(svgpp::tag::attribute::rx rx, double v); diff --git a/tests/svgpp_document_traverser.cpp b/tests/svgpp_document_traverser.cpp index 62e4d6e5b..e02f69ea5 100644 --- a/tests/svgpp_document_traverser.cpp +++ b/tests/svgpp_document_traverser.cpp @@ -1,3 +1,7 @@ +// The pre-processed boost::mpl::set allows only 20 elements, but we need more +#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS +#define BOOST_MPL_LIMIT_SET_SIZE 40 + #include #include #include @@ -26,25 +30,26 @@ void traverseDocumentWithSvgpp(SvgppContext &context, char *text) { using processed_attributes_t = boost::mpl::set::type; svgpp::document_traversal< diff --git a/tests/test_svg_analyzer_penwidth.cpp b/tests/test_svg_analyzer_penwidth.cpp new file mode 100644 index 000000000..7f42a2c6a --- /dev/null +++ b/tests/test_svg_analyzer_penwidth.cpp @@ -0,0 +1,23 @@ +#include +#include + +#include "svg_analyzer.h" +#include "test_utilities.h" + +TEST_CASE("SvgAnalyzer penwidth", + "Test that the SvgAnalyzer can recreate the original SVG with the " + "correct `stroke-width` attribute when the Graphviz `penwidth` " + "attribute is used for nodes and edges") { + + const auto shape = GENERATE(from_range(all_node_shapes)); + INFO(fmt::format("Shape: {}", shape)); + + const auto penwidth = GENERATE(0.5, 1.0, 2.0); + INFO(fmt::format("Node and edge penwidth: {}", penwidth)); + + auto dot = fmt::format( + "digraph g1 {{node [shape={} penwidth={}]; edge [penwidth={}]; a -> b}}", + shape, penwidth, penwidth); + + SVGAnalyzer::make_from_dot(dot).re_create_and_verify_svg(); +} -- 2.40.0