From 33d9123464d897379e2f52b43994f6b4fdb667eb Mon Sep 17 00:00:00 2001 From: Yusei Tahara <yusei@nexedi.com> Date: Fri, 20 Jul 2007 08:32:34 +0000 Subject: [PATCH] Added a xhtml validation test for content views. git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@15257 20353a03-c40f-0410-a6d1-a30d3c3de9de --- product/ERP5/tests/testXHTML.py | 176 ++++++++++++++++++++++++++++++++ product/ERP5/tests/utils.py | 140 +++++++++++++++++++++++++ 2 files changed, 316 insertions(+) create mode 100644 product/ERP5/tests/testXHTML.py create mode 100644 product/ERP5/tests/utils.py diff --git a/product/ERP5/tests/testXHTML.py b/product/ERP5/tests/testXHTML.py new file mode 100644 index 0000000000..6aa59556c3 --- /dev/null +++ b/product/ERP5/tests/testXHTML.py @@ -0,0 +1,176 @@ +############################################################################## +# +# Copyright (c) 2007 Nexedi SARL and Contributors. All Rights Reserved. +# +# 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 os, sys +if __name__ == '__main__': + execfile(os.path.join(sys.path[0], 'framework.py')) + +# Needed in order to have a log file inside the current folder +os.environ['EVENT_LOG_FILE'] = os.path.join(os.getcwd(), 'zLOG.log') +os.environ['EVENT_LOG_SEVERITY'] = '-300' + +from Testing import ZopeTestCase +from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase +from Products.CMFCore.utils import getToolByName +from AccessControl.SecurityManagement import newSecurityManager +from zLOG import LOG +import time + +try: + from transaction import get as get_transaction +except ImportError: + pass + +# +# Test Setting +# +INSTANCE_HOME = os.environ['INSTANCE_HOME'] +bt5_path = os.path.join(INSTANCE_HOME, 'bt5') +# dependency order +target_business_templates = ( + 'erp5_base', + 'erp5_trade', + 'erp5_mysql_innodb_catalog', + + 'erp5_pdf_editor', + 'erp5_pdf_style', + 'erp5_pdm', + 'erp5_accounting', + + 'erp5_apparel', + +## 'erp5_banking_core', +## 'erp5_banking_cash', +## 'erp5_banking_check', +## 'erp5_banking_inventory', + + 'erp5_budget', + + 'erp5_commerce', + + 'erp5_consulting', + + 'erp5_crm', + + 'erp5_web', + 'erp5_dms', + + 'erp5_forge', + + 'erp5_immobilisation', + + 'erp5_item', + + 'erp5_mrp', + + 'erp5_payroll', + + 'erp5_project', +) + + +class TestXHTML(ERP5TypeTestCase): + + run_all_test = 1 + + def getTitle(self): + return "XHTML Test" + + def getBusinessTemplateList(self): + """ """ + return target_business_templates + + def afterSetUp(self): + self.portal = self.getPortal() + self.login() + self.enableDefaultSitePreference() + + def login(self, quiet=0, run=run_all_test): + uf = self.getPortal().acl_users + uf._doAddUser('seb', '', ['Manager'], []) + uf._doAddUser('ERP5TypeTestCase', '', ['Manager'], []) + user = uf.getUserById('seb').__of__(uf) + newSecurityManager(None, user) + + def enableDefaultSitePreference(self): + portal_preferences = getToolByName(self.portal, 'portal_preferences') + portal_workflow = getToolByName(self.portal, 'portal_workflow') + default_site_preference = portal_preferences.default_site_preference + portal_workflow.doActionFor(default_site_preference, 'enable_action') + + +def validate_xhtml(source): + import popen2 + stdout, stdin, stderr = popen2.popen3('/usr/bin/tidy -e -q -utf8') + stdin.write(source) + stdin.close() + for i in stderr: + data = i.split(' - ') + if len(data) >= 2: + if data[1].startswith('Error: '): + return False + return True + + +def makeTestMethod(module_id, portal_type, view_name): + def testMethod(self): + module = getattr(self.portal, module_id) + content = module.newContent(portal_type=portal_type) + view = getattr(content, view_name) + self.assert_(validate_xhtml(view())) + return testMethod + + +def addTestMethodDynamically(): + from Products.ERP5.tests.utils import BusinessTemplateInfo + for i in target_business_templates: + business_template = os.path.join(bt5_path, '%s.bt5' % i) + business_template_info = BusinessTemplateInfo(business_template) + for module_id, module_portal_type in business_template_info.modules.items(): + for portal_type in business_template_info.allowed_content_types.get( + module_portal_type, ()): + for action_information in business_template_info.actions[portal_type]: + if (action_information['category']=='object_view' and + action_information['visible']==1 and + action_information['text'].startswith('string:${object_url}/') and + len(action_information['text'].split('/'))==2): + view_name = action_information['text'].split('/')[-1] + method = makeTestMethod(module_id, portal_type, view_name) + method_name = 'test%s%s' % (portal_type, view_name) + setattr(TestXHTML, method_name, method) + +addTestMethodDynamically() + + +if __name__ == '__main__': + framework() +else: + import unittest + def test_suite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(TestXHTML)) + return suite diff --git a/product/ERP5/tests/utils.py b/product/ERP5/tests/utils.py new file mode 100644 index 0000000000..53d3d949af --- /dev/null +++ b/product/ERP5/tests/utils.py @@ -0,0 +1,140 @@ +############################################################################## +# +# Copyright (c) 2007 Nexedi SARL and Contributors. All Rights Reserved. +# +# 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 tarfile +import xml.parsers.expat +import xml.dom.minidom +from urllib import url2pathname + + +class BusinessTemplateInfo: + + def __init__(self, tar_path): + self.tar = tarfile.open(tar_path, 'r:gz') + self.setUp() + + def setUp(self): + self.title = '' + self.modules = {} + self.allowed_content_types = {} + self.actions = {} + + self.setUpTitle() + self.setUpModules() + self.setUpAllowedContentTypes() + self.setUpActions() + + def setUpTitle(self): + for tarinfo in self.tar.getmembers(): + if tarinfo.name.endswith('/bt/title'): + self.title = self.tar.extractfile(tarinfo).read() + + def setUpModules(self): + name = '%s/ModuleTemplateItem/' % self.title + for tarinfo in self.tar.getmembers(): + if tarinfo.name.startswith(name) and tarinfo.type==tarfile.REGTYPE: + source = self.tar.extractfile(tarinfo).read() + doc = xml.dom.minidom.parseString(source) + module_id = doc.getElementsByTagName('id')[0].childNodes[0].data + portal_type = doc.getElementsByTagName('portal_type')[0].childNodes[0].data + self.modules[module_id] = portal_type + + def setUpAllowedContentTypes(self): + name = '%s/PortalTypeAllowedContentTypeTemplateItem/allowed_content_types.xml' % self.title + try: + tarinfo = self.tar.getmember(name) + except KeyError: + return + source = self.tar.extractfile(tarinfo).read() + doc = xml.dom.minidom.parseString(source) + for portal_type_node in doc.getElementsByTagName('portal_type'): + portal_type = portal_type_node.getAttribute('id') + self.allowed_content_types[portal_type] = [] + for item in portal_type_node.getElementsByTagName('item'): + self.allowed_content_types[portal_type].append(item.childNodes[0].data) + + def setUpActions(self): + class Handler: + cur_key = None + old_tag = None + cur_tag = None + key_val = None + value_val = None + + def __init__(self): + self.data = {} + + def start(self, name, attrs): + if not name in ('item', 'key', 'value', 'string', 'int', 'float'): + return + self.old_tag = self.cur_tag + self.cur_tag = name + if name=='key': + self.cur_key = name + + def end(self, name): + self.cur_tag = None + if name=='item': + self.data[self.key_val] = self.value_val + self.cur_key = None + self.key_val = None + self.value_val = None + + def char(self, data): + if self.cur_tag in ('string', 'int', 'float'): + f = getattr(self, 'to%s' % self.cur_tag) + if self.old_tag=='key': + self.key_val = f(data) + elif self.old_tag=='value': + self.value_val = f(data) + + def tostring(self, value): + return str(value) + + def toint(self, value): + return int(value) + + def tofloat(self, value): + return float(value) + + def parse(source): + handler = Handler() + p = xml.parsers.expat.ParserCreate() + p.StartElementHandler = handler.start + p.EndElementHandler = handler.end + p.CharacterDataHandler = handler.char + p.Parse(source) + return handler.data + + name = '%s/ActionTemplateItem/portal_types/' % self.title + for tarinfo in self.tar.getmembers(): + if tarinfo.name.startswith(name) and tarinfo.type==tarfile.REGTYPE: + portal_type = url2pathname(tarinfo.name.split('/')[-2]) + if not portal_type in self.actions: + self.actions[portal_type] = [] + data = parse(self.tar.extractfile(tarinfo).read()) + self.actions[portal_type].append(data) -- 2.30.9