SVG parser unit test - add attribute comparison framework + test data

This commit is contained in:
Artem Pavlenko 2022-12-11 10:13:26 +00:00
parent 0b62415225
commit d29aeb2ddb
2 changed files with 101 additions and 65 deletions

@ -1 +1 @@
Subproject commit 5206bfd11f122bc8fe81519d39768b30108da03a Subproject commit 95789262db507872c5976756777ee4cf64457ea5

View file

@ -30,59 +30,124 @@
#include <mapnik/svg/svg_converter.hpp> #include <mapnik/svg/svg_converter.hpp>
#include <mapnik/svg/svg_path_adapter.hpp> #include <mapnik/svg/svg_path_adapter.hpp>
#include <mapnik/svg/svg_path_attributes.hpp> #include <mapnik/svg/svg_path_attributes.hpp>
#include <mapnik/util/fs.hpp>
#include "util.hpp" #include "util.hpp"
#include <fstream> #include <fstream>
#include <iterator> #include <iterator>
#include <iomanip>
#include <sstream>
// boost
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <boost/property_tree/json_parser.hpp>
namespace // internal namespace // internal
{ {
template<int MAX>
std::ostream& operator<<(std::ostream& os, agg::rgba8 const& c)
{
os << mapnik::color{c.r, c.g, c.b, c.a};
return os;
}
std::ostream& operator<<(std::ostream& os, mapnik::gradient const& gr)
{
double cx, cy, fx, fy, r;
gr.get_control_points(fx, fy, cx, cy, r);
os << "<gradient cx=\"" << cx << "\" cy=\"" << cy << "\""
<< " fx=\"" << fx << "\" fy=\"" << fy << "\" r=\"" << r << "\">\n";
for (auto const& stop : gr.get_stop_array())
{
os << " <stop offset=\"" << std::get<0>(stop) << "\" color=\"" << std::get<1>(stop) << "\"/>\n";
}
os << "</gradient>\n";
return os;
}
std::ostream& operator<<(std::ostream& os, agg::trans_affine const& tr)
{
os << "<transform>matrix(" << tr.sx << "," << tr.shy << ","
<< tr.shx << "," << tr.sy << "," << tr.tx << ","
<< tr.ty << ")</transform>";
return os;
}
struct group_attribute_visitor struct group_attribute_visitor
{ {
group_attribute_visitor(int& index) group_attribute_visitor(std::stringstream& ss, unsigned padding)
: index_(index) : ss_(ss), padding_(padding)
{} {}
void operator()(mapnik::svg::group const& g) const void operator()(mapnik::svg::group const& g) const
{ {
std::cerr << " <g opacity=" << g.opacity << ">" << std::endl; padding_ += 2;
//ss_ << "padding=>" << padding_ << std::endl;
std::string pad(padding_, ' ');
ss_ << pad << "<g opacity=\"" << g.opacity << "\">" << std::endl;
for (auto const& elem : g.elements) for (auto const& elem : g.elements)
{ {
mapbox::util::apply_visitor(group_attribute_visitor<MAX>(index_), elem); mapbox::util::apply_visitor(group_attribute_visitor(ss_, padding_), elem);
} }
std::cerr << " </g>" << std::endl; ss_ << pad << "</g>" << std::endl;
padding_ -= 2;
} }
void operator()(mapnik::svg::path_attributes const& attr) const void operator()(mapnik::svg::path_attributes const& attr) const
{ {
if (index_++ == MAX) padding_ += 2;
std::string pad(padding_, ' ');
ss_ << pad << "<attribute index=\"" << attr.index << "\">" << std::endl;
ss_ << pad << attr.transform << std::endl;
if (!attr.fill_gradient.get_stop_array().empty())
ss_ << pad << attr.fill_gradient;
if (!attr.stroke_gradient.get_stop_array().empty())
ss_ << pad << attr.stroke_gradient;
ss_ << pad << " <opacity>" << attr.opacity << "</opacity>" << std::endl;
ss_ << pad << " <fill>" << attr.fill_color << "</fill>" << std::endl;
ss_ << pad << " <fill-opacity>" << attr.fill_opacity << "</fill-opacity>" << std::endl;
ss_ << pad << " <stroke>" << attr.stroke_color << "</stroke>" << std::endl;
ss_ << pad << " <stroke-width>" << attr.stroke_width << "</stroke-width>" << std::endl;
ss_ << pad << " <stroke-opacity>" << attr.stroke_opacity << "</stroke-opacity>" << std::endl;
ss_ << pad << "</attribute>" << std::endl;
padding_ -=2;
}
std::stringstream& ss_;
mutable unsigned padding_;
};
bool check_equal_attributes(std::string const& svg_file, mapnik::svg::group const& g)
{ {
std::cerr << " <attribute index=" << attr.index << ">" << std::endl; unsigned padding = 0;
std::cerr << " <opacity>" << attr.opacity << "</opacity>" << std::endl; std::stringstream ss;
// std::cerr << " <fill>" << attr.fill_color << "</fill>" << std::endl; ss << "<svg opacity=\"" << g.opacity << "\">" << std::endl;
std::cerr << " <fill-opacity>" << attr.fill_opacity << "</fill-opacity>" << std::endl; for (auto const& elem : g.elements)
// std::cerr << " <stroke>" << attr.stroke_color << "</stroke>" << std::endl; {
std::cerr << " <stroke-width>" << attr.stroke_width << "</stroke-width>" << std::endl; mapbox::util::apply_visitor(group_attribute_visitor(ss, padding), elem);
std::cerr << " <stroke-opacity>" << attr.stroke_opacity << "</stroke-opacity>" << std::endl; }
std::cerr << " </attribute>" << std::endl; ss << "</svg>" << std::endl;
std::string well_known_xml = svg_file + ".xml";
if (!mapnik::util::exists(well_known_xml))
{
std::cerr << "Well-known-xml-filename:" << well_known_xml << std::endl;
std::cerr << ss.str() << std::endl;
return false;
} }
else else
{ {
std::cerr << " </skip>" << std::endl; boost::property_tree::ptree t0, t1;
} boost::property_tree::read_xml(well_known_xml, t0, boost::property_tree::xml_parser::trim_whitespace);
} boost::property_tree::read_xml(ss, t1, boost::property_tree::xml_parser::trim_whitespace);
int& index_;
};
template<int MAX> if (t0 != t1)
void group_attribute_printer(mapnik::svg::group const& g)
{ {
std::cerr << "<svg opacity=" << g.opacity << ">" << std::endl; std::cerr << ss.str() << std::endl;
int index = 0; }
for (auto const& elem : g.elements) return (t0 == t1);
{
mapbox::util::apply_visitor(group_attribute_visitor<MAX>(index), elem);
} }
std::cerr << "</svg>" << std::endl;
} }
struct test_parser struct test_parser
@ -312,11 +377,9 @@ TEST_CASE("SVG parser")
auto const& group_attrs = storage->svg_group(); auto const& group_attrs = storage->svg_group();
agg::line_cap_e expected_cap(agg::square_cap); agg::line_cap_e expected_cap(agg::square_cap);
REQUIRE(group_attrs.elements.size() == 1);
// FIXME
// REQUIRE(attrs[0].line_cap == expected_cap); REQUIRE(check_equal_attributes(svg_name, group_attrs));
group_attribute_printer<0>(group_attrs);
double x, y; double x, y;
unsigned cmd; unsigned cmd;
std::vector<std::tuple<double, double, unsigned>> vec; std::vector<std::tuple<double, double, unsigned>> vec;
@ -480,9 +543,7 @@ TEST_CASE("SVG parser")
auto const& group_attrs = storage->svg_group(); auto const& group_attrs = storage->svg_group();
agg::line_join_e expected_join(agg::bevel_join); agg::line_join_e expected_join(agg::bevel_join);
REQUIRE(group_attrs.elements.size() == 1); REQUIRE(check_equal_attributes(svg_name, group_attrs));
// FIXME
// REQUIRE(attrs[0].line_join == expected_join);
} }
SECTION("SVG <line>") SECTION("SVG <line>")
@ -717,10 +778,7 @@ TEST_CASE("SVG parser")
auto const& group_attrs = storage->svg_group(); auto const& group_attrs = storage->svg_group();
// REQUIRE(group_attrs.elements.size() == 3); REQUIRE(check_equal_attributes(svg_name, group_attrs));
// FIXME
// REQUIRE(attrs[1].fill_gradient == attrs[2].fill_gradient);
mapnik::svg::svg_path_adapter path(stl_storage); mapnik::svg::svg_path_adapter path(stl_storage);
double x, y; double x, y;
unsigned cmd; unsigned cmd;
@ -768,13 +826,7 @@ TEST_CASE("SVG parser")
REQUIRE(storage); REQUIRE(storage);
auto const& group_attrs = storage->svg_group(); auto const& group_attrs = storage->svg_group();
// FIXME REQUIRE(check_equal_attributes(svg_name, group_attrs));
// REQUIRE(attrs.size() == 3);
// REQUIRE(attrs[1].fill_gradient == attrs[2].fill_gradient);
// REQUIRE(attrs[1].fill_gradient.get_gradient_type() == mapnik::RADIAL);
agg::trans_affine transform;
transform *= agg::trans_affine_translation(240, 155);
// REQUIRE(attrs[1].fill_gradient.get_transform() == transform);
} }
SECTION("SVG <gradient> with xlink:href") SECTION("SVG <gradient> with xlink:href")
@ -790,11 +842,7 @@ TEST_CASE("SVG parser")
REQUIRE(storage); REQUIRE(storage);
auto const& group_attrs = storage->svg_group(); auto const& group_attrs = storage->svg_group();
// FIXME REQUIRE(check_equal_attributes(svg_name, group_attrs));
// REQUIRE(attrs.elements.size() == 2);
// REQUIRE(attrs[0].fill_gradient.get_gradient_type() == mapnik::LINEAR);
// REQUIRE(attrs[1].fill_gradient.get_gradient_type() == mapnik::LINEAR);
// REQUIRE(attrs[1].fill_gradient.has_stop());
} }
SECTION("SVG <gradient> with radial percents") SECTION("SVG <gradient> with radial percents")
@ -808,19 +856,7 @@ TEST_CASE("SVG parser")
REQUIRE(bbox == mapnik::box2d<double>(0, 0, 200, 200)); REQUIRE(bbox == mapnik::box2d<double>(0, 0, 200, 200));
auto storage = svg.get_data(); auto storage = svg.get_data();
REQUIRE(storage); REQUIRE(storage);
REQUIRE(check_equal_attributes(svg_name, storage->svg_group()));
double x1, x2, y1, y2, r;
// FIXME
// auto const& attrs = storage->attributes();
// REQUIRE(attrs.size() == 1);
// REQUIRE(attrs[0].fill_gradient.get_gradient_type() == mapnik::RADIAL);
// REQUIRE(attrs[0].fill_gradient.has_stop());
// attrs[0].fill_gradient.get_control_points(x1, y1, x2, y2, r);
// REQUIRE(x1 == 0);
// REQUIRE(y1 == 0.25);
// REQUIRE(x2 == 0.10);
// REQUIRE(y2 == 0.10);
// REQUIRE(r == 0.75);
} }
SECTION("SVG <clipPath>") SECTION("SVG <clipPath>")