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_path_adapter.hpp>
#include <mapnik/svg/svg_path_attributes.hpp>
#include <mapnik/util/fs.hpp>
#include "util.hpp"
#include <fstream>
#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
{
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
{
group_attribute_visitor(int& index)
: index_(index)
group_attribute_visitor(std::stringstream& ss, unsigned padding)
: ss_(ss), padding_(padding)
{}
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)
{
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
{
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)
{
unsigned padding = 0;
std::stringstream ss;
ss << "<svg opacity=\"" << g.opacity << "\">" << std::endl;
for (auto const& elem : g.elements)
{
std::cerr << " <attribute index=" << attr.index << ">" << std::endl;
std::cerr << " <opacity>" << attr.opacity << "</opacity>" << std::endl;
// std::cerr << " <fill>" << attr.fill_color << "</fill>" << std::endl;
std::cerr << " <fill-opacity>" << attr.fill_opacity << "</fill-opacity>" << std::endl;
// std::cerr << " <stroke>" << attr.stroke_color << "</stroke>" << std::endl;
std::cerr << " <stroke-width>" << attr.stroke_width << "</stroke-width>" << std::endl;
std::cerr << " <stroke-opacity>" << attr.stroke_opacity << "</stroke-opacity>" << std::endl;
std::cerr << " </attribute>" << std::endl;
mapbox::util::apply_visitor(group_attribute_visitor(ss, padding), elem);
}
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
{
std::cerr << " </skip>" << std::endl;
}
}
int& index_;
};
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);
template<int MAX>
void group_attribute_printer(mapnik::svg::group const& g)
{
std::cerr << "<svg opacity=" << g.opacity << ">" << std::endl;
int index = 0;
for (auto const& elem : g.elements)
if (t0 != t1)
{
mapbox::util::apply_visitor(group_attribute_visitor<MAX>(index), elem);
std::cerr << ss.str() << std::endl;
}
return (t0 == t1);
}
std::cerr << "</svg>" << std::endl;
}
struct test_parser
@ -312,11 +377,9 @@ TEST_CASE("SVG parser")
auto const& group_attrs = storage->svg_group();
agg::line_cap_e expected_cap(agg::square_cap);
REQUIRE(group_attrs.elements.size() == 1);
// FIXME
// REQUIRE(attrs[0].line_cap == expected_cap);
group_attribute_printer<0>(group_attrs);
REQUIRE(check_equal_attributes(svg_name, group_attrs));
double x, y;
unsigned cmd;
std::vector<std::tuple<double, double, unsigned>> vec;
@ -480,9 +543,7 @@ TEST_CASE("SVG parser")
auto const& group_attrs = storage->svg_group();
agg::line_join_e expected_join(agg::bevel_join);
REQUIRE(group_attrs.elements.size() == 1);
// FIXME
// REQUIRE(attrs[0].line_join == expected_join);
REQUIRE(check_equal_attributes(svg_name, group_attrs));
}
SECTION("SVG <line>")
@ -717,10 +778,7 @@ TEST_CASE("SVG parser")
auto const& group_attrs = storage->svg_group();
// REQUIRE(group_attrs.elements.size() == 3);
// FIXME
// REQUIRE(attrs[1].fill_gradient == attrs[2].fill_gradient);
REQUIRE(check_equal_attributes(svg_name, group_attrs));
mapnik::svg::svg_path_adapter path(stl_storage);
double x, y;
unsigned cmd;
@ -768,13 +826,7 @@ TEST_CASE("SVG parser")
REQUIRE(storage);
auto const& group_attrs = storage->svg_group();
// FIXME
// 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);
REQUIRE(check_equal_attributes(svg_name, group_attrs));
}
SECTION("SVG <gradient> with xlink:href")
@ -790,11 +842,7 @@ TEST_CASE("SVG parser")
REQUIRE(storage);
auto const& group_attrs = storage->svg_group();
// FIXME
// 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());
REQUIRE(check_equal_attributes(svg_name, group_attrs));
}
SECTION("SVG <gradient> with radial percents")
@ -808,19 +856,7 @@ TEST_CASE("SVG parser")
REQUIRE(bbox == mapnik::box2d<double>(0, 0, 200, 200));
auto storage = svg.get_data();
REQUIRE(storage);
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);
REQUIRE(check_equal_attributes(svg_name, storage->svg_group()));
}
SECTION("SVG <clipPath>")