Back to index

plone3  3.1.7
test_interfaces.py
Go to the documentation of this file.
00001 ################################################################################
00002 #
00003 # Copyright (c) 2002-2005, Benjamin Saller <bcsaller@ideasuite.com>, and
00004 #                              the respective authors. All rights reserved.
00005 # For a list of Archetypes contributors see docs/CREDITS.txt.
00006 #
00007 # Redistribution and use in source and binary forms, with or without
00008 # modification, are permitted provided that the following conditions are met:
00009 #
00010 # * Redistributions of source code must retain the above copyright notice, this
00011 #   list of conditions and the following disclaimer.
00012 # * Redistributions in binary form must reproduce the above copyright notice,
00013 #   this list of conditions and the following disclaimer in the documentation
00014 #   and/or other materials provided with the distribution.
00015 # * Neither the name of the author nor the names of its contributors may be used
00016 #   to endorse or promote products derived from this software without specific
00017 #   prior written permission.
00018 #
00019 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
00020 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
00022 # FOR A PARTICULAR PURPOSE.
00023 #
00024 ################################################################################
00025 
00026 # @@ auto generating tests is bullshit. this should go somewhere more
00027 # easily auditable, like doctests.  DWM
00028 
00029 from Testing import ZopeTestCase
00030 
00031 from Products.Archetypes.tests.atsitetestcase import ATSiteTestCase
00032 
00033 from Interface.Implements import getImplementsOfInstances
00034 from Interface.Implements import getImplements
00035 from Interface.Implements import flattenInterfaces
00036 from Interface.Verify import verifyClass, verifyObject
00037 from Interface.Exceptions import BrokenImplementation
00038 from Interface.Exceptions import DoesNotImplement
00039 from Interface.Exceptions import BrokenMethodImplementation
00040 
00041 from Products.Archetypes.interfaces.base import *
00042 from Products.Archetypes.interfaces.field import *
00043 from Products.Archetypes.interfaces.layer import *
00044 from Products.Archetypes.interfaces.marshall import *
00045 from Products.Archetypes.interfaces.metadata import *
00046 from Products.Archetypes.interfaces.orderedfolder import *
00047 from Products.Archetypes.interfaces.referenceable import *
00048 from Products.Archetypes.interfaces.storage import *
00049 
00050 from Products.Archetypes.BaseObject import BaseObject
00051 from Products.Archetypes.BaseContent import BaseContent
00052 from Products.Archetypes.BaseFolder import BaseFolder
00053 from Products.Archetypes.BaseUnit import BaseUnit
00054 from Products.Archetypes import Field as at_field# use __all__ field
00055 from Products.Archetypes.Marshall import Marshaller, PrimaryFieldMarshaller, \
00056     RFC822Marshaller
00057 from Products.Archetypes.OrderedBaseFolder import OrderedBaseFolder
00058 from Products.Archetypes.Schema import Schema
00059 from Products.Archetypes.SQLStorage import BaseSQLStorage, GadflySQLStorage, \
00060     MySQLSQLStorage, PostgreSQLStorage
00061 from Products.Archetypes.Storage import Storage, ReadOnlyStorage, \
00062     StorageLayer, AttributeStorage, ObjectManagedStorage, MetadataStorage
00063 from Products.Archetypes.atapi import registerType
00064 from Products.PloneTestCase.layer import ZCMLLayer
00065 
00066 def className(klass):
00067     """ get the short class name """
00068     # remove <>
00069     name = str(klass)[1:-1]
00070     return name.split('.')[-1].split(' ')[0]
00071 
00072 # list of tests
00073 tests = []
00074 
00075 class InterfaceTest(ZopeTestCase.ZopeTestCase):
00076     """general interface testing class
00077 
00078     klass - the class object to test
00079     forcedImpl - a list of interface class objects that the class klass
00080         *must* implement to fullfil this test
00081 
00082     This test class doesn't implement a test* method so you have to provide
00083     a test method in your implementation. See above for two examples. One
00084     example uses the special magic of setattr::
00085 
00086         setattr(MyClass, MyMethodName, lambda self: self._testStuff())
00087 
00088     """
00089     layer = ZCMLLayer
00090     klass = None    # test this class
00091     instance = None # test this instance
00092     forcedImpl = () # class must implement this tuple of interfaces
00093 
00094     def interfaceImplementedByInstanceOf(self, klass, interface):
00095         """ tests if the klass implements the interface in the right way """
00096         # is the class really implemented by the given interface?
00097         self.failUnless(interface.isImplementedByInstancesOf(klass),
00098             'The class %s does not implement %s' % (className(klass), className(interface)))
00099         # verify if the implementation is correct
00100         try:
00101             verifyClass(interface, klass)
00102         except (BrokenImplementation, DoesNotImplement,
00103           BrokenMethodImplementation), errmsg:
00104             self.fail('The class %s does not implement %s correctly: \n%s'
00105                 % (className(klass), className(interface), errmsg))
00106 
00107     def interfaceImplementedBy(self, instance, interface):        
00108         """ tests if the instance implements the interface in the right way """
00109         # is the class really implemented by the given interface?
00110         self.failUnless(interface.isImplementedBy(instance),
00111             'The instance of %s does not implement %s' % (className(instance), className(interface)))
00112         # verify if the implementation is correct
00113         try:
00114             verifyObject(interface, instance)
00115         except (BrokenImplementation, DoesNotImplement,
00116           BrokenMethodImplementation), errmsg:
00117             self.fail('The instance of %s does not implement %s correctly: \n%s'
00118                 % (className(instance), className(interface), errmsg))
00119 
00120     def getImplementsOfInstanceOf(self, klass):
00121         """ returns the interfaces implemented by the klass (flat)"""
00122         impl = getImplementsOfInstances(klass)
00123         if not isinstance(impl, tuple):
00124             impl = (impl,)
00125         if impl:
00126             return flattenInterfaces(impl)
00127 
00128     def getImplementsOf(self, instance):
00129         """ returns the interfaces implemented by the instance (flat)"""
00130         impl = getImplements(instance)
00131         if not isinstance(impl, tuple):
00132             impl = (impl,)
00133         if impl:
00134             return flattenInterfaces(impl)
00135 
00136     def doesImplementByInstanceOf(self, klass, interfaces):
00137         """ make shure that the klass implements at least these interfaces"""
00138         if not isinstance(interfaces, tuple):
00139             interfaces = (interfaces)
00140         impl = self.getImplementsOfInstanceOf(klass)
00141         for interface in interfaces:
00142             self.failUnless(interface in impl, 'The class %s does not implement %s' % (className(klass), className(interface)))
00143 
00144     def doesImplementBy(self, instance, interfaces):
00145         """ make shure that the klass implements at least these interfaces"""
00146         if not isinstance(interfaces, tuple):
00147             interfaces = (interfaces)
00148         impl = self.getImplementsOf(instance)
00149         for interface in interfaces:
00150             self.failUnless(interface in impl, 'The instance of %s does not implement %s' % (className(instance), className(interface)))
00151 
00152     def _testStuff(self):
00153         """ test self.klass and self.instance """
00154         if self.klass:
00155             if self.forcedImpl:
00156                 self.doesImplementByInstanceOf(self.klass, self.forcedImpl)
00157             for iface in self.getImplementsOfInstanceOf(self.klass):
00158                 self.interfaceImplementedByInstanceOf(self.klass, iface)
00159         if self.instance:
00160             if self.forcedImpl:
00161                 self.doesImplementBy(self.instance, self.forcedImpl)
00162             for iface in self.getImplementsOf(self.instance):
00163                 self.interfaceImplementedBy(self.instance, iface)
00164 
00165 ###############################################################################
00166 ###                         testing starts here                             ###
00167 ###############################################################################
00168 
00169 class FieldInterfaceTest(InterfaceTest):
00170     """ test all field classes from Field.Field.__all__"""
00171 
00172     klass = at_field.Field # not used but set to class Field
00173     forcedImpl = ()
00174 
00175     def testFieldInterface(self):
00176        for fieldname in at_field.__all__:
00177             klass = getattr(at_field, fieldname)
00178             instance = klass()
00179             self.doesImplementByInstanceOf(klass, self.forcedImpl)
00180             for iface in self.getImplementsOf(instance):
00181                 self.interfaceImplementedBy(instance, iface)
00182 
00183 tests.append(FieldInterfaceTest)
00184 
00185 # format: (class object, (list interface objects))
00186 testClasses = [
00187     (BaseObject, ()),
00188     (BaseUnit, ()),
00189     (Marshaller, ()), (PrimaryFieldMarshaller, ()), (RFC822Marshaller, ()),
00190     (Schema, ()),
00191     (Storage, ()), (ReadOnlyStorage, ()), (StorageLayer, ()),
00192         (AttributeStorage, ()), (ObjectManagedStorage, ()),
00193         (MetadataStorage, ()),
00194     (BaseSQLStorage, ()), (GadflySQLStorage, ()), (MySQLSQLStorage, ()),
00195         (PostgreSQLStorage, ()),
00196 ]
00197 
00198 PROJECTNAME = 'Archetypes.tests'
00199 #class EM(ExtensibleMetadata): pass
00200 #registerType(EM, PROJECTNAME)
00201 class BC(BaseContent): pass
00202 registerType(BC, PROJECTNAME)
00203 class BF(BaseFolder): pass
00204 registerType(BF, PROJECTNAME)
00205 class OBF(OrderedBaseFolder): pass
00206 registerType(OBF, PROJECTNAME)
00207 
00208 # format: (instance object, (list interface objects))
00209 # take care: you must provide an instance, not a class!
00210 def make_test_instances():
00211     return [
00212         # (EM(), ()), XXX See comment on ExtensibleMetadata
00213         (BC('test'), ()),
00214         (BF('test'), ()),
00215         (OBF('test'), ()),
00216         ]
00217 
00218 # @@ so inefficient
00219 from Products.PloneTestCase.utils import safe_load_site_wrapper
00220 testInstances = safe_load_site_wrapper(make_test_instances)()
00221 
00222 for testClass in testClasses:
00223     klass, forcedImpl = testClass
00224     name = className(klass)
00225     funcName = 'test%sInterface' % name
00226 
00227     class KlassInterfaceTest(InterfaceTest):
00228         """ implementation for %s """ % name
00229         klass      = klass
00230         forcedImpl = forcedImpl
00231         layer = ZCMLLayer
00232 
00233     # add the testing method to the class to get a nice name
00234     setattr(KlassInterfaceTest, funcName, lambda self: self._testStuff())
00235     tests.append(KlassInterfaceTest)
00236 
00237 for testInstance in testInstances:
00238     instance, forcedImpl = testInstance
00239     name = className(instance)
00240     funcName = 'test%sInterface' % name
00241 
00242     class InstanceInterfaceTest(InterfaceTest):
00243         """ implementation for %s """ % name
00244         instance   = instance
00245         forcedImpl = forcedImpl
00246         layer = ZCMLLayer
00247 
00248     # add the testing method to the class to get a nice name
00249     setattr(InstanceInterfaceTest, funcName, lambda self: self._testStuff())
00250     tests.append(InstanceInterfaceTest)
00251 
00252 
00253 def test_suite():
00254     from unittest import TestSuite, makeSuite
00255     suite = TestSuite()
00256     for test in tests:
00257         suite.addTest(makeSuite(test))
00258     return suite