[Erp5-report] r16780 - in /erp5/trunk/products/ERP5OOo/tests: testOOoStyle.py utils.py

nobody at svn.erp5.org nobody at svn.erp5.org
Tue Oct 2 17:02:01 CEST 2007


Author: jerome
Date: Tue Oct  2 17:02:01 2007
New Revision: 16780

URL: http://svn.erp5.org?rev=16780&view=rev
Log:
Tests ods_style and odt_style for validity against opendocument schema.
The utility class "Validator" can be reused to validate any OOoTemplate.


Added:
    erp5/trunk/products/ERP5OOo/tests/testOOoStyle.py
    erp5/trunk/products/ERP5OOo/tests/utils.py

Added: erp5/trunk/products/ERP5OOo/tests/testOOoStyle.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5OOo/tests/testOOoStyle.py?rev=16780&view=auto
==============================================================================
--- erp5/trunk/products/ERP5OOo/tests/testOOoStyle.py (added)
+++ erp5/trunk/products/ERP5OOo/tests/testOOoStyle.py Tue Oct  2 17:02:01 2007
@@ -1,0 +1,149 @@
+##############################################################################
+#
+# Copyright (c) 2007 Nexedi SA and Contributors. All Rights Reserved.
+#          Jerome Perrin <jerome at nexedi.com>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability 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
+# garantees 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+##############################################################################
+
+import unittest
+from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
+from Testing import ZopeTestCase
+from Products.ERP5OOo.tests.utils import Validator
+
+HTTP_OK = 200
+
+
+class TestOOoStyle(ERP5TypeTestCase, ZopeTestCase.Functional):
+  """Tests ODF styles for ERP5."""
+  skin = None
+  content_type = None
+
+  def getBusinessTemplateList(self):
+    return ('erp5_base', 'erp5_ods_style', 'erp5_odt_style',)
+
+  def afterSetUp(self):
+    if not self.skin:
+      raise NotImplementedError('Subclasses must define skin')
+    
+    self.auth = 'ERP5TypeTestCase:'
+    person_module = self.portal.person_module
+    if not hasattr(person_module, 'pers'):
+      person_module.newContent(id='pers', portal_type='Person')
+    self.portal.changeSkin(self.skin)
+    self.validator = Validator()
+
+  def _validate(self, odf_file_data):
+    error_list = self.validator.validate(odf_file_data)
+    if error_list:
+      self.fail(''.join(error_list))
+
+  def test_skin_selection(self):
+    self.assertTrue(self.skin in
+              self.portal.portal_skins.getSkinSelections())
+
+  def test_list_view(self):
+    response = self.publish(
+                   '/%s/person_module/PersonModule_viewPersonList'
+                    % self.portal.getId(), self.auth)
+    self.assertEquals(HTTP_OK, response.getStatus())
+    content_type = response.getHeader('content-type')
+    self.assertTrue(content_type.startswith(self.content_type), content_type)
+    content_disposition = response.getHeader('content-disposition')
+    self.assertEquals('inline', content_disposition.split(';')[0])
+    self._validate(response.getBody())
+
+  def test_form_view(self):
+    response = self.publish(
+                   '/%s/person_module/pers/Person_view'
+                   % self.portal.getId(), self.auth)
+    self.assertEquals(HTTP_OK, response.getStatus())
+    content_type = response.getHeader('content-type')
+    self.assertTrue(content_type.startswith(self.content_type), content_type)
+    content_disposition = response.getHeader('content-disposition')
+    self.assertEquals('inline', content_disposition.split(';')[0])
+    self._validate(response.getBody())
+
+  def test_form_view_format(self):
+    # empty format= does not uses oood for conversion
+    response = self.publish(
+                   '/%s/person_module/pers/Person_view?format='
+                   % self.portal.getId(), self.auth)
+    self.assertEquals(HTTP_OK, response.getStatus())
+    content_type = response.getHeader('content-type')
+    self.assertTrue(content_type.startswith(self.content_type), content_type)
+    content_disposition = response.getHeader('content-disposition')
+    self.assertEquals('inline', content_disposition.split(';')[0])
+    self._validate(response.getBody())
+
+  def test_report_view(self):
+    response = self.publish(
+                   '/%s/person_module/pers/Base_viewHistory'
+                    % self.portal.getId(), self.auth)
+    self.assertEquals(HTTP_OK, response.getStatus())
+    content_type = response.getHeader('content-type')
+    self.assertTrue(content_type.startswith(self.content_type), content_type)
+    content_disposition = response.getHeader('content-disposition')
+    self.assertEquals('inline', content_disposition.split(';')[0])
+    self._validate(response.getBody())
+
+  def test_report_view_landscape(self):
+    response = self.publish(
+       '/%s/person_module/pers/Base_viewHistory?landscape=1'
+        % self.portal.getId(), self.auth)
+    self.assertEquals(HTTP_OK, response.getStatus())
+    content_type = response.getHeader('content-type')
+    self.assertTrue(content_type.startswith(self.content_type), content_type)
+    content_disposition = response.getHeader('content-disposition')
+    self.assertEquals('inline', content_disposition.split(';')[0])
+    self._validate(response.getBody())
+
+  def test_report_view_sheet_per_report_section(self):
+    response = self.publish(
+       '/%s/person_module/pers/Base_viewHistory?sheet_per_report_section=1'
+        % self.portal.getId(), self.auth)
+    self.assertEquals(HTTP_OK, response.getStatus())
+    content_type = response.getHeader('content-type')
+    self.assertTrue(content_type.startswith(self.content_type), content_type)
+    content_disposition = response.getHeader('content-disposition')
+    self.assertEquals('inline', content_disposition.split(';')[0])
+    self._validate(response.getBody())
+
+
+class TestODTStyle(TestOOoStyle):
+  skin = 'ODT'
+  content_type = 'application/vnd.oasis.opendocument.text'
+
+
+class TestODSStyle(TestOOoStyle):
+  skin = 'ODS'
+  content_type = 'application/vnd.oasis.opendocument.spreadsheet'
+
+
+def test_suite():
+  suite = unittest.TestSuite()
+  suite.addTest(unittest.makeSuite(TestODTStyle))
+  # ODS style is not valid yet
+ # suite.addTest(unittest.makeSuite(TestODSStyle))
+  return suite
+

Added: erp5/trunk/products/ERP5OOo/tests/utils.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5OOo/tests/utils.py?rev=16780&view=auto
==============================================================================
--- erp5/trunk/products/ERP5OOo/tests/utils.py (added)
+++ erp5/trunk/products/ERP5OOo/tests/utils.py Tue Oct  2 17:02:01 2007
@@ -1,0 +1,146 @@
+##############################################################################
+#
+# Copyright (c) 2007 Nexedi SA and Contributors. All Rights Reserved.
+#          Jerome Perrin <jerome at nexedi.com>
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability 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
+# garantees 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+##############################################################################
+
+"""This module provides utilities for testing ODF files.
+
+Validator: a class defining a `validate` method that expects odf file content
+as first argument and returns list of errors.
+
+"""
+
+import os
+import sys
+import tempfile
+import zipfile
+import popen2
+import urllib2
+from cStringIO import StringIO
+
+try:
+  import libxml2
+except ImportError:
+  libxml2 = None
+try:
+  import odfpy
+except ImportError:
+  odfpy = None
+
+
+if libxml2:
+
+  class ErrorHandler:
+    """Collect errors"""
+    def __init__(self, file_name):
+      libxml2.lineNumbersDefault(1)
+      self.file_name = file_name
+      self.error_list = []
+
+    def onError(self, msg, data):
+      line = libxml2.lastError().line()
+      self.error_list.append('%s:%s: %s' % (self.file_name, line, msg))
+    onWarning = onError
+
+
+  class LibXML2Validator:
+    """Validate ODF document using RelaxNG and libxml2"""
+    schema_url = \
+      'http://docs.oasis-open.org/office/v1.1/OS/OpenDocument-schema-v1.1.rng'
+
+    def __init__(self, schema_url=schema_url):
+      self.schema_url = schema_url
+      self.schema_path = os.path.join(
+              tempfile.gettempdir(), 'OpenDocument.rng')
+      # download if local copy does not exists
+      if not os.path.exists(self.schema_path):
+        self._download()
+      ctxt = libxml2.relaxNGNewParserCtxt(self.schema_path)
+      self.relaxng = ctxt.relaxNGParse()
+
+    def validate(self, odf_file_content):
+      error_list = []
+      odf_file = StringIO(odf_file_content)
+      for f in ('content.xml', 'meta.xml', 'styles.xml', 'settings.xml'):
+        error_list.extend(self._validateXML(odf_file, f))
+      return error_list
+
+    def _download(self):
+      r = urllib2.urlopen(self.schema_url)
+      out_file = open(self.schema_path, 'w')
+      try:
+        out_file.write(r.read())
+      finally:
+        out_file.close()
+        r.close()
+
+    def _validateXML(self, odf_file, content_file_name):
+      validationCtxt = self.relaxng.relaxNGNewValidCtxt()
+      err = ErrorHandler(content_file_name)
+
+      validationCtxt.setValidityErrorHandler(
+          err.onError, err.onWarning)
+
+      zfd = zipfile.ZipFile(odf_file)
+      content = zfd.read(content_file_name)
+
+      validationCtxt.relaxNGValidateDoc(
+                libxml2.parseMemory(content, len(content)))
+      return err.error_list
+
+  Validator = LibXML2Validator
+
+elif odfpy:
+
+  class OdflintValidator:
+    """Validates ODF files using odflint, available on pypi
+    http://opendocumentfellowship.org/development/projects/odfpy
+    """
+    def validate(self, odf_file_content):
+      fd, file_name = tempfile.mkstemp()
+      os.write(fd, odf_file_content)
+      os.close(fd)
+      stdout, stdin = popen2.popen4('odflint %s' % file_name)
+      stdin.close()
+      error_list = ''
+      for line in stdout:
+        if line.startswith('Error: '):
+          error_list += line
+      os.unlink(file_name)
+      return error_list
+
+  Validator = OdflintValidator
+
+else:
+
+  class NoValidator:
+    """Does not actually validate, but keep the interface."""
+    def validate(self, odf_file_content):
+      print >> sys.stderr, 'No validator available'
+
+  Validator = NoValidator
+
+




More information about the Erp5-report mailing list