summaryrefslogtreecommitdiffstats
path: root/testfiles/lpespaths-test.h
diff options
context:
space:
mode:
Diffstat (limited to 'testfiles/lpespaths-test.h')
-rw-r--r--testfiles/lpespaths-test.h235
1 files changed, 235 insertions, 0 deletions
diff --git a/testfiles/lpespaths-test.h b/testfiles/lpespaths-test.h
new file mode 100644
index 0000000..b2065b0
--- /dev/null
+++ b/testfiles/lpespaths-test.h
@@ -0,0 +1,235 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/** @file
+ * LPE test file wrapper
+ *//*
+ * Authors: see git history
+ *
+ * Copyright (C) 2020 Authors
+ *
+ * Released under GNU GPL version 2 or later, read the file 'COPYING' for more information
+ */
+
+#include <2geom/pathvector.h>
+#include <gtest/gtest.h>
+#include <src/file.h>
+#include <src/inkscape.h>
+#include <src/object/sp-root.h>
+#include <src/svg/svg.h>
+
+#include "src/extension/init.h"
+#include "inkscape-application.h"
+#include "src/util/numeric/converters.h"
+
+using namespace Inkscape;
+
+/* This class allow test LPE's. To make possible in latest release of Inkscape
+ * LPE is not updated on load (if in the future any do we must take account) so we load
+ * a svg, get all "d" attribute from paths, shapes...
+ * Update all path effects with root object and check equality of paths.
+ * We use some helpers inside the SVG document to test:
+ * inkscape:test-threshold="0.1" can be global using in root element or per item
+ * inkscape:test-ignore="1" ignore this element from tests
+ * Question: Maybe is better store SVG as files instead inline CPP files, there is a
+ * 1.2 started MR, I can't finish without too much work than a cmake advanced user
+ */
+
+class LPESPathsTest : public ::testing::Test
+{
+protected:
+ void SetUp() override
+ {
+ // setup hidden dependency
+ Application::create(false);
+ Inkscape::Extension::init();
+ const testing::TestInfo* const test_info =
+ testing::UnitTest::GetInstance()->current_test_info();
+ svg = test_info->file();;
+#ifdef INKSCAPE_TESTS_DIR
+ svg = INKSCAPE_TESTS_DIR;
+#else
+ size_t pos = svg.find("lpespaths-test.h");
+ svg.erase(pos);
+#endif
+ svg += "/lpe_tests/"; // gitlab use this separator
+ /* svg += test_info->test_suite_name(); */
+ svg += test_info->name();
+ svg += ".svg";
+ }
+
+ void pathCompare(char const *a, char const *b, Glib::ustring const &id, double precision = 0.001)
+ {
+ bool success = false;
+ pathCompareInternal(a, b, precision, success);
+ if (!success) {
+ #define DIAG(x) " " << #x << ":\n " << x << std::endl
+ std::cout << "More information about the failure:\n" << DIAG(svg) << DIAG(id) << DIAG(a) << DIAG(b);
+ failed.emplace_back(id);
+ }
+ }
+
+ void pathCompareInternal(char const *a, char const *b, double precision, bool &success)
+ {
+ bool a_empty = a[0] == '\0';
+ bool b_empty = b[0] == '\0';
+ if (a_empty || b_empty) {
+ if (a_empty && b_empty) {
+ success = true;
+ return;
+ } else {
+ FAIL() << "Mismatching emptiness of paths";
+ }
+ }
+
+ Geom::PathVector apv = sp_svg_read_pathv(a);
+ Geom::PathVector bpv = sp_svg_read_pathv(b);
+ if (apv.empty()) {
+ FAIL() << "Couldn't parse original 'd'";
+ }
+ if (bpv.empty()) {
+ FAIL() << "Couldn't parse 'd'";
+ }
+
+ size_t totala = apv.curveCount();
+ size_t totalb = bpv.curveCount();
+ ASSERT_EQ(totala, totalb);
+
+ // find initial
+ size_t initial = 0;
+ for (size_t i = 0; i < totala; i++) {
+ Geom::Point pointa = apv.pointAt(0.0);
+ Geom::Point pointb = bpv.pointAt(i);
+ if (Geom::are_near(pointa, pointb, precision)) {
+ initial = i;
+ break;
+ }
+ }
+
+ if (initial != 0 && initial == totala) {
+ std::cout << "[ WARN ] Curve reversed. We do not block here. We reverse the path and test node positions on reverse" << std::endl;
+ bpv.reverse();
+ } else if (initial != 0) {
+ std::cout << "[ WARN ] Different starting node. We do not block here. We gap the origin to " << initial << " de " << totala << " and test with the pathvector reindexed" << std::endl;
+ }
+
+ for (size_t i = 0; i < totala; i++) {
+ if (initial >= totala) {
+ initial = 0;
+ }
+ Geom::Point pointa = apv.pointAt(i + 0.2);
+ Geom::Point pointb = bpv.pointAt(initial + 0.2);
+ Geom::Point pointc = apv.pointAt(i + 0.4);
+ Geom::Point pointd = bpv.pointAt(initial + 0.4);
+ Geom::Point pointe = apv.pointAt(i);
+ Geom::Point pointf = bpv.pointAt(initial);
+ ASSERT_NEAR(pointa[Geom::X], pointb[Geom::X], precision);
+ ASSERT_NEAR(pointa[Geom::Y], pointb[Geom::Y], precision);
+ ASSERT_NEAR(pointc[Geom::X], pointd[Geom::X], precision);
+ ASSERT_NEAR(pointc[Geom::Y], pointd[Geom::Y], precision);
+ ASSERT_NEAR(pointe[Geom::X], pointf[Geom::X], precision);
+ ASSERT_NEAR(pointe[Geom::Y], pointf[Geom::Y], precision);
+ initial++;
+ }
+
+ success = true;
+ }
+
+ void TearDown() override
+ {
+ Glib::ustring ids = "";
+ for (auto fail : failed) {
+ if (ids != "") {
+ ids += ",";
+ }
+ ids += fail;
+ }
+ if (ids != "") {
+ FAIL() << "[FAILED IDS] " << ids;
+ }
+ }
+
+ // you can override custom threshold from svg file using in
+ // root svg from global and override with per shape "inkscape:test-threshold"
+ void testDoc(std::string file)
+ {
+ double precision = 0.001;
+ auto doc = SPDocument::createNewDoc(file.c_str(), false);
+ ASSERT_TRUE(doc != nullptr);
+ SPLPEItem *lpeitem = doc->getRoot();
+ std::vector<SPObject *> objs;
+ std::vector<Glib::ustring> ids;
+ std::vector<Glib::ustring> lpes;
+ std::vector<Glib::ustring> ds;
+ for (auto obj : doc->getObjectsByElement("path")) {
+ objs.push_back(obj);
+ }
+ for (auto obj : doc->getObjectsByElement("ellipse")) {
+ objs.push_back(obj);
+ }
+ for (auto obj : doc->getObjectsByElement("circle")) {
+ objs.push_back(obj);
+ }
+ for (auto obj : doc->getObjectsByElement("rect")) {
+ objs.push_back(obj);
+ }
+ for (auto obj : objs) {
+ SPObject *parentobj = obj->parent;
+ SPObject *layer = obj;
+ while (parentobj->parent && parentobj->parent->parent) {
+ layer = parentobj;
+ parentobj = parentobj->parent;
+ }
+ if (!g_strcmp0(obj->getAttribute("d"), "M 0,0")) {
+ if (obj->getAttribute("id")) {
+ std::cout << "[ WARN ] Item with id:" << obj->getAttribute("id") << " has empty path data" << std::endl;
+ }
+ } else if (!layer->getAttribute("inkscape:test-ignore") && obj->getAttribute("d") && obj->getAttribute("id")) {
+ ds.push_back(Glib::ustring(obj->getAttribute("d")));
+ ids.push_back(Glib::ustring(obj->getAttribute("id")));
+ lpes.push_back(Glib::ustring(layer->getAttribute("inkscape:label") ? layer->getAttribute("inkscape:label") : layer->getAttribute("id")));
+ }
+ }
+ sp_file_fix_lpe(doc);
+ doc->ensureUpToDate();
+ sp_lpe_item_update_patheffect(lpeitem, true, true, true);
+ // to bypass onload
+ sp_lpe_item_update_patheffect(lpeitem, true, true, true);
+ if (lpeitem->getAttribute("inkscape:test-threshold")) {
+ precision = Util::read_number(lpeitem->getAttribute("inkscape:test-threshold"));
+ }
+ size_t index = 0;
+ for (auto id : ids) {
+ SPObject *obj = doc->getObjectById(id);
+ if (obj) {
+ if (obj->getAttribute("inkscape:test-threshold")) {
+ precision = Util::read_number(obj->getAttribute("inkscape:test-threshold"));
+ }
+ if (!obj->getAttribute("inkscape:test-ignore")) {
+ Glib::ustring idandlayer = "";
+ idandlayer = obj->getAttribute("id");
+ idandlayer += "("; // top layers has the LPE name tested in in id
+ idandlayer += lpes[index];
+ idandlayer += ")";
+ pathCompare(ds[index].c_str(), obj->getAttribute("d"), idandlayer , precision);
+ } else {
+ std::cout << "[ WARN ] Item with id:" << obj->getAttribute("id") << " ignored by inkscape:test-ignore" << std::endl;
+ }
+ } else {
+ std::cout << "[ WARN ] Item with id:" << id << " removed on apply LPE" << std::endl;
+ }
+ index++;
+ }
+ }
+ std::string svg = "";
+ std::vector<Glib::ustring> failed;
+};
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :