diff options
Diffstat (limited to 'share/extensions/tests/test_inkex_elements_base.py')
-rw-r--r-- | share/extensions/tests/test_inkex_elements_base.py | 322 |
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')) |