summaryrefslogtreecommitdiffstats
path: root/testfiles/src
diff options
context:
space:
mode:
authorAdrian Boguszewski <adrbogus1@student.pg.gda.pl>2018-06-09 21:40:28 +0000
committerAdrian Boguszewski <adrbogus1@student.pg.gda.pl>2018-06-09 21:40:28 +0000
commit60ecfba7009619f285c2b469b2c378300ec726a0 (patch)
tree7ee73a1586fc5c679fedea23a9575b7c7cfbc095 /testfiles/src
parentMerge branch 'gadic/inkscape-transl_fr' (diff)
downloadinkscape-60ecfba7009619f285c2b469b2c378300ec726a0.tar.gz
inkscape-60ecfba7009619f285c2b469b2c378300ec726a0.zip
Migrated object-test and sp-gradient-test to gtest
Diffstat (limited to 'testfiles/src')
-rw-r--r--testfiles/src/cxxtests-to-migrate/object-test.h234
-rw-r--r--testfiles/src/cxxtests-to-migrate/sp-gradient-test.h161
-rw-r--r--testfiles/src/object-test.cpp205
-rw-r--r--testfiles/src/sp-gradient-test.cpp129
4 files changed, 334 insertions, 395 deletions
diff --git a/testfiles/src/cxxtests-to-migrate/object-test.h b/testfiles/src/cxxtests-to-migrate/object-test.h
deleted file mode 100644
index 0af823684..000000000
--- a/testfiles/src/cxxtests-to-migrate/object-test.h
+++ /dev/null
@@ -1,234 +0,0 @@
-#ifndef SEEN_OBJECT_TEST_H
-#define SEEN_OBJECT_TEST_H
-
-#include <cassert>
-#include <ctime>
-#include <cxxtest/TestSuite.h>
-#include <string>
-#include <vector>
-
-#include "document.h"
-#include "sp-item-group.h"
-#include "sp-object.h"
-#include "sp-path.h"
-#include "sp-root.h"
-#include "xml/document.h"
-#include "xml/node.h"
-
-class ObjectTest : public CxxTest::TestSuite
-{
-public:
- virtual ~ObjectTest() {}
-
- static ObjectTest *createSuite() { return new ObjectTest(); }
- static void destroySuite(ObjectTest *suite) { delete suite; }
-
- void testObjects()
- {
- clock_t begin, end;
- // Sample document
- // svg:svg
- // svg:defs
- // svg:path
- // svg:linearGradient
- // svg:stop
- // svg:filter
- // svg:feGaussianBlur (feel free to implement for other filters)
- // svg:clipPath
- // svg:rect
- // svg:g
- // svg:use
- // svg:circle
- // svg:ellipse
- // svg:text
- // svg:polygon
- // svg:polyline
- // svg:image
- // svg:line
-
- char const *docString =
- "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n"
- "<!-- just a comment -->\n"
- "<title id=\"title\">SVG test</title>\n"
- "<defs>\n"
- " <path id=\"P\" d=\"M -21,-4 -5,0 -18,12 -3,4 -4,21 0,5 12,17 4,2 21,3 5,-1 17,-12 2,-4 3,-21 -1,-5 -12,-18 -4,-3z\"/>\n"
- " <linearGradient id=\"LG\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"0%\">\n"
- " <stop offset=\"0%\" style=\"stop-color:#ffff00;stop-opacity:1\"/>\n"
- " <stop offset=\"100%\" style=\"stop-color:red;stop-opacity:1\"/>\n"
- " </linearGradient>\n"
- " <clipPath id=\"clip\" clipPathUnits=\"userSpaceOnUse\">\n"
- " <rect x=\"10\" y=\"10\" width=\"100\" height=\"100\"/>\n"
- " </clipPath>\n"
- " <filter style=\"color-interpolation-filters:sRGB\" id=\"filter\" x=\"-0.15\" width=\"1.34\" y=\"0\" height=\"1\">\n"
- " <feGaussianBlur stdDeviation=\"4.26\"/>\n"
- " </filter>\n"
- "</defs>\n"
-
- "<g id=\"G\" transform=\"skewX(10.5) translate(9,5)\">\n"
- " <use id=\"U\" xlink:href=\"#P\" opacity=\"0.5\" fill=\"#1dace3\" transform=\"rotate(4)\"/>\n"
- " <circle id=\"C\" cx=\"45.5\" cy=\"67\" r=\"23\" fill=\"#000\"/>\n"
- " <ellipse id=\"E\" cx=\"200\" cy=\"70\" rx=\"85\" ry=\"55\" fill=\"url(#LG)\"/>\n"
- " <text id=\"T\" fill=\"#fff\" style=\"font-size:45;font-family:Verdana\" x=\"150\" y=\"86\">TEST</text>\n"
- " <polygon id=\"PG\" points=\"60,20 100,40 100,80 60,100 20,80 20,40\" clip-path=\"url(#clip)\" filter=\"url(#filter)\"/>\n"
- " <polyline id=\"PL\" points=\"0,40 40,40 40,80 80,80 80,120 120,120 120,160\" style=\"fill:none;stroke:red;stroke-width:4\"/>\n"
- " <image id=\"I\" xlink:href=\"data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjE4MCIgd2lkdGg9IjUwMCI+PHBhdGggZD0iTTAsNDAgNDAsNDAgNDAs" // this is one line
- "ODAgODAsODAgODAsMTIwIDEyMCwxMjAgMTIwLDE2MCIgc3R5bGU9ImZpbGw6d2hpdGU7c3Ryb2tlOnJlZDtzdHJva2Utd2lkdGg6NCIvPjwvc3ZnPgo=\"/>\n"
- " <line id=\"L\" x1=\"20\" y1=\"100\" x2=\"100\" y2=\"20\" stroke=\"black\" stroke-width=\"2\"/>\n"
- "</g>\n"
- "</svg>\n";
-
- begin = clock();
- SPDocument *doc = SPDocument::createNewDocFromMem(docString, strlen(docString), false);
- end = clock();
-
- assert(doc != NULL); // cannot continue if doc is null, abort!
- assert(doc->getRoot() != NULL);
-
- SPRoot *root = doc->getRoot();
- assert(root->getRepr() != NULL);
- assert(root->hasChildren());
-
- std::cout << "Took " << double(end - begin) / double(CLOCKS_PER_SEC) << " seconds to construct the test document\n";
-
- SPPath *path = dynamic_cast<SPPath *>(doc->getObjectById("P"));
- testClones(path);
-
- SPGroup *group = dynamic_cast<SPGroup *>(doc->getObjectById("G"));
- testGrouping(group);
-
- // Test parent behavior
- SPObject *child = root->firstChild();
- assert(child != NULL);
- TS_ASSERT(child->parent == root);
- TS_ASSERT(child->document == doc);
- TS_ASSERT(root->isAncestorOf(child));
-
- // Test list behavior
- SPObject *next = child->getNext();
- SPObject *prev = next;
- TS_ASSERT(next->getPrev() == child);
- prev = next;
- next = next->getNext();
- while (next != NULL) {
- // Walk the list
- TS_ASSERT(next->getPrev() == prev);
- prev = next;
- next = next->getNext();
- }
-
- // Test hrefcount
- TS_ASSERT(path->isReferenced());
- }
-
- void testClones(SPPath *path)
- {
- clock_t begin, end;
-
- assert(path != NULL);
-
- // Since we don't yet have any clean way to do this (FIXME), we'll abuse the XML tree a bit.
- Inkscape::XML::Node *node = path->getRepr();
- assert(node != NULL);
-
- Inkscape::XML::Document *xml_doc = node->document();
-
- Inkscape::XML::Node *parent = node->parent();
- assert(parent != NULL);
-
- TS_TRACE("Benchmarking clones...");
- const size_t num_clones = 10000;
-
- std::string href(std::string("#") + std::string(path->getId()));
- std::vector<Inkscape::XML::Node *> clones(num_clones, NULL);
-
- begin = clock();
- // Create num_clones clones of this path and stick them in the document
- for (size_t i = 0; i < num_clones; ++i) {
- Inkscape::XML::Node *clone = xml_doc->createElement("svg:use");
- Inkscape::GC::release(clone);
- clone->setAttribute("xlink:href", href.c_str());
- parent->addChild(clone, node);
- clones[i] = clone;
- }
- end = clock();
-
- std::cout << "Took " << double(end - begin) / double(CLOCKS_PER_SEC) << " seconds to write " << num_clones << " clones of a path\n";
-
- begin = clock();
- // Remove those clones
- for (size_t i = num_clones - 1; i >= 1; --i) {
- parent->removeChild(clones[i]);
- }
- end = clock();
-
- std::cout << "Took " << double(end - begin) / double(CLOCKS_PER_SEC) << " seconds to remove " << num_clones << " clones of a path\n";
- }
-
- void testGrouping(SPGroup *group)
- {
- clock_t begin, end;
-
- assert(group != NULL);
-
- // Since we don't yet have any clean way to do this (FIXME), we'll abuse the XML tree a bit.
- Inkscape::XML::Node *node = group->getRepr();
- assert(node != NULL);
-
- Inkscape::XML::Document *xml_doc = node->document();
-
- TS_TRACE("Benchmarking groups...");
- const size_t num_elements = 10000;
-
- Inkscape::XML::Node *new_group = xml_doc->createElement("svg:g");
- Inkscape::GC::release(new_group);
- node->addChild(new_group, NULL);
-
- std::vector<Inkscape::XML::Node *> elements(num_elements, NULL);
-
- begin = clock();
- for (size_t i = 0; i < num_elements; ++i) {
- Inkscape::XML::Node *circle = xml_doc->createElement("svg:circle");
- Inkscape::GC::release(circle);
- circle->setAttribute("cx", "2048");
- circle->setAttribute("cy", "1024");
- circle->setAttribute("r", "1.5");
- new_group->addChild(circle, NULL);
- elements[i] = circle;
- }
- end = clock();
-
- std::cout << "Took " << double(end - begin) / double(CLOCKS_PER_SEC) << " seconds to write " << num_elements << " elements into a group\n";
-
- SPGroup *n_group = dynamic_cast<SPGroup *>(group->get_child_by_repr(new_group));
- assert(n_group != NULL);
-
- begin = clock();
- std::vector<SPItem*> ch;
- sp_item_group_ungroup(n_group, ch, false);
- end = clock();
-
- std::cout << "Took " << double(end - begin) / double(CLOCKS_PER_SEC) << " seconds to ungroup a <g> with " << num_elements << " elements\n";
- std::cout << " Note: sp_item_group_ungroup_handle_clones() is responsible\n for most of the time as it is linear in number of elements\n which results in quadratic behavior for ungrouping." << std::endl;
-
- begin = clock();
- // Remove those elements
- for (size_t i = num_elements - 1; i >= 1; --i) {
- elements[i]->parent()->removeChild(elements[i]);
- }
- end = clock();
-
- std::cout << "Took " << double(end - begin) / double(CLOCKS_PER_SEC) << " seconds to remove " << num_elements << " elements\n";
- }
-};
-#endif // SEEN_OBJECT_TEST_H
-
-/*
- Local Variables:
- mode:c++
- c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
- indent-tabs-mode:nil
- fill-column:99
- End:
-*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/testfiles/src/cxxtests-to-migrate/sp-gradient-test.h b/testfiles/src/cxxtests-to-migrate/sp-gradient-test.h
deleted file mode 100644
index 578d0c5c0..000000000
--- a/testfiles/src/cxxtests-to-migrate/sp-gradient-test.h
+++ /dev/null
@@ -1,161 +0,0 @@
-#ifndef SEEN_SP_GRADIENT_TEST_H
-#define SEEN_SP_GRADIENT_TEST_H
-
-#include "document-using-test.h"
-
-
-#include "sp-gradient.h"
-#include "svg/svg.h"
-#include "xml/repr.h"
-#include <2geom/transforms.h>
-#include "helper/geom.h"
-
-class SPGradientTest : public DocumentUsingTest
-{
-public:
- SPDocument* _doc;
-
- SPGradientTest() :
- _doc(0)
- {
- }
-
- virtual ~SPGradientTest()
- {
- if ( _doc )
- {
- _doc->doUnref();
- }
- }
-
- static void createSuiteSubclass( SPGradientTest *& dst )
- {
- SPGradient *gr = static_cast<SPGradient *>(g_object_new(SP_TYPE_GRADIENT, NULL));
- if ( gr ) {
- UTEST_ASSERT(gr->gradientTransform.isIdentity());
- UTEST_ASSERT(gr->gradientTransform == Geom::identity());
- g_object_unref(gr);
-
- dst = new SPGradientTest();
- }
- }
-
- static SPGradientTest *createSuite()
- {
- return Inkscape::createSuiteAndDocument<SPGradientTest>( createSuiteSubclass );
- }
-
- static void destroySuite( SPGradientTest *suite ) { delete suite; }
-
-// -------------------------------------------------------------------------
-// -------------------------------------------------------------------------
-
- void testSetGradientTransform()
- {
- SPGradient *gr = static_cast<SPGradient *>(g_object_new(SP_TYPE_GRADIENT, NULL));
- SP_OBJECT(gr)->document = _doc;
-
- SP_OBJECT(gr)->setKeyValue( SP_ATTR_GRADIENTTRANSFORM, "translate(5, 8)");
- TS_ASSERT_EQUALS( gr->gradientTransform, Geom::Affine(Geom::Translate(5, 8)) );
-
- SP_OBJECT(gr)->setKeyValue( SP_ATTR_GRADIENTTRANSFORM, "");
- TS_ASSERT_EQUALS( gr->gradientTransform, Geom::identity() );
-
- SP_OBJECT(gr)->setKeyValue( SP_ATTR_GRADIENTTRANSFORM, "rotate(90)");
- TS_ASSERT_EQUALS( gr->gradientTransform, Geom::Affine(rotate_degrees(90)) );
-
- g_object_unref(gr);
- }
-
-
- void testWrite()
- {
- SPGradient *gr = static_cast<SPGradient *>(g_object_new(SP_TYPE_GRADIENT, NULL));
- SP_OBJECT(gr)->document = _doc;
-
- SP_OBJECT(gr)->setKeyValue( SP_ATTR_GRADIENTTRANSFORM, "matrix(0, 1, -1, 0, 0, 0)");
- Inkscape::XML::Document *xml_doc = _doc->getReprDoc();
- Inkscape::XML::Node *repr = xml_doc->createElement("svg:radialGradient");
- SP_OBJECT(gr)->updateRepr(repr, SP_OBJECT_WRITE_ALL);
- {
- gchar const *tr = repr->attribute("gradientTransform");
- Geom::Affine svd;
- bool const valid = sp_svg_transform_read(tr, &svd);
- TS_ASSERT( valid );
- TS_ASSERT_EQUALS( svd, Geom::Affine(rotate_degrees(90)) );
- }
-
- g_object_unref(gr);
- }
-
-
- void testGetG2dGetGs2dSetGs2d()
- {
- SPGradient *gr = static_cast<SPGradient *>(g_object_new(SP_TYPE_GRADIENT, NULL));
- SP_OBJECT(gr)->document = _doc;
- Geom::Affine const grXform(2, 1,
- 1, 3,
- 4, 6);
- gr->gradientTransform = grXform;
- Geom::Rect const unit_rect(Geom::Point(0, 0), Geom::Point(1, 1));
- {
- Geom::Affine const g2d(sp_gradient_get_g2d_matrix(gr, Geom::identity(), unit_rect));
- Geom::Affine const gs2d(sp_gradient_get_gs2d_matrix(gr, Geom::identity(), unit_rect));
- TS_ASSERT_EQUALS( g2d, Geom::identity() );
- TS_ASSERT( Geom::are_near(gs2d, gr->gradientTransform * g2d, 1e-12) );
-
- sp_gradient_set_gs2d_matrix(gr, Geom::identity(), unit_rect, gs2d);
- TS_ASSERT( Geom::are_near(gr->gradientTransform, grXform, 1e-12) );
- }
-
- gr->gradientTransform = grXform;
- Geom::Affine const funny(2, 3,
- 4, 5,
- 6, 7);
- {
- Geom::Affine const g2d(sp_gradient_get_g2d_matrix(gr, funny, unit_rect));
- Geom::Affine const gs2d(sp_gradient_get_gs2d_matrix(gr, funny, unit_rect));
- TS_ASSERT_EQUALS( g2d, funny );
- TS_ASSERT( Geom::are_near(gs2d, gr->gradientTransform * g2d, 1e-12) );
-
- sp_gradient_set_gs2d_matrix(gr, funny, unit_rect, gs2d);
- TS_ASSERT( Geom::are_near(gr->gradientTransform, grXform, 1e-12) );
- }
-
- gr->gradientTransform = grXform;
- Geom::Rect const larger_rect(Geom::Point(5, 6), Geom::Point(8, 10));
- {
- Geom::Affine const g2d(sp_gradient_get_g2d_matrix(gr, funny, larger_rect));
- Geom::Affine const gs2d(sp_gradient_get_gs2d_matrix(gr, funny, larger_rect));
- TS_ASSERT_EQUALS( g2d, Geom::Affine(3, 0,
- 0, 4,
- 5, 6) * funny );
- TS_ASSERT( Geom::are_near(gs2d, gr->gradientTransform * g2d, 1e-12) );
-
- sp_gradient_set_gs2d_matrix(gr, funny, larger_rect, gs2d);
- TS_ASSERT( Geom::are_near(gr->gradientTransform, grXform, 1e-12) );
-
- SP_OBJECT(gr)->setKeyValue( SP_ATTR_GRADIENTUNITS, "userSpaceOnUse");
- Geom::Affine const user_g2d(sp_gradient_get_g2d_matrix(gr, funny, larger_rect));
- Geom::Affine const user_gs2d(sp_gradient_get_gs2d_matrix(gr, funny, larger_rect));
- TS_ASSERT_EQUALS( user_g2d, funny );
- TS_ASSERT( Geom::are_near(user_gs2d, gr->gradientTransform * user_g2d, 1e-12) );
- }
- g_object_unref(gr);
- }
-
-};
-
-
-#endif // SEEN_SP_GRADIENT_TEST_H
-
-/*
- Local Variables:
- mode:c++
- c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
- indent-tabs-mode:nil
- fill-column:99
- End:
-*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/testfiles/src/object-test.cpp b/testfiles/src/object-test.cpp
new file mode 100644
index 000000000..565fc1b12
--- /dev/null
+++ b/testfiles/src/object-test.cpp
@@ -0,0 +1,205 @@
+/*
+ * Unit tests migrated from cxxtest
+ *
+ * Authors:
+ * Adrian Boguszewski
+ *
+ * Copyright (C) 2018 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <gtest/gtest.h>
+#include <doc-per-case-test.h>
+#include <src/object/sp-root.h>
+#include <src/object/sp-path.h>
+
+using namespace Inkscape;
+using namespace Inkscape::XML;
+
+class ObjectTest: public DocPerCaseTest {
+public:
+ ObjectTest() {
+ // Sample document
+ // svg:svg
+ // svg:defs
+ // svg:path
+ // svg:linearGradient
+ // svg:stop
+ // svg:filter
+ // svg:feGaussianBlur (feel free to implement for other filters)
+ // svg:clipPath
+ // svg:rect
+ // svg:g
+ // svg:use
+ // svg:circle
+ // svg:ellipse
+ // svg:text
+ // svg:polygon
+ // svg:polyline
+ // svg:image
+ // svg:line
+ char const *docString =
+ "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n"
+ "<!-- just a comment -->\n"
+ "<title id=\"title\">SVG test</title>\n"
+ "<defs>\n"
+ " <path id=\"P\" d=\"M -21,-4 -5,0 -18,12 -3,4 -4,21 0,5 12,17 4,2 21,3 5,-1 17,-12 2,-4 3,-21 -1,-5 -12,-18 -4,-3z\"/>\n"
+ " <linearGradient id=\"LG\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"0%\">\n"
+ " <stop offset=\"0%\" style=\"stop-color:#ffff00;stop-opacity:1\"/>\n"
+ " <stop offset=\"100%\" style=\"stop-color:red;stop-opacity:1\"/>\n"
+ " </linearGradient>\n"
+ " <clipPath id=\"clip\" clipPathUnits=\"userSpaceOnUse\">\n"
+ " <rect x=\"10\" y=\"10\" width=\"100\" height=\"100\"/>\n"
+ " </clipPath>\n"
+ " <filter style=\"color-interpolation-filters:sRGB\" id=\"filter\" x=\"-0.15\" width=\"1.34\" y=\"0\" height=\"1\">\n"
+ " <feGaussianBlur stdDeviation=\"4.26\"/>\n"
+ " </filter>\n"
+ "</defs>\n"
+
+ "<g id=\"G\" transform=\"skewX(10.5) translate(9,5)\">\n"
+ " <use id=\"U\" xlink:href=\"#P\" opacity=\"0.5\" fill=\"#1dace3\" transform=\"rotate(4)\"/>\n"
+ " <circle id=\"C\" cx=\"45.5\" cy=\"67\" r=\"23\" fill=\"#000\"/>\n"
+ " <ellipse id=\"E\" cx=\"200\" cy=\"70\" rx=\"85\" ry=\"55\" fill=\"url(#LG)\"/>\n"
+ " <text id=\"T\" fill=\"#fff\" style=\"font-size:45;font-family:Verdana\" x=\"150\" y=\"86\">TEST</text>\n"
+ " <polygon id=\"PG\" points=\"60,20 100,40 100,80 60,100 20,80 20,40\" clip-path=\"url(#clip)\" filter=\"url(#filter)\"/>\n"
+ " <polyline id=\"PL\" points=\"0,40 40,40 40,80 80,80 80,120 120,120 120,160\" style=\"fill:none;stroke:red;stroke-width:4\"/>\n"
+ " <image id=\"I\" xlink:href=\"data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjE4MCIgd2lkdGg9IjUwMCI+PHBhdGggZD0iTTAsNDAgNDAsNDAgNDAs" // this is one line
+ "ODAgODAsODAgODAsMTIwIDEyMCwxMjAgMTIwLDE2MCIgc3R5bGU9ImZpbGw6d2hpdGU7c3Ryb2tlOnJlZDtzdHJva2Utd2lkdGg6NCIvPjwvc3ZnPgo=\"/>\n"
+ " <line id=\"L\" x1=\"20\" y1=\"100\" x2=\"100\" y2=\"20\" stroke=\"black\" stroke-width=\"2\"/>\n"
+ "</g>\n"
+ "</svg>\n";
+ doc = SPDocument::createNewDocFromMem(docString, static_cast<int>(strlen(docString)), false);
+ }
+
+ ~ObjectTest() {
+ doc->doUnref();
+ }
+
+ SPDocument *doc;
+};
+
+TEST_F(ObjectTest, Clones) {
+ ASSERT_TRUE(doc != nullptr);
+ ASSERT_TRUE(doc->getRoot() != nullptr);
+
+ SPRoot *root = doc->getRoot();
+ ASSERT_TRUE(root->getRepr() != nullptr);
+ ASSERT_TRUE(root->hasChildren());
+
+ SPPath *path = dynamic_cast<SPPath *>(doc->getObjectById("P"));
+ ASSERT_TRUE(path != nullptr);
+
+ Node *node = path->getRepr();
+ ASSERT_TRUE(node != nullptr);
+
+ Document *xml_doc = node->document();
+ ASSERT_TRUE(xml_doc != nullptr);
+
+ Node *parent = node->parent();
+ ASSERT_TRUE(parent != nullptr);
+
+ const size_t num_clones = 1000;
+ std::string href = std::string("#") + std::string(path->getId());
+ std::vector<Node *> clones(num_clones, nullptr);
+
+ // Create num_clones clones of this path and stick them in the document
+ for (size_t i = 0; i < num_clones; ++i) {
+ Node *clone = xml_doc->createElement("svg:use");
+ Inkscape::GC::release(clone);
+ clone->setAttribute("xlink:href", href.c_str());
+ parent->addChild(clone, node);
+ clones[i] = clone;
+ }
+
+ // Remove those clones
+ for (size_t i = 0; i < num_clones; ++i) {
+ parent->removeChild(clones[i]);
+ }
+}
+
+TEST_F(ObjectTest, Grouping) {
+ ASSERT_TRUE(doc != nullptr);
+ ASSERT_TRUE(doc->getRoot() != nullptr);
+
+ SPRoot *root = doc->getRoot();
+ ASSERT_TRUE(root->getRepr() != nullptr);
+ ASSERT_TRUE(root->hasChildren());
+
+ SPGroup *group = dynamic_cast<SPGroup *>(doc->getObjectById("G"));
+
+ ASSERT_TRUE(group != nullptr);
+
+ Node *node = group->getRepr();
+ ASSERT_TRUE(node != nullptr);
+
+ Document *xml_doc = node->document();
+ ASSERT_TRUE(xml_doc != nullptr);
+
+ const size_t num_elements = 1000;
+
+ Node *new_group = xml_doc->createElement("svg:g");
+ Inkscape::GC::release(new_group);
+ node->addChild(new_group, nullptr);
+
+ std::vector<Node *> elements(num_elements, nullptr);
+
+ for (size_t i = 0; i < num_elements; ++i) {
+ Node *circle = xml_doc->createElement("svg:circle");
+ Inkscape::GC::release(circle);
+ circle->setAttribute("cx", "2048");
+ circle->setAttribute("cy", "1024");
+ circle->setAttribute("r", "1.5");
+ new_group->addChild(circle, nullptr);
+ elements[i] = circle;
+ }
+
+ SPGroup *n_group = dynamic_cast<SPGroup *>(group->get_child_by_repr(new_group));
+ ASSERT_TRUE(n_group != nullptr);
+
+ std::vector<SPItem*> ch;
+ sp_item_group_ungroup(n_group, ch, false);
+
+ // Remove those elements
+ for (size_t i = 0; i < num_elements; ++i) {
+ elements[i]->parent()->removeChild(elements[i]);
+ }
+
+}
+
+TEST_F(ObjectTest, Objects) {
+ ASSERT_TRUE(doc != nullptr);
+ ASSERT_TRUE(doc->getRoot() != nullptr);
+
+ SPRoot *root = doc->getRoot();
+ ASSERT_TRUE(root->getRepr() != nullptr);
+ ASSERT_TRUE(root->hasChildren());
+
+ SPPath *path = dynamic_cast<SPPath *>(doc->getObjectById("P"));
+ ASSERT_TRUE(path != nullptr);
+
+ // Test parent behavior
+ SPObject *child = root->firstChild();
+ ASSERT_TRUE(child != nullptr);
+
+ EXPECT_EQ(root, child->parent);
+ EXPECT_EQ(doc, child->document);
+ EXPECT_TRUE(root->isAncestorOf(child));
+
+ // Test list behavior
+ SPObject *next = child->getNext();
+ SPObject *prev = next;
+ EXPECT_EQ(child, next->getPrev());
+
+ prev = next;
+ next = next->getNext();
+ while (next != nullptr) {
+ // Walk the list
+ EXPECT_EQ(prev, next->getPrev());
+ prev = next;
+ next = next->getNext();
+ }
+
+ // Test hrefcount
+ EXPECT_TRUE(path->isReferenced());
+} \ No newline at end of file
diff --git a/testfiles/src/sp-gradient-test.cpp b/testfiles/src/sp-gradient-test.cpp
new file mode 100644
index 000000000..92c8e57ad
--- /dev/null
+++ b/testfiles/src/sp-gradient-test.cpp
@@ -0,0 +1,129 @@
+/*
+ * Unit tests migrated from cxxtest
+ *
+ * Authors:
+ * Adrian Boguszewski
+ *
+ * Copyright (C) 2018 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <gtest/gtest.h>
+#include <doc-per-case-test.h>
+#include <src/object/sp-gradient.h>
+#include <src/attributes.h>
+#include <2geom/transforms.h>
+#include <src/xml/node.h>
+#include <src/xml/simple-document.h>
+#include <src/svg/svg.h>
+
+using namespace Inkscape;
+using namespace Inkscape::XML;
+
+class SPGradientTest: public DocPerCaseTest {
+public:
+ SPGradientTest() {
+ DocPerCaseTest::SetUpTestCase();
+ gr = new SPGradient();
+ }
+
+ ~SPGradientTest() {
+ delete gr;
+ DocPerCaseTest::TearDownTestCase();
+ }
+
+ SPGradient *gr;
+};
+
+TEST_F(SPGradientTest, Init) {
+ ASSERT_TRUE(gr != nullptr);
+ EXPECT_TRUE(gr->gradientTransform.isIdentity());
+ EXPECT_EQ(Geom::identity(), gr->gradientTransform);
+}
+
+TEST_F(SPGradientTest, SetGradientTransform) {
+ SP_OBJECT(gr)->document = _doc;
+
+ SP_OBJECT(gr)->setKeyValue(SP_ATTR_GRADIENTTRANSFORM, "translate(5, 8)");
+ EXPECT_EQ(Geom::Affine(Geom::Translate(5.0, 8.0)), gr->gradientTransform);
+
+ SP_OBJECT(gr)->setKeyValue(SP_ATTR_GRADIENTTRANSFORM, "");
+ EXPECT_EQ(Geom::identity(), gr->gradientTransform);
+
+ SP_OBJECT(gr)->setKeyValue(SP_ATTR_GRADIENTTRANSFORM, "rotate(90)");
+ EXPECT_EQ(Geom::Affine(Geom::Rotate::from_degrees(90.0)), gr->gradientTransform);
+}
+
+TEST_F(SPGradientTest, Write) {
+ SP_OBJECT(gr)->document = _doc;
+
+ SP_OBJECT(gr)->setKeyValue(SP_ATTR_GRADIENTTRANSFORM, "matrix(0, 1, -1, 0, 0, 0)");
+ Document *xml_doc = _doc->getReprDoc();
+
+ ASSERT_TRUE(xml_doc != nullptr);
+
+ Node *repr = xml_doc->createElement("svg:radialGradient");
+ SP_OBJECT(gr)->updateRepr(xml_doc, repr, SP_OBJECT_WRITE_ALL);
+
+ gchar const *tr = repr->attribute("gradientTransform");
+ Geom::Affine svd;
+ bool const valid = sp_svg_transform_read(tr, &svd);
+
+ EXPECT_TRUE(valid);
+ EXPECT_EQ(Geom::Affine(Geom::Rotate::from_degrees(90.0)), svd);
+}
+
+TEST_F(SPGradientTest, GetG2dGetGs2dSetGs2) {
+ SP_OBJECT(gr)->document = _doc;
+
+ Geom::Affine grXform(2, 1,
+ 1, 3,
+ 4, 6);
+ gr->gradientTransform = grXform;
+
+ Geom::Rect unit_rect(Geom::Point(0, 0), Geom::Point(1, 1));
+ {
+ Geom::Affine g2d(sp_gradient_get_g2d_matrix(gr, Geom::identity(), unit_rect));
+ Geom::Affine gs2d(sp_gradient_get_gs2d_matrix(gr, Geom::identity(), unit_rect));
+ EXPECT_EQ(Geom::identity(), g2d);
+ EXPECT_TRUE(Geom::are_near(gs2d, gr->gradientTransform * g2d, 1e-12));
+
+ sp_gradient_set_gs2d_matrix(gr, Geom::identity(), unit_rect, gs2d);
+ EXPECT_TRUE(Geom::are_near(gr->gradientTransform, grXform, 1e-12));
+ }
+
+ gr->gradientTransform = grXform;
+ Geom::Affine funny(2, 3,
+ 4, 5,
+ 6, 7);
+ {
+ Geom::Affine g2d(sp_gradient_get_g2d_matrix(gr, funny, unit_rect));
+ Geom::Affine gs2d(sp_gradient_get_gs2d_matrix(gr, funny, unit_rect));
+ EXPECT_EQ(funny, g2d);
+ EXPECT_TRUE(Geom::are_near(gs2d, gr->gradientTransform * g2d, 1e-12));
+
+ sp_gradient_set_gs2d_matrix(gr, funny, unit_rect, gs2d);
+ EXPECT_TRUE(Geom::are_near(gr->gradientTransform, grXform, 1e-12));
+ }
+
+ gr->gradientTransform = grXform;
+ Geom::Rect larger_rect(Geom::Point(5, 6), Geom::Point(8, 10));
+ {
+ Geom::Affine g2d(sp_gradient_get_g2d_matrix(gr, funny, larger_rect));
+ Geom::Affine gs2d(sp_gradient_get_gs2d_matrix(gr, funny, larger_rect));
+ EXPECT_EQ(Geom::Affine(3, 0,
+ 0, 4,
+ 5, 6) * funny, g2d );
+ EXPECT_TRUE(Geom::are_near(gs2d, gr->gradientTransform * g2d, 1e-12));
+
+ sp_gradient_set_gs2d_matrix(gr, funny, larger_rect, gs2d);
+ EXPECT_TRUE(Geom::are_near(gr->gradientTransform, grXform, 1e-12));
+
+ SP_OBJECT(gr)->setKeyValue( SP_ATTR_GRADIENTUNITS, "userSpaceOnUse");
+ Geom::Affine user_g2d(sp_gradient_get_g2d_matrix(gr, funny, larger_rect));
+ Geom::Affine user_gs2d(sp_gradient_get_gs2d_matrix(gr, funny, larger_rect));
+ EXPECT_EQ(funny, user_g2d);
+ EXPECT_TRUE(Geom::are_near(user_gs2d, gr->gradientTransform * user_g2d, 1e-12));
+ }
+}