summaryrefslogtreecommitdiffstats
path: root/share/extensions/tests/test_inkex_elements_base.py
diff options
context:
space:
mode:
Diffstat (limited to 'share/extensions/tests/test_inkex_elements_base.py')
-rw-r--r--share/extensions/tests/test_inkex_elements_base.py322
1 files changed, 322 insertions, 0 deletions
diff --git a/share/extensions/tests/test_inkex_elements_base.py b/share/extensions/tests/test_inkex_elements_base.py
new file mode 100644
index 0000000..02ecd72
--- /dev/null
+++ b/share/extensions/tests/test_inkex_elements_base.py
@@ -0,0 +1,322 @@
+#!/usr/bin/env python
+# coding=utf-8
+"""
+Test the element API base classes and basic functionality
+"""
+from lxml import etree
+
+from inkex.elements import (
+ load_svg, ShapeElement, Group, Rectangle, Tspan, TextElement, Line,
+)
+from inkex.transforms import Transform
+from inkex.styles import Style
+from inkex.utils import FragmentError
+from inkex.tester import TestCase
+from inkex.tester.svg import svg_file
+
+class FakeShape(ShapeElement): # pylint: disable=abstract-method
+ """A protend shape"""
+ tag_name = 'fake'
+
+class SvgTestCase(TestCase):
+ """Test SVG"""
+ source_file = 'complextransform.test.svg'
+
+ def setUp(self):
+ super(SvgTestCase, self).setUp()
+ self.svg = svg_file(self.data_file('svg', self.source_file))
+
+class OverridenElementTestCase(SvgTestCase):
+ """Test element overriding functionality"""
+ def test_tag_names(self):
+ """
+ Test tag names for custom and unknown tags
+ """
+ doc = load_svg("""
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:x="http://x.com/x">
+ <g id="good"></g>
+ <badsvg id="bad">Unknown SVG tag</badsvg>
+ <x:othertag id="ugly"></x:othertag>
+</svg>""")
+ svg = doc.getroot()
+
+ good = svg.getElementById("good")
+ self.assertEqual(good.TAG, "g")
+ bad = svg.getElementById("bad")
+ self.assertEqual(bad.TAG, "badsvg")
+ ugly = svg.getElementById("ugly")
+ self.assertEqual(ugly.TAG, "othertag")
+
+ def test_reference_count(self):
+ """
+ Test inkex.element.BaseElement-derived object type is preserved on adding to group
+
+ See https://gitlab.com/inkscape/extensions/-/issues/81 for details
+ """
+ grp = Group()
+ for _ in range(10):
+ rect = Rectangle()
+ grp.add(rect)
+
+ for elem in grp:
+ self.assertEqual(type(elem), Rectangle)
+
+ def test_abstract_raises(self):
+ """Abstract classes cannot be instantiated"""
+ self.assertRaises(NotImplementedError, FakeShape().get_path)
+ self.assertRaises(AttributeError, FakeShape().set_path, None)
+
+ def test_add(self):
+ """Can add single or multiple elements with passthrough"""
+ elem = self.svg.getElementById('D')
+ group = elem.add(Group(id='foo'))
+ self.assertEqual(group.get('id'), 'foo')
+ groups = elem.add(Group(id='f1'), Group(id='f2'))
+ self.assertEqual(len(groups), 2)
+ self.assertEqual(groups[0].get('id'), 'f1')
+ self.assertEqual(groups[1].get('id'), 'f2')
+
+ def test_creation(self):
+ """Create elements with attributes"""
+ group = Group().update(inkscape__label='Foo')
+ self.assertEqual(group.get('inkscape:label'), 'Foo')
+ group = Group().update(inkscape__label='Bar')
+ self.assertEqual(group.label, 'Bar')
+
+ def test_tostring(self):
+ """Elements can be printed as strings"""
+ self.assertEqual(Group().tostring(), b'<g/>')
+ elem = Group(id='bar')
+ path = elem.add(Tspan(id='foo'))
+ elem.transform.add_translate(50, 50)
+ path.style['fill'] = 'red'
+ self.assertEqual(elem.tostring(), \
+ b'<g transform="translate(50, 50)"><tspan id="foo" style="fill:red"/></g>')
+
+class AttributeHandelingTestCase(SvgTestCase):
+ """Test how attributes are handled"""
+ def test_chained_multiple_attrs(self):
+ """Set multiple attributes at a time"""
+ group = Group().update(
+ attr1='A',
+ attr2='B'
+ ).update(
+ attr3='C',
+ attr4='D'
+ )
+ self.assertEqual(group.get('attr1'), 'A')
+ self.assertEqual(group.get('attr2'), 'B')
+ self.assertEqual(group.get('attr3'), 'C')
+ self.assertEqual(group.get('attr4'), 'D')
+
+ # remove attributes, setting them to None
+ group.update(
+ attr1=None,
+ attr4=None
+ )
+
+ self.assertEqual(group.get('attr1'), None)
+ self.assertEqual(group.get('attr2'), 'B')
+ self.assertEqual(group.get('attr3'), 'C')
+ self.assertEqual(group.get('attr4'), None)
+
+ self.assertEqual(group.pop('attr2'), 'B')
+ self.assertEqual(group.pop('attr3'), 'C')
+
+ def test_set_wrapped_attribute(self):
+ """Remove wrapped attribute using .set()"""
+ group = Group().update(
+ transform=Transform(scale=2)
+ )
+ self.assertEqual(group.transform.matrix[0][0], 2)
+ self.assertEqual(group.transform.matrix[1][1], 2)
+
+ group.update(
+ transform=None
+ )
+ self.assertEqual(group.transform, Transform())
+
+ def test_pop_wrapped_attribute(self):
+ """Remove wrapped attribute using .pop()"""
+ group = Group()
+
+ self.assertEqual(group.pop('transform'), Transform())
+
+ group.update(
+ transform=Transform(scale=2)
+ )
+ self.assertEqual(group.pop('transform'), Transform(scale=2))
+ self.assertEqual(group.pop('transform'), Transform())
+ self.assertRaises(AttributeError, getattr, group, 'foo')
+
+ def test_pop_regular_attribute(self):
+ """Remove wrapped attribute using .pop()"""
+ group = Group()
+
+ self.assertEqual(group.get('attr1'), None)
+
+ group.update(
+ attr1="42"
+ )
+ self.assertEqual(group.pop('attr1'), "42")
+ self.assertEqual(group.pop('attr1'), None)
+
+ def test_update_consistant(self):
+ """Update doesn't keep callbacks around"""
+ elem = self.svg.getElementById('D')
+ tr_a = Transform(translate=(10, 10))
+ tr_b = Transform(translate=(-20, 15))
+ elem.transform = tr_a
+ elem.transform = tr_b
+ self.assertEqual(str(elem.transform), 'translate(-20, 15)')
+ tr_a.add_translate(10, 10)
+ self.assertEqual(str(elem.transform), 'translate(-20, 15)')
+ elem.set('transform', None)
+ self.assertEqual(elem.get('transform'), None)
+
+ def test_in_place_style(self):
+ """Do styles update when we set them"""
+ elem = self.svg.getElementById('D')
+ elem.style['fill'] = 'purpleberry'
+ self.assertEqual(elem.get('style'), 'fill:purpleberry')
+ elem.style = {'marker': 'flag'}
+ self.assertEqual(elem.get('style'), 'marker:flag')
+ elem.style = Style(stroke='gammon')
+ self.assertEqual(elem.get('style'), 'stroke:gammon')
+ elem.style.update('grape:2;strawberry:nice;')
+ self.assertEqual(elem.get('style'), 'stroke:gammon;grape:2;strawberry:nice')
+
+ def test_random_id(self):
+ """Test setting a random id"""
+ elem = self.svg.getElementById('D')
+ elem.set_random_id('Thing')
+ self.assertEqual(elem.get('id'), 'Thing5815')
+ elem.set_random_id('Thing', size=2)
+ self.assertEqual(elem.get('id'), 'Thing85')
+ elem.set_random_id()
+ self.assertEqual(elem.get('id'), 'path5392')
+ # No document root, no random id allowed
+ self.assertRaises(FragmentError, elem.copy().set_random_id)
+
+ def test_random_ids(self):
+ """Test setting a tree of ids"""
+ elem = self.svg.getElementById('D')
+ self.svg.set_random_ids(prefix='TreeItem')
+ self.assertEqual(self.svg.get('id'), 'TreeItem5815')
+ self.assertEqual(self.svg[0].get('id'), 'TreeItem8555')
+ self.assertEqual(elem.get('id'), 'TreeItem2036')
+
+ def test_set_id_backlinks(self):
+ """Changing an id can update backlinks"""
+ elem = self.svg.getElementById('path1')
+ elem.set_id('plant54', True)
+ self.assertEqual(self.svg.getElementById('G').get('xlink:href'), '#plant54')
+ self.assertEqual(self.svg.getElementById('G').href, elem)
+ self.assertEqual(str(self.svg.getElementById('B').style), 'fill:#eee;joker:url(#plant54)')
+
+ def test_get_element_by_name(self):
+ """Get elements by name"""
+ self.assertEqual(self.svg.getElementByName('Key').get('id'), 'K')
+ self.assertEqual(self.svg.getElementByName('Elm', 'svg:g').get('id'), 'L')
+ self.assertEqual(self.svg.getElementByName('Mine').get('id'), 'M')
+ self.assertEqual(self.svg.getElementByName('doesntexist'), None)
+ self.assertEqual(self.svg.getElementByName('Key', 'rect'), None)
+
+
+class TransformationTestCase(SvgTestCase):
+ """Test transformative functions"""
+ def test_bounding_box(self):
+ """Elements can have bounding boxes"""
+ elem = self.svg.getElementById('D')
+ self.assertEqual(tuple(elem.bounding_box()), ((60.0, 100.0), (130.0, 170.00)))
+ self.assertTrue(elem.bounding_box().center.is_close((80.0, 150.0)))
+ self.assertEqual(tuple(TextElement(x='10', y='5').bounding_box()), ((10, 10), (5, 5)))
+ group = Group(elem)
+ self.assertEqual(elem.bounding_box(), group.bounding_box())
+
+ def test_transform(self):
+ """In-place modified transforms are retained"""
+ elem = self.svg.getElementById('D')
+ self.assertEqual(str(elem.transform), 'translate(30, 10)')
+ elem.transform.add_translate(-10, 10)
+ self.assertEqual(str(elem.transform), 'translate(20, 20)')
+
+ def test_scale(self):
+ """In-place scaling from blank transform"""
+ elem = self.svg.getElementById('F')
+ self.assertEqual(elem.transform, Transform())
+ self.assertEqual(elem.get('transform'), None)
+ elem.transform.add_scale(1.0666666666666667, 1.0666666666666667)
+ self.assertEqual(elem.get('transform'), Transform(scale=1.06667))
+ self.assertIn(b'transform', etree.tostring(elem))
+
+ def test_in_place_transforms(self):
+ """Do style and transforms update correctly"""
+ elem = self.svg.getElementById('D')
+ self.assertEqual(type(elem.transform), Transform)
+ self.assertEqual(type(elem.style), Style)
+ self.assertTrue(elem.transform)
+ elem.transform = Transform()
+ self.assertEqual(elem.transform, Transform())
+ self.assertEqual(elem.get('transform'), None)
+ self.assertNotIn(b'transform', etree.tostring(elem))
+ elem.transform.add_translate(10, 10)
+ self.assertIn(b'transform', etree.tostring(elem))
+ elem.transform.add_translate(-10, -10)
+ self.assertNotIn(b'transform', etree.tostring(elem))
+
+class RelationshipTestCase(SvgTestCase):
+ """Test relationships between elements"""
+ def test_findall(self):
+ """Findall elements in svg"""
+ groups = self.svg.findall('svg:g')
+ self.assertEqual(len(groups), 1)
+
+ def test_copy(self):
+ """Test copying elements"""
+ elem = self.svg.getElementById('D')
+ cpy = elem.copy()
+ self.assertFalse(cpy.getparent())
+ self.assertFalse(cpy.get('id'))
+
+ def test_duplicate(self):
+ """Test duplicating elements"""
+ elem = self.svg.getElementById('D')
+ dup = elem.duplicate()
+ self.assertTrue(dup.get('id'))
+ self.assertNotEqual(elem.get('id'), dup.get('id'))
+ self.assertEqual(elem.getparent(), dup.getparent())
+
+ def test_replace_with(self):
+ """Replacing nodes in a tree"""
+ rect = self.svg.getElementById('E')
+ path = rect.to_path_element()
+ rect.replace_with(path)
+ self.assertEqual(rect.getparent(), None)
+ self.assertEqual(path.getparent(), self.svg.getElementById('C'))
+
+ def test_descendants(self):
+ """Elements can walk their descendants"""
+ self.assertEqual(tuple(self.svg.descendants().ids), (
+ 'mydoc', 'path1', 'base', 'metadata7',
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M',
+ ))
+ get = self.svg.getElementById
+ self.assertEqual(tuple(get('L').descendants().ids), ('L', 'M'))
+ self.assertEqual(tuple(get('M').descendants().ids), ('M',))
+
+ def test_ancestors(self):
+ """Element descendants of elements"""
+ get = self.svg.getElementById
+ self.assertEqual(tuple(get('M').ancestors().ids), ('L', 'K', 'A', 'mydoc'))
+ self.assertEqual(tuple(get('M').ancestors(stop_at=[None]).ids), ('L', 'K', 'A', 'mydoc'))
+ self.assertEqual(tuple(get('M').ancestors(stop_at=[get('K')]).ids), ('L', 'K'))
+ self.assertEqual(tuple(get('M').ancestors(stop_at=[get('L')]).ids), ('L',))
+
+ def test_luca(self):
+ """Test last common ancestor"""
+ get = self.svg.getElementById
+ self.assertEqual(tuple(get('M').ancestors(get('M')).ids), ('L',))
+ self.assertEqual(tuple(get('G').ancestors(get('H')).ids), ('C',))
+ self.assertEqual(tuple(get('M').ancestors(get('H')).ids), ('L', 'K', 'A'))