############################################################################## # -*- coding: utf-8 -*- # Copyright (c) 2009 Nexedi SA and Contributors. All Rights Reserved. # Fabien Morin <fabien@nexedi.com> # # WARNING: This program as such is intended to be used by professional # programmers who take the whole responsibility of assessing all potential # consequences resulting from its eventual inadequacies and bugs # End users who are looking for a ready-to-use solution with commercial # guarantees and support are strongly adviced to contract a Free Software # Service Company # # This program is Free Software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, # USA. # ############################################################################## import unittest import transaction from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase from Products.ERP5OOo.tests.testFormPrintout import TestFormPrintoutMixin from Products.ERP5OOo.OOoUtils import OOoBuilder from Products.ERP5OOo.tests.utils import Validator from Products.ERP5Type.tests.utils import FileUpload from urllib import quote_plus from lxml import etree import os class TestFormPrintoutAsODG(TestFormPrintoutMixin): run_all_test = 1 def getTitle(self): """ Return the title of the current test set. """ return "FormPrintoutAsODG" def afterSetUp(self): self.login() # XML validator v12schema_url = os.path.join(os.path.dirname(__file__), 'OpenDocument-schema-v1.2-draft9.rng') self.validator = Validator(schema_url=v12schema_url) foo_file_path = os.path.join(os.path.dirname(__file__), 'test_document', 'Foo_001.odg') foo_file = open(foo_file_path, 'rb') self._validate(foo_file.read()) custom = self.portal.portal_skins.custom addStyleSheet = custom.manage_addProduct['OFSP'].manage_addFile if custom._getOb('Foo_getODGStyleSheet', None) is None: addStyleSheet(id='Foo_getODGStyleSheet', file=foo_file, title='', precondition='', content_type='application/vnd.oasis.opendocument.graphics') erp5OOo = custom.manage_addProduct['ERP5OOo'] addOOoTemplate = erp5OOo.addOOoTemplate if custom._getOb('Foo_viewAsOdg', None) is None: addOOoTemplate(id='Foo_viewAsOdg', title='') request = self.app.REQUEST Foo_viewAsOdg = custom.Foo_viewAsOdg Foo_viewAsOdg.doSettings(request, title='', xml_file_id='content.xml', ooo_stylesheet='Foo_getODGStyleSheet') builder = OOoBuilder(foo_file) content = builder.extract('content.xml') Foo_viewAsOdg.pt_edit(content, content_type='application/vnd.oasis.opendocument.graphics') if custom._getOb('Foo_viewAsODGPrintout', None) is None: erp5OOo.addFormPrintout(id='Foo_viewAsODGPrintout', title='', form_name='Foo_view', template='Foo_getODGStyleSheet') if custom._getOb('FooReport_viewAsODGPrintout', None) is None: erp5OOo.addFormPrintout(id='FooReport_viewAsODGPrintout', title='') ## append 'test1' data to a listbox foo_module = self.portal.foo_module if foo_module._getOb('test1', None) is None: foo_module.newContent(id='test1', portal_type='Foo') test1 = foo_module.test1 if test1._getOb("foo_1", None) is None: test1.newContent("foo_1", portal_type='Foo Line') if test1._getOb("foo_2", None) is None: test1.newContent("foo_2", portal_type='Foo Line') transaction.commit() self.tic() def getStyleDictFromFieldName(self, content_xml, field_id): '''parse content_xml string and return a dict with node node.tag as key and style dict as value ''' element_tree = etree.XML(content_xml) text_xpath = '//draw:frame[@draw:name="%s"]/*' % field_id node_list = element_tree.xpath(text_xpath, namespaces=element_tree.nsmap) style_dict = {} for target_node in node_list: style_dict = {} for descendant in target_node.iterdescendants(): style_dict.setdefault(descendant.tag, {}).update(descendant.attrib) return style_dict def test_01_TextField(self): """ mapping a field to textbox """ portal = self.getPortal() foo_module = self.portal.foo_module if foo_module._getOb('test1', None) is None: foo_module.newContent(id='test1', portal_type='Foo') test1 = foo_module.test1 test1.setTitle('Foo title!') transaction.commit() self.tic() style_dict = {'{urn:oasis:names:tc:opendocument:xmlns:text:1.0}span': {'{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name': 'T2'}, '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}p': {} } # test target foo_printout = portal.foo_module.test1.Foo_viewAsODGPrintout original_file_content = self.getODFDocumentFromPrintout(foo_printout) self._validate(original_file_content) # extract content.xml from original odg document original_doc_builder = OOoBuilder(original_file_content) original_content_xml = original_doc_builder.extract("content.xml") # get style of the title in the orignal test document original_document_style_dict = self.getStyleDictFromFieldName(original_content_xml, 'my_title') # check the style is good before the odg generation self.assertEqual(original_document_style_dict, style_dict) request = self.app.REQUEST # 1. Normal case: "my_title" field to the "my_title" reference in the ODF document odf_document = foo_printout.index_html(REQUEST=request) self.assertTrue(odf_document is not None) builder = OOoBuilder(odf_document) content_xml = builder.extract("content.xml") final_document_style_dict = self.getStyleDictFromFieldName(content_xml, 'my_title') # check the style is keept after the odg generation self.assertEqual(final_document_style_dict, style_dict) self.assertTrue(content_xml.find("Foo title!") > 0) self.assertEqual(request.RESPONSE.getHeader('content-type'), 'application/vnd.oasis.opendocument.graphics; charset=utf-8') self.assertEqual(request.RESPONSE.getHeader('content-disposition'), 'inline;filename="Foo_viewAsODGPrintout.odg"') self._validate(odf_document) # 2. Normal case: change the field value and check again the ODF document test1.setTitle("Changed Title!") #foo_form.my_title.set_value('default', "Changed Title!") odf_document = foo_printout.index_html(REQUEST=request) self.assertTrue(odf_document is not None) builder = OOoBuilder(odf_document) content_xml = builder.extract("content.xml") self.assertTrue(content_xml.find("Changed Title!") > 0) self._validate(odf_document) # 3. False case: change the field name test1.setTitle("you cannot find") # rename id 'my_title' to 'xxx_title', then does not match in the ODF document foo_form = portal.foo_module.test1.Foo_view foo_form.manage_renameObject('my_title', 'xxx_title', REQUEST=request) odf_document = foo_printout.index_html(REQUEST=request) self.assertTrue(odf_document is not None) builder = OOoBuilder(odf_document) content_xml = builder.extract("content.xml") self.assertFalse(content_xml.find("you cannot find") > 0) self._validate(odf_document) # put back foo_form.manage_renameObject('xxx_title', 'my_title', REQUEST=request) ## 4. False case: does not set a ODF template self.assertTrue(foo_printout.template == 'Foo_getODGStyleSheet') tmp_template = foo_printout.template foo_printout.template = None # template == None, causes a ValueError try: foo_printout.index_html(REQUEST=request) except ValueError, e: # e -> 'Can not create a ODF Document without a odf_template' self.assertTrue(True) # put back foo_printout.template = tmp_template # 5. Normal case: just call a FormPrintout object request.RESPONSE.setHeader('Content-Type', 'text/html') test1.setTitle("call!") odf_document = foo_printout() # call self.assertTrue(odf_document is not None) builder = OOoBuilder(odf_document) content_xml = builder.extract("content.xml") self.assertTrue(content_xml.find("call!") > 0) # when just call FormPrintout, it does not change content-type self.assertEqual(request.RESPONSE.getHeader('content-type'), 'text/html') self._validate(odf_document) # 5. Normal case: utf-8 string test1.setTitle("Français") odf_document = foo_printout() self.assertTrue(odf_document is not None) builder = OOoBuilder(odf_document) content_xml = builder.extract("content.xml") self.assertTrue(content_xml.find("Français") > 0) self._validate(odf_document) # 6. Normal case: unicode string test1.setTitle(u'Français test2') odf_document = foo_printout() self.assertTrue(odf_document is not None) builder = OOoBuilder(odf_document) content_xml = builder.extract("content.xml") self.assertTrue(content_xml.find("Français test2") > 0) self._validate(odf_document) def test_02_TextFieldWithMultiLines(self): """ mapping a field containing many lines ('\n') to a textbox """ portal = self.getPortal() # add a description field in the form foo_form = self.portal.foo_module.test1.Foo_view if foo_form._getOb("my_description", None) is None: foo_form.manage_addField('my_description', 'Description', 'TextAreaField') foo_module = self.portal.foo_module if foo_module._getOb('test1', None) is None: foo_module.newContent(id='test1', portal_type='Foo') test1 = foo_module.test1 test1.setDescription('A text a bit more longer\n\nWith a newline !') transaction.commit() self.tic() style_dict = {'{urn:oasis:names:tc:opendocument:xmlns:text:1.0}line-break': {}, '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}p': {}, '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}span': {'{urn:oasis:names:tc:opendocument:xmlns:text:1.0}style-name': 'T4'} } # test target foo_printout = portal.foo_module.test1.Foo_viewAsODGPrintout original_file_content = self.getODFDocumentFromPrintout(foo_printout) self._validate(original_file_content) # extract content.xml from original odg document original_doc_builder = OOoBuilder(original_file_content) original_content_xml = original_doc_builder.extract("content.xml") # get style of the title in the orignal test document original_document_style_dict = self.getStyleDictFromFieldName(original_content_xml, 'my_description') # check the style is good before the odg generation self.assertEqual(original_document_style_dict, style_dict) request = self.app.REQUEST # 1. Normal case: "my_title" field to the "my_title" reference in the ODF document odf_document = foo_printout.index_html(REQUEST=request) self.assertTrue(odf_document is not None) # validate the generated document self._validate(odf_document) builder = OOoBuilder(odf_document) content_xml = builder.extract("content.xml") content = etree.XML(content_xml) final_document_style_dict = self.getStyleDictFromFieldName(content_xml, 'my_description') # check the style is keept after the odg generation self.assertEqual(final_document_style_dict, style_dict) # check the two lines are prensent in the generated document self.assertTrue(content_xml.find('A text a bit more longer') > 0) self.assertTrue(content_xml.find('With a newline !') > 0) # check there is two line-break in the element my_description text_xpath = '//draw:frame[@draw:name="my_description"]//text:line-break' node_list = content.xpath(text_xpath, namespaces=content.nsmap) self.assertEqual(len(node_list), 2) def test_03_Image(self): """ Mapping an ImageField to odg document. Check it's possible to use an odg document to map an image with a form.ImageField """ # create a new person person_module = self.portal.getDefaultModule('Person') if person_module._getOb('person1', None) is None: person_module.newContent(id='person1', portal_type='Person') person1 = person_module.person1 # add an image to this person current_dir = os.path.dirname(__file__) parent_dir = os.path.dirname(current_dir) image_path = os.path.join(parent_dir, 'www', 'form_printout_icon.png') file_data = FileUpload(image_path, 'rb') image = person1.newContent(portal_type='Image') image.edit(file=file_data) foo_printout = image.Foo_viewAsODGPrintout foo_form = image.Foo_view # add an image_field to Foo_view if there is not if foo_form._getOb("image_view", None) is None: foo_form.manage_addField('image_view', 'logo', 'ImageField') image_view_field = foo_form.image_view # set the image on the field image_view_field.values['default'] = image.absolute_url_path() # 01 - Normal image mapping odf_document = foo_printout() self.assertTrue(odf_document is not None) self._validate(odf_document) builder = OOoBuilder(odf_document) content_xml = builder.extract("content.xml") self.assertTrue(content_xml.find('<draw:image xlink:href') > 0) self.assertTrue(content_xml.find("Pictures/%s.png" % \ quote_plus(image.getPath())) > 0) # check the image is in the odg file try: builder.extract("Pictures/%s.png" % quote_plus(image.getPath())) except KeyError: self.fail('image "Pictures/%s.png" not found in odg document' % \ image.getPath()) content = etree.XML(content_xml) image_frame_xpath = '//draw:frame[@draw:name="image_view"]' image_frame_list = content.xpath(image_frame_xpath, namespaces=content.nsmap) self.assertTrue(len(image_frame_list) > 0) image_frame = image_frame_list[0] # Check the image size. # as the test image (form_printout_icon.png) is a square, proportions # should be keept, so heigh and width should be same and equal to the # height of the original image in the original odf test document. self.assertEqual(image_frame.attrib['{%s}height' % content.nsmap['svg']], '1.206cm') self.assertEqual(image_frame.attrib['{%s}width' % content.nsmap['svg']], '1.206cm') # 02: No image defined image_view_field.values['default'] = '' odf_document = foo_printout() self.assertTrue(odf_document is not None) builder = OOoBuilder(odf_document) content_xml = builder.extract("content.xml") # confirming the image was removed self.assertTrue(content_xml.find('<draw:image xlink:href') < 0) self._validate(odf_document) def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(TestFormPrintoutAsODG)) return suite