1# encoding: utf-8 2 3""" 4Test suite for pptx.oxml.__init__.py module, primarily XML parser-related. 5""" 6 7from __future__ import print_function, unicode_literals 8 9import pytest 10 11from lxml import etree 12 13from docx.oxml import ( 14 OxmlElement, oxml_parser, parse_xml, register_element_cls 15) 16from docx.oxml.ns import qn 17from docx.oxml.shared import BaseOxmlElement 18 19 20class DescribeOxmlElement(object): 21 22 def it_returns_an_lxml_element_with_matching_tag_name(self): 23 element = OxmlElement('a:foo') 24 assert isinstance(element, etree._Element) 25 assert element.tag == ( 26 '{http://schemas.openxmlformats.org/drawingml/2006/main}foo' 27 ) 28 29 def it_adds_supplied_attributes(self): 30 element = OxmlElement('a:foo', {'a': 'b', 'c': 'd'}) 31 assert etree.tostring(element) == ( 32 '<a:foo xmlns:a="http://schemas.openxmlformats.org/drawingml/200' 33 '6/main" a="b" c="d"/>' 34 ).encode('utf-8') 35 36 def it_adds_additional_namespace_declarations_when_supplied(self): 37 ns1 = 'http://schemas.openxmlformats.org/drawingml/2006/main' 38 ns2 = 'other' 39 element = OxmlElement('a:foo', nsdecls={'a': ns1, 'x': ns2}) 40 assert len(element.nsmap.items()) == 2 41 assert element.nsmap['a'] == ns1 42 assert element.nsmap['x'] == ns2 43 44 45class DescribeOxmlParser(object): 46 47 def it_strips_whitespace_between_elements(self, whitespace_fixture): 48 pretty_xml_text, stripped_xml_text = whitespace_fixture 49 element = etree.fromstring(pretty_xml_text, oxml_parser) 50 xml_text = etree.tostring(element, encoding='unicode') 51 assert xml_text == stripped_xml_text 52 53 # fixtures ------------------------------------------------------- 54 55 @pytest.fixture 56 def whitespace_fixture(self): 57 pretty_xml_text = ( 58 '<foø>\n' 59 ' <bår>text</bår>\n' 60 '</foø>\n' 61 ) 62 stripped_xml_text = '<foø><bår>text</bår></foø>' 63 return pretty_xml_text, stripped_xml_text 64 65 66class DescribeParseXml(object): 67 68 def it_accepts_bytes_and_assumes_utf8_encoding(self, xml_bytes): 69 parse_xml(xml_bytes) 70 71 def it_accepts_unicode_providing_there_is_no_encoding_declaration(self): 72 non_enc_decl = '<?xml version="1.0" standalone="yes"?>' 73 enc_decl = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' 74 xml_body = '<foo><bar>føøbår</bar></foo>' 75 # unicode body by itself doesn't raise 76 parse_xml(xml_body) 77 # adding XML decl without encoding attr doesn't raise either 78 xml_text = '%s\n%s' % (non_enc_decl, xml_body) 79 parse_xml(xml_text) 80 # but adding encoding in the declaration raises ValueError 81 xml_text = '%s\n%s' % (enc_decl, xml_body) 82 with pytest.raises(ValueError): 83 parse_xml(xml_text) 84 85 def it_uses_registered_element_classes(self, xml_bytes): 86 register_element_cls('a:foo', CustElmCls) 87 element = parse_xml(xml_bytes) 88 assert isinstance(element, CustElmCls) 89 90 # fixture components --------------------------------------------- 91 92 @pytest.fixture 93 def xml_bytes(self): 94 return ( 95 '<a:foo xmlns:a="http://schemas.openxmlformats.org/drawingml/200' 96 '6/main">\n' 97 ' <a:bar>foøbår</a:bar>\n' 98 '</a:foo>\n' 99 ).encode('utf-8') 100 101 102class DescribeRegisterElementCls(object): 103 104 def it_determines_class_used_for_elements_with_matching_tagname( 105 self, xml_text): 106 register_element_cls('a:foo', CustElmCls) 107 foo = parse_xml(xml_text) 108 assert type(foo) is CustElmCls 109 assert type(foo.find(qn('a:bar'))) is etree._Element 110 111 # fixture components --------------------------------------------- 112 113 @pytest.fixture 114 def xml_text(self): 115 return ( 116 '<a:foo xmlns:a="http://schemas.openxmlformats.org/drawingml/200' 117 '6/main">\n' 118 ' <a:bar>foøbår</a:bar>\n' 119 '</a:foo>\n' 120 ) 121 122 123# =========================================================================== 124# static fixture 125# =========================================================================== 126 127class CustElmCls(BaseOxmlElement): 128 pass 129