summaryrefslogtreecommitdiffstats
path: root/testfiles/src/object-set-test.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--testfiles/src/object-set-test.cpp706
1 files changed, 706 insertions, 0 deletions
diff --git a/testfiles/src/object-set-test.cpp b/testfiles/src/object-set-test.cpp
new file mode 100644
index 0000000..2112937
--- /dev/null
+++ b/testfiles/src/object-set-test.cpp
@@ -0,0 +1,706 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Multiindex container for selection
+ *
+ * Authors:
+ * Adrian Boguszewski
+ *
+ * Copyright (C) 2016 Adrian Boguszewski
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+#include <gtest/gtest.h>
+#include <doc-per-case-test.h>
+#include <src/object/sp-factory.h>
+#include <src/object/sp-marker.h>
+#include <src/object/sp-rect.h>
+#include <src/object/sp-path.h>
+#include <src/object/sp-use.h>
+#include <src/object/sp-root.h>
+#include <src/object/object-set.h>
+#include <xml/node.h>
+#include <src/xml/text-node.h>
+#include <src/xml/simple-document.h>
+//#include <unistd.h>
+#include <2geom/transforms.h>
+using namespace Inkscape;
+using namespace Inkscape::XML;
+
+class ObjectSetTest: public DocPerCaseTest {
+public:
+ ObjectSetTest() {
+ auto *const _doc = this->_doc.get();
+ N = _doc->getRoot()->children.size();
+
+ A = new SPObject();
+ B = new SPObject();
+ C = new SPObject();
+ D = new SPObject();
+ E = new SPObject();
+ F = new SPObject();
+ G = new SPObject();
+ H = new SPObject();
+ X = new SPObject();
+ set = new ObjectSet(_doc);
+ set2 = new ObjectSet(_doc);
+ auto sd = _doc->getReprDoc();
+ auto xt = new TextNode(Util::share_string("x"), sd);
+ auto ht = new TextNode(Util::share_string("h"), sd);
+ auto gt = new TextNode(Util::share_string("g"), sd);
+ auto ft = new TextNode(Util::share_string("f"), sd);
+ auto et = new TextNode(Util::share_string("e"), sd);
+ auto dt = new TextNode(Util::share_string("d"), sd);
+ auto ct = new TextNode(Util::share_string("c"), sd);
+ auto bt = new TextNode(Util::share_string("b"), sd);
+ auto at = new TextNode(Util::share_string("a"), sd);
+ X->invoke_build(_doc, xt, 0);
+ H->invoke_build(_doc, ht, 0);
+ G->invoke_build(_doc, gt, 0);
+ F->invoke_build(_doc, ft, 0);
+ E->invoke_build(_doc, et, 0);
+ D->invoke_build(_doc, dt, 0);
+ C->invoke_build(_doc, ct, 0);
+ B->invoke_build(_doc, bt, 0);
+ A->invoke_build(_doc, at, 0);
+
+ //create 3 rects at root of document
+ Inkscape::XML::Node *repr = _doc->getReprDoc()->createElement("svg:rect");
+ _doc->getRoot()->appendChild(repr);
+ r1.reset(dynamic_cast<SPRect*>(_doc->getObjectByRepr(repr)));
+ repr = _doc->getReprDoc()->createElement("svg:rect");
+ _doc->getRoot()->appendChild(repr);
+ r2.reset(dynamic_cast<SPRect*>(_doc->getObjectByRepr(repr)));
+ repr = _doc->getReprDoc()->createElement("svg:rect");
+ _doc->getRoot()->appendChild(repr);
+ r3.reset(dynamic_cast<SPRect*>(_doc->getObjectByRepr(repr)));
+ EXPECT_EQ(N + 3, _doc->getRoot()->children.size());// defs, namedview, and those three rects.
+ r1->x = r1->y = r2->x = r2->y = r3->x = r3->y = 0;
+ r1->width = r1->height = r2->width = r2->height = r3->width = r3->height = 10;
+ r1->set_shape();
+ r2->set_shape();
+ r3->set_shape();
+
+ }
+ ~ObjectSetTest() override {
+ delete set;
+ delete set2;
+ delete X;
+ delete H;
+ delete G;
+ delete F;
+ delete E;
+ delete D;
+ delete C;
+ delete B;
+ delete A;
+ }
+ SPObject* A;
+ SPObject* B;
+ SPObject* C;
+ SPObject* D;
+ SPObject* E;
+ SPObject* F;
+ SPObject* G;
+ SPObject* H;
+ SPObject* X;
+ std::unique_ptr<SPRect> r1;
+ std::unique_ptr<SPRect> r2;
+ std::unique_ptr<SPRect> r3;
+ ObjectSet* set;
+ ObjectSet* set2;
+ int N; //!< Number of root children in default document
+};
+
+#define SP_IS_CLONE(obj) (dynamic_cast<const SPUse*>(obj) != NULL)
+
+bool containsClone(ObjectSet* set) {
+ for (auto it : set->items()) {
+ if (SP_IS_CLONE(it)) {
+ return true;
+ }
+ if (SP_IS_GROUP(it)) {
+ ObjectSet tmp_set(set->document());
+ std::vector<SPObject*> c = it->childList(false);
+ tmp_set.setList(c);
+ if (containsClone(&tmp_set)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+TEST_F(ObjectSetTest, Basics) {
+ EXPECT_EQ(0, set->size());
+ set->add(A);
+ EXPECT_EQ(1, set->size());
+ EXPECT_TRUE(set->includes(A));
+ set->add(B);
+ set->add(C);
+ EXPECT_EQ(3, set->size());
+ EXPECT_TRUE(set->includes(B));
+ EXPECT_TRUE(set->includes(C));
+ EXPECT_FALSE(set->includes(D));
+ EXPECT_FALSE(set->includes(X));
+ EXPECT_FALSE(set->includes(nullptr));
+ set->remove(A);
+ EXPECT_EQ(2, set->size());
+ EXPECT_FALSE(set->includes(A));
+ set->clear();
+ EXPECT_EQ(0, set->size());
+ bool resultNull = set->add((SPObject*)nullptr);
+ EXPECT_FALSE(resultNull);
+ EXPECT_EQ(0, set->size());
+ bool resultNull2 = set->remove(nullptr);
+ EXPECT_FALSE(resultNull2);
+}
+
+TEST_F(ObjectSetTest, Advanced) {
+ set->add(A);
+ set->add(B);
+ set->add(C);
+ EXPECT_TRUE(set->includes(C));
+ set->toggle(C);
+ EXPECT_EQ(2, set->size());
+ EXPECT_FALSE(set->includes(C));
+ set->toggle(D);
+ EXPECT_EQ(3, set->size());
+ EXPECT_TRUE(set->includes(D));
+ set->toggle(D);
+ EXPECT_EQ(2, set->size());
+ EXPECT_FALSE(set->includes(D));
+ EXPECT_EQ(nullptr, set->single());
+ set->set(X);
+ EXPECT_EQ(1, set->size());
+ EXPECT_TRUE(set->includes(X));
+ EXPECT_EQ(X, set->single());
+ EXPECT_FALSE(set->isEmpty());
+ set->clear();
+ EXPECT_TRUE(set->isEmpty());
+ std::vector<SPObject*> list1 {A, B, C, D};
+ std::vector<SPObject*> list2 {E, F};
+ set->addList(list1);
+ EXPECT_EQ(4, set->size());
+ set->addList(list2);
+ EXPECT_EQ(6, set->size());
+ EXPECT_TRUE(set->includes(A));
+ EXPECT_TRUE(set->includes(B));
+ EXPECT_TRUE(set->includes(C));
+ EXPECT_TRUE(set->includes(D));
+ EXPECT_TRUE(set->includes(E));
+ EXPECT_TRUE(set->includes(F));
+ set->setList(list2);
+ EXPECT_EQ(2, set->size());
+ EXPECT_TRUE(set->includes(E));
+ EXPECT_TRUE(set->includes(F));
+}
+
+TEST_F(ObjectSetTest, Items) {
+ // cannot test smallestItem and largestItem functions due to too many dependencies
+ // uncomment if the problem is fixed
+
+ SPRect* rect10x100 = &*r1;
+ rect10x100->x = rect10x100->x = 0;
+ rect10x100->width = 10;
+ rect10x100->height = 100;
+ rect10x100->set_shape();
+
+ SPRect* rect20x40 = &*r2;
+ rect20x40->x = rect20x40->x = 0;
+ rect20x40->width = 20;
+ rect20x40->height = 40;
+ rect20x40->set_shape();
+
+ SPRect* rect30x30 = &*r3;
+ rect30x30->x = rect30x30->x = 0;
+ rect30x30->width = 30;
+ rect30x30->height = 30;
+ rect30x30->set_shape();
+
+
+ set->add(rect10x100);
+ EXPECT_EQ(rect10x100, set->singleItem());
+ EXPECT_EQ(rect10x100->getRepr(), set->singleRepr());
+ set->add(rect20x40);
+ EXPECT_EQ(nullptr, set->singleItem());
+ EXPECT_EQ(nullptr, set->singleRepr());
+ set->add(rect30x30);
+ EXPECT_EQ(3, set->size());
+ EXPECT_EQ(rect10x100, set->smallestItem(ObjectSet::CompareSize::HORIZONTAL));
+ EXPECT_EQ(rect30x30, set->smallestItem(ObjectSet::CompareSize::VERTICAL));
+ EXPECT_EQ(rect20x40, set->smallestItem(ObjectSet::CompareSize::AREA));
+ EXPECT_EQ(rect30x30, set->largestItem(ObjectSet::CompareSize::HORIZONTAL));
+ EXPECT_EQ(rect10x100, set->largestItem(ObjectSet::CompareSize::VERTICAL));
+ EXPECT_EQ(rect10x100, set->largestItem(ObjectSet::CompareSize::AREA));
+}
+
+TEST_F(ObjectSetTest, Ranges) {
+ std::vector<SPObject*> objs {A, D, B, E, C, F};
+ set->add(objs.begin() + 1, objs.end() - 1);
+ EXPECT_EQ(4, set->size());
+ auto it = set->objects().begin();
+ EXPECT_EQ(D, *it++);
+ EXPECT_EQ(B, *it++);
+ EXPECT_EQ(E, *it++);
+ EXPECT_EQ(C, *it++);
+ EXPECT_EQ(set->objects().end(), it);
+ SPObject* rect1 = SPFactory::createObject("svg:rect");
+ SPObject* rect2 = SPFactory::createObject("svg:rect");
+ SPObject* rect3 = SPFactory::createObject("svg:rect");
+ set->add(rect1);
+ set->add(rect2);
+ set->add(rect3);
+ EXPECT_EQ(7, set->size());
+ auto xmlNode = set->xmlNodes().begin();
+ EXPECT_EQ(3, boost::distance(set->xmlNodes()));
+ EXPECT_EQ(rect1->getRepr(), *xmlNode++);
+ EXPECT_EQ(rect2->getRepr(), *xmlNode++);
+ EXPECT_EQ(rect3->getRepr(), *xmlNode++);
+ EXPECT_EQ(set->xmlNodes().end(), xmlNode);
+ auto item = set->items().begin();
+ EXPECT_EQ(3, boost::distance(set->items()));
+ EXPECT_EQ(rect1, *item++);
+ EXPECT_EQ(rect2, *item++);
+ EXPECT_EQ(rect3, *item++);
+ EXPECT_EQ(set->items().end(), item);
+}
+
+TEST_F(ObjectSetTest, Autoremoving) {
+ set->add(A);
+ EXPECT_TRUE(set->includes(A));
+ EXPECT_EQ(1, set->size());
+ A->releaseReferences();
+ EXPECT_EQ(0, set->size());
+}
+
+TEST_F(ObjectSetTest, BasicDescendants) {
+ A->attach(B, nullptr);
+ B->attach(C, nullptr);
+ A->attach(D, nullptr);
+ bool resultB = set->add(B);
+ bool resultB2 = set->add(B);
+ EXPECT_TRUE(resultB);
+ EXPECT_FALSE(resultB2);
+ EXPECT_TRUE(set->includes(B));
+ bool resultC = set->add(C);
+ EXPECT_FALSE(resultC);
+ EXPECT_FALSE(set->includes(C));
+ EXPECT_EQ(1, set->size());
+ bool resultA = set->add(A);
+ EXPECT_TRUE(resultA);
+ EXPECT_EQ(1, set->size());
+ EXPECT_TRUE(set->includes(A));
+ EXPECT_FALSE(set->includes(B));
+}
+
+TEST_F(ObjectSetTest, AdvancedDescendants) {
+ A->attach(B, nullptr);
+ A->attach(C, nullptr);
+ A->attach(X, nullptr);
+ B->attach(D, nullptr);
+ B->attach(E, nullptr);
+ C->attach(F, nullptr);
+ C->attach(G, nullptr);
+ C->attach(H, nullptr);
+ set->add(A);
+ bool resultF = set->remove(F);
+ EXPECT_TRUE(resultF);
+ EXPECT_EQ(4, set->size());
+ EXPECT_FALSE(set->includes(F));
+ EXPECT_TRUE(set->includes(B));
+ EXPECT_TRUE(set->includes(G));
+ EXPECT_TRUE(set->includes(H));
+ EXPECT_TRUE(set->includes(X));
+ bool resultF2 = set->add(F);
+ EXPECT_TRUE(resultF2);
+ EXPECT_EQ(5, set->size());
+ EXPECT_TRUE(set->includes(F));
+}
+
+TEST_F(ObjectSetTest, Removing) {
+ A->attach(B, nullptr);
+ A->attach(C, nullptr);
+ A->attach(X, nullptr);
+ B->attach(D, nullptr);
+ B->attach(E, nullptr);
+ C->attach(F, nullptr);
+ C->attach(G, nullptr);
+ C->attach(H, nullptr);
+ bool removeH = set->remove(H);
+ EXPECT_FALSE(removeH);
+ set->add(A);
+ bool removeX = set->remove(X);
+ EXPECT_TRUE(removeX);
+ EXPECT_EQ(2, set->size());
+ EXPECT_TRUE(set->includes(B));
+ EXPECT_TRUE(set->includes(C));
+ EXPECT_FALSE(set->includes(X));
+ EXPECT_FALSE(set->includes(A));
+ bool removeX2 = set->remove(X);
+ EXPECT_FALSE(removeX2);
+ EXPECT_EQ(2, set->size());
+ bool removeA = set->remove(A);
+ EXPECT_FALSE(removeA);
+ EXPECT_EQ(2, set->size());
+ bool removeC = set->remove(C);
+ EXPECT_TRUE(removeC);
+ EXPECT_EQ(1, set->size());
+ EXPECT_TRUE(set->includes(B));
+ EXPECT_FALSE(set->includes(C));
+}
+
+TEST_F(ObjectSetTest, TwoSets) {
+ A->attach(B, nullptr);
+ A->attach(C, nullptr);
+ set->add(A);
+ set2->add(A);
+ EXPECT_EQ(1, set->size());
+ EXPECT_EQ(1, set2->size());
+ set->remove(B);
+ EXPECT_EQ(1, set->size());
+ EXPECT_TRUE(set->includes(C));
+ EXPECT_EQ(1, set2->size());
+ EXPECT_TRUE(set2->includes(A));
+ C->releaseReferences();
+ EXPECT_EQ(0, set->size());
+ EXPECT_EQ(1, set2->size());
+ EXPECT_TRUE(set2->includes(A));
+}
+
+TEST_F(ObjectSetTest, SetRemoving) {
+ ObjectSet *objectSet = new ObjectSet(_doc.get());
+ A->attach(B, nullptr);
+ objectSet->add(A);
+ objectSet->add(C);
+ EXPECT_EQ(2, objectSet->size());
+ delete objectSet;
+ EXPECT_STREQ(nullptr, A->getId());
+ EXPECT_STREQ(nullptr, C->getId());
+}
+
+TEST_F(ObjectSetTest, Delete) {
+ //we cannot use the same item as in other tests since it will be freed at the test destructor
+
+ EXPECT_EQ(_doc->getRoot(), r1->parent);
+ set->add(r1.get());
+ set->deleteItems();
+ r1.release();
+ EXPECT_EQ(0, set->size());
+ //EXPECT_EQ(nullptr, r1->parent);
+}
+
+TEST_F(ObjectSetTest, Ops) {
+ set->add(r1.get());
+ set->add(r2.get());
+ set->add(r3.get());
+ set->duplicate();
+ EXPECT_EQ(N + 6, _doc->getRoot()->children.size());// defs, namedview, and those 3x2 rects.
+ EXPECT_EQ(3, set->size());
+ EXPECT_FALSE(set->includes(r1.get()));
+ set->deleteItems();
+ EXPECT_TRUE(set->isEmpty());
+ set->add(r1.get());
+ set->add(r2.get());
+ set->add(r3.get());
+ set->group();//r1-3 are now invalid (grouping makes copies)
+ r1.release();
+ r2.release();
+ r3.release();
+ EXPECT_EQ(N + 1, _doc->getRoot()->children.size());
+ EXPECT_EQ(1, set->size());
+ set->ungroup();
+ EXPECT_EQ(N + 3, _doc->getRoot()->children.size());
+ EXPECT_EQ(3, set->size());
+ /* Uncomment this when toNextLayer is made desktop-independent
+ set->group();
+ set2->add(set->singleItem()->childList(false)[0]);
+ EXPECT_EQ(3, set->singleItem()->children.size());
+ EXPECT_EQ(4, _doc->getRoot()->children.size());
+ set2->popFromGroup();
+ EXPECT_EQ(2, set->singleItem()->children.size());
+ EXPECT_EQ(5, _doc->getRoot()->children.size());
+ set->ungroup();
+ set->add(set2->singleItem());
+ */
+ set->clone();
+ EXPECT_EQ(N + 6, _doc->getRoot()->children.size());
+ EXPECT_EQ(3, set->size());
+ EXPECT_NE(nullptr,dynamic_cast<SPUse*>(*(set->items().begin())));
+ EXPECT_EQ(nullptr,dynamic_cast<SPRect*>(*(set->items().begin())));
+ set->unlink();
+ EXPECT_EQ(N + 6, _doc->getRoot()->children.size());
+ EXPECT_EQ(3, set->size());
+ EXPECT_EQ(nullptr,dynamic_cast<SPUse*>(*(set->items().begin())));
+ EXPECT_NE(nullptr,dynamic_cast<SPRect*>(*(set->items().begin())));
+ set->clone(); //creates 3 clones
+ set->clone(); //creates 3 clones of clones
+ EXPECT_EQ(N + 12, _doc->getRoot()->children.size());
+ EXPECT_EQ(3, set->size());
+ EXPECT_NE(nullptr,dynamic_cast<SPUse*>( ((SPUse*)(*(set->items().begin())))->get_original()));//"original is a Use"
+ set->unlink(); //clone of clone of rect -> rect
+ EXPECT_EQ(nullptr,dynamic_cast<SPUse*>(*(set->items().begin())));
+ EXPECT_NE(nullptr,dynamic_cast<SPRect*>(*(set->items().begin())));
+ set->clone();
+ set->set(*(set->items().begin()));
+ set->cloneOriginal();//get clone original
+ EXPECT_EQ(N + 15, _doc->getRoot()->children.size());
+ EXPECT_EQ(1, set->size());
+ EXPECT_NE(nullptr,dynamic_cast<SPRect*>(*(set->items().begin())));
+ //let's stop here.
+ // TODO: write a hundred more tests to check clone (non-)displacement when grouping, ungrouping and unlinking...
+ TearDownTestCase();
+ SetUpTestCase();
+}
+
+TEST_F(ObjectSetTest, unlinkRecursiveBasic) {
+ // This is the same as the test (ObjectSetTest, Ops), but with unlinkRecursive instead of unlink.
+ set->set(r1.get());
+ set->add(r2.get());
+ set->add(r3.get());
+ EXPECT_FALSE(containsClone(set));
+ set->duplicate();
+ EXPECT_FALSE(containsClone(set));
+ EXPECT_EQ(N + 6, _doc->getRoot()->children.size());// defs, namedview, and those 3x2 rects.
+ EXPECT_EQ(3, set->size());
+ EXPECT_FALSE(set->includes(r1.get()));
+ set->deleteItems();
+ EXPECT_FALSE(containsClone(set));
+ EXPECT_TRUE(set->isEmpty());
+ set->add(r1.get());
+ set->add(r2.get());
+ set->add(r3.get());
+ EXPECT_FALSE(containsClone(set));
+ set->group();//r1-3 are now invalid (grouping makes copies)
+ r1.release();
+ r2.release();
+ r3.release();
+ EXPECT_FALSE(containsClone(set));
+ EXPECT_EQ(N + 1, _doc->getRoot()->children.size());
+ EXPECT_EQ(1, set->size());
+ set->ungroup();
+ EXPECT_FALSE(containsClone(set));
+ EXPECT_EQ(N + 3, _doc->getRoot()->children.size());
+ EXPECT_EQ(3, set->size());
+ /* Uncomment this when toNextLayer is made desktop-independent
+ set->group();
+ set2->add(set->singleItem()->childList(false)[0]);
+ EXPECT_EQ(3, set->singleItem()->children.size());
+ EXPECT_EQ(4, _doc->getRoot()->children.size());
+ set2->popFromGroup();
+ EXPECT_EQ(2, set->singleItem()->children.size());
+ EXPECT_EQ(5, _doc->getRoot()->children.size());
+ set->ungroup();
+ set->add(set2->singleItem());
+ */
+ set->clone();
+ EXPECT_TRUE(containsClone(set));
+ EXPECT_EQ(N + 6, _doc->getRoot()->children.size());
+ EXPECT_EQ(3, set->size());
+ EXPECT_NE(nullptr, dynamic_cast<SPUse*>(*(set->items().begin())));
+ EXPECT_EQ(nullptr, dynamic_cast<SPRect*>(*(set->items().begin())));
+ set->unlinkRecursive(false, true);
+ EXPECT_FALSE(containsClone(set));
+ EXPECT_EQ(N + 6, _doc->getRoot()->children.size());
+ EXPECT_EQ(3, set->size());
+ EXPECT_EQ(nullptr, dynamic_cast<SPUse*>(*(set->items().begin())));
+ EXPECT_NE(nullptr, dynamic_cast<SPRect*>(*(set->items().begin())));
+ set->clone(); //creates 3 clones
+ EXPECT_TRUE(containsClone(set));
+ set->clone(); //creates 3 clones of clones
+ EXPECT_TRUE(containsClone(set));
+ EXPECT_EQ(N + 12, _doc->getRoot()->children.size());
+ EXPECT_EQ(3, set->size());
+ EXPECT_NE(nullptr, dynamic_cast<SPUse*>( ((SPUse*)(*(set->items().begin())))->get_original()));//"original is a Use"
+ set->unlinkRecursive(false, true); //clone of clone of rect -> rect
+ EXPECT_FALSE(containsClone(set));
+ EXPECT_EQ(nullptr, dynamic_cast<SPUse*>(*(set->items().begin())));
+ EXPECT_NE(nullptr, dynamic_cast<SPRect*>(*(set->items().begin())));
+ set->clone();
+ EXPECT_TRUE(containsClone(set));
+ set->set(*(set->items().begin()));
+ set->cloneOriginal();//get clone original
+ EXPECT_EQ(N + 15, _doc->getRoot()->children.size());
+ EXPECT_EQ(1, set->size());
+ EXPECT_NE(nullptr, dynamic_cast<SPRect*>(*(set->items().begin())));
+ TearDownTestCase();
+ SetUpTestCase();
+}
+
+TEST_F(ObjectSetTest, unlinkRecursiveAdvanced) {
+ set->set(r1.get());
+ set->add(r2.get());
+ set->add(r3.get());
+ set->group();//r1-3 are now invalid (grouping makes copies)
+ r1.release();
+ r2.release();
+ r3.release();
+ EXPECT_FALSE(containsClone(set));
+ EXPECT_EQ(1, set->size());
+ SPItem* original = set->singleItem();
+ set->clone();
+ EXPECT_TRUE(containsClone(set));
+ EXPECT_EQ(1, set->size());
+ set->add(original);
+ EXPECT_TRUE(containsClone(set));
+ EXPECT_EQ(2, set->size());
+ set->group();
+ EXPECT_TRUE(containsClone(set));
+ EXPECT_EQ(1, set->size());
+ original = set->singleItem();
+ set->clone();
+ EXPECT_TRUE(containsClone(set));
+ EXPECT_EQ(1, set->size());
+ set->add(original);
+ EXPECT_TRUE(containsClone(set));
+ EXPECT_EQ(2, set->size());
+ set->group();
+ EXPECT_TRUE(containsClone(set));
+ EXPECT_EQ(1, set->size());
+ original = set->singleItem();
+ set->clone();
+ EXPECT_TRUE(containsClone(set));
+ EXPECT_EQ(1, set->size());
+ set->add(original);
+ EXPECT_TRUE(containsClone(set));
+ EXPECT_EQ(2, set->size());
+ set->unlinkRecursive(false, true);
+ EXPECT_FALSE(containsClone(set));
+ EXPECT_EQ(2, set->size());
+
+ TearDownTestCase();
+ SetUpTestCase();
+}
+
+TEST_F(ObjectSetTest, ZOrder) {
+ //sp_object_compare_position_bool == true iff "r1<r2" iff r1 is "before" r2 in the file, ie r1 is lower than r2
+ EXPECT_TRUE(sp_object_compare_position_bool(r1.get(),r2.get()));
+ EXPECT_TRUE(sp_object_compare_position_bool(r2.get(),r3.get()));
+ EXPECT_TRUE(sp_object_compare_position_bool(r1.get(),r3.get()));
+ EXPECT_FALSE(sp_object_compare_position_bool(r2.get(),r1.get()));
+ EXPECT_FALSE(sp_object_compare_position_bool(r3.get(),r1.get()));
+ EXPECT_FALSE(sp_object_compare_position_bool(r3.get(),r2.get()));
+ //1 2 3
+ set->set(r2.get());
+ set->raise();
+ //1 3 2
+ EXPECT_TRUE(sp_object_compare_position_bool(r1.get(),r3.get()));
+ EXPECT_TRUE(sp_object_compare_position_bool(r3.get(),r2.get()));//!
+ set->set(r3.get());
+ set->lower();
+ //3 1 2
+ EXPECT_TRUE(sp_object_compare_position_bool(r3.get(),r1.get()));
+ EXPECT_TRUE(sp_object_compare_position_bool(r1.get(),r2.get()));
+ set->raiseToTop();
+ //1 2 3
+ EXPECT_TRUE(sp_object_compare_position_bool(r1.get(),r2.get()));
+ EXPECT_TRUE(sp_object_compare_position_bool(r2.get(),r3.get()));
+ set->lowerToBottom();
+ //3 1 2
+ EXPECT_TRUE(sp_object_compare_position_bool(r3.get(),r1.get()));
+ EXPECT_TRUE(sp_object_compare_position_bool(r1.get(),r2.get()));
+}
+
+TEST_F(ObjectSetTest, Combine) {
+ set->add(r1.get());
+ set->add(r2.get());
+ set->combine();
+ r1.release();
+ r2.release();
+ EXPECT_EQ(1, set->size());
+ EXPECT_EQ(N + 2, _doc->getRoot()->children.size());
+ set->breakApart();
+ EXPECT_EQ(2, set->size());
+ EXPECT_EQ(N + 3, _doc->getRoot()->children.size());
+ set->deleteItems();
+ set->set(r3.get());
+ set->toCurves();
+ r3.release();
+ auto x = set->singleItem();
+ EXPECT_NE(nullptr,dynamic_cast<SPPath*>(x));
+ EXPECT_EQ(nullptr,dynamic_cast<SPRect*>(x));
+ set->deleteItems();
+}
+
+TEST_F(ObjectSetTest, Moves) {
+ set->add(r1.get());
+ set->moveRelative(15,15);
+ EXPECT_EQ(15,r1->x.value);
+ Geom::Point p(20,20);
+ Geom::Scale s(2);
+ set->setScaleRelative(p,s);
+ EXPECT_EQ(10,r1->x.value);
+ EXPECT_EQ(20,r1->width.value);
+ set->toCurves();
+ r1.release();
+ auto x = set->singleItem();
+ EXPECT_EQ(20,(*(x->documentVisualBounds()))[0].extent());
+ set->rotate90(true);
+ set->rotate90(true);
+ EXPECT_EQ(20,(*(x->documentVisualBounds()))[0].extent());
+ set->deleteItems();
+}
+
+TEST_F(ObjectSetTest, toMarker) {
+ r1->x = 12;
+ r1->y = 34;
+ r1->width = 56;
+ r1->height = 78;
+ r1->set_shape();
+ r1->updateRepr();
+
+ r2->x = 6;
+ r2->y = 7;
+ r2->width = 8;
+ r2->height = 9;
+ r2->set_shape();
+ r2->updateRepr();
+
+ r3->x = 10;
+ r3->y = 10;
+ r3->width = 10;
+ r3->height = 10;
+ r3->set_shape();
+ r3->updateRepr();
+
+ // add rects to set in different order than they appear in the document,
+ // to verify selection order independence.
+ set->set(r1.get());
+ set->add(r3.get());
+ set->add(r2.get());
+ set->toMarker();
+
+ // original items got deleted
+ r1.release();
+ r2.release();
+ r3.release();
+
+ auto markers = _doc->getObjectsByElement("marker");
+ ASSERT_EQ(markers.size(), 1);
+
+ auto marker = dynamic_cast<SPMarker *>(markers[0]);
+ ASSERT_NE(marker, nullptr);
+
+ EXPECT_FLOAT_EQ(marker->refX.computed, 31);
+ EXPECT_FLOAT_EQ(marker->refY.computed, 52.5);
+ EXPECT_FLOAT_EQ(marker->markerWidth.computed, 62);
+ EXPECT_FLOAT_EQ(marker->markerHeight.computed, 105);
+
+ auto markerchildren = marker->childList(false);
+ ASSERT_EQ(markerchildren.size(), 3);
+
+ auto *markerrect1 = dynamic_cast<SPRect *>(markerchildren[0]);
+ auto *markerrect2 = dynamic_cast<SPRect *>(markerchildren[1]);
+
+ ASSERT_NE(markerrect1, nullptr);
+ ASSERT_NE(markerrect2, nullptr);
+
+ EXPECT_FLOAT_EQ(markerrect1->x.value, 6);
+ EXPECT_FLOAT_EQ(markerrect1->y.value, 27);
+ EXPECT_FLOAT_EQ(markerrect1->width.value, 56);
+ EXPECT_FLOAT_EQ(markerrect1->height.value, 78);
+
+ EXPECT_FLOAT_EQ(markerrect2->x.value, 0);
+ EXPECT_FLOAT_EQ(markerrect2->y.value, 0);
+ EXPECT_FLOAT_EQ(markerrect2->width.value, 8);
+ EXPECT_FLOAT_EQ(markerrect2->height.value, 9);
+}