• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

zopefoundation / Zope / 3956162881

pending completion
3956162881

push

github

Michael Howitz
Update to deprecation warning free releases.

4401 of 7036 branches covered (62.55%)

Branch coverage included in aggregate %.

27161 of 31488 relevant lines covered (86.26%)

0.86 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.15
/src/Products/PageTemplates/tests/testHTMLTests.py
1
##############################################################################
2
#
3
# Copyright (c) 2002 Zope Foundation and Contributors.
4
#
5
# This software is subject to the provisions of the Zope Public License,
6
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
7
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
8
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
9
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
10
# FOR A PARTICULAR PURPOSE
11
#
12
##############################################################################
13

14
import unittest
1✔
15

16
from chameleon.exc import ExpressionError
1✔
17

18
import zope.component.testing
1✔
19
from AccessControl import SecurityManager
1✔
20
from AccessControl.SecurityManagement import noSecurityManager
1✔
21
from Acquisition import Implicit
1✔
22
from Products.PageTemplates.interfaces import IUnicodeEncodingConflictResolver
1✔
23
from Products.PageTemplates.PageTemplate import PageTemplate
1✔
24
from Products.PageTemplates.tests import util
1✔
25
from Products.PageTemplates.unicodeconflictresolver import \
1✔
26
    DefaultUnicodeEncodingConflictResolver
27
from Products.PageTemplates.unicodeconflictresolver import \
1✔
28
    PreferredCharsetResolver
29
from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
1✔
30
from zExceptions import NotFound
1✔
31
from zope.component import provideUtility
1✔
32
from zope.location.interfaces import LocationError
1✔
33
from zope.traversing.adapters import DefaultTraversable
1✔
34

35
from .util import useChameleonEngine
1✔
36

37

38
class AqPageTemplate(Implicit, PageTemplate):
1✔
39
    pass
1✔
40

41

42
class AqZopePageTemplate(Implicit, ZopePageTemplate):
1✔
43
    pass
1✔
44

45

46
class Folder(util.Base):
1✔
47
    pass
1✔
48

49

50
class UnitTestSecurityPolicy:
1✔
51
    """
52
        Stub out the existing security policy for unit testing purposes.
53
    """
54
    # Standard SecurityPolicy interface
55
    def validate(self,
1✔
56
                 accessed=None,
57
                 container=None,
58
                 name=None,
59
                 value=None,
60
                 context=None,
61
                 roles=None,
62
                 *args, **kw):
63
        return 1
1✔
64

65
    def checkPermission(self, permission, object, context):
1✔
66
        return 1
×
67

68

69
class HTMLTests(zope.component.testing.PlacelessSetup, unittest.TestCase):
1✔
70
    PREFIX = None
1✔
71

72
    def setUp(self):
1✔
73
        super().setUp()
1✔
74
        useChameleonEngine()
1✔
75
        zope.component.provideAdapter(DefaultTraversable, (None,))
1✔
76

77
        provideUtility(DefaultUnicodeEncodingConflictResolver,
1✔
78
                       IUnicodeEncodingConflictResolver)
79

80
        self.folder = f = Folder()
1✔
81
        f.laf = AqPageTemplate()
1✔
82
        f.t = AqPageTemplate()
1✔
83
        f.z = AqZopePageTemplate('testing')
1✔
84
        self.policy = UnitTestSecurityPolicy()
1✔
85
        self.oldPolicy = SecurityManager.setSecurityPolicy(self.policy)
1✔
86
        noSecurityManager()  # Use the new policy.
1✔
87

88
    def tearDown(self):
1✔
89
        super().tearDown()
1✔
90
        SecurityManager.setSecurityPolicy(self.oldPolicy)
1✔
91
        noSecurityManager()  # Reset to old policy.
1✔
92

93
    def assert_expected(self, t, fname, *args, **kwargs):
1✔
94
        t.write(util.read_input(fname))
1✔
95
        assert not t._v_errors, 'Template errors: %s' % t._v_errors
1✔
96
        if self.PREFIX is not None \
1✔
97
                and util.exists_output(self.PREFIX + fname):
98
            fname = self.PREFIX + fname
1✔
99
        expect = util.read_output(fname)
1✔
100
        out = t(*args, **kwargs)
1✔
101
        util.check_html(expect, out)
1✔
102

103
    def assert_expected_unicode(self, t, fname, *args, **kwargs):
1✔
104
        t.write(util.read_input(fname))
1✔
105
        assert not t._v_errors, 'Template errors: %s' % t._v_errors
1✔
106
        expect = util.read_output(fname)
1✔
107
        if not isinstance(expect, str):
1!
108
            expect = str(expect, 'utf-8')
×
109
        out = t(*args, **kwargs)
1✔
110
        util.check_html(expect, out)
1✔
111

112
    def getProducts(self):
1✔
113
        return [
1✔
114
            {'description': 'This is the tee for those who LOVE Zope. '
115
             'Show your heart on your tee.',
116
             'price': 12.99, 'image': 'smlatee.jpg'
117
             },
118
            {'description': 'This is the tee for Jim Fulton. '
119
             'He\'s the Zope Pope!',
120
             'price': 11.99, 'image': 'smpztee.jpg'
121
             },
122
        ]
123

124
    def test_1(self):
1✔
125
        self.assert_expected(self.folder.laf, 'TeeShopLAF.html')
1✔
126

127
    def test_2(self):
1✔
128
        self.folder.laf.write(util.read_input('TeeShopLAF.html'))
1✔
129

130
        self.assert_expected(self.folder.t, 'TeeShop2.html',
1✔
131
                             getProducts=self.getProducts)
132

133
    def test_3(self):
1✔
134
        self.folder.laf.write(util.read_input('TeeShopLAF.html'))
1✔
135

136
        self.assert_expected(self.folder.t, 'TeeShop1.html',
1✔
137
                             getProducts=self.getProducts)
138

139
    def testSimpleLoop(self):
1✔
140
        self.assert_expected(self.folder.t, 'Loop1.html')
1✔
141

142
    def testFancyLoop(self):
1✔
143
        self.assert_expected(self.folder.t, 'Loop2.html')
1✔
144

145
    def testGlobalsShadowLocals(self):
1✔
146
        self.assert_expected(self.folder.t, 'GlobalsShadowLocals.html')
1✔
147

148
    def testStringExpressions(self):
1✔
149
        self.assert_expected(self.folder.t, 'StringExpression.html')
1✔
150

151
    def testReplaceWithNothing(self):
1✔
152
        self.assert_expected(self.folder.t, 'CheckNothing.html')
1✔
153

154
    def testWithXMLHeader(self):
1✔
155
        self.assert_expected(self.folder.t, 'CheckWithXMLHeader.html')
1✔
156

157
    def testNotExpression(self):
1✔
158
        self.assert_expected(self.folder.t, 'CheckNotExpression.html')
1✔
159

160
    def testPathNothing(self):
1✔
161
        self.assert_expected(self.folder.t, 'CheckPathNothing.html')
1✔
162

163
    def testPathAlt(self):
1✔
164
        self.assert_expected(self.folder.t, 'CheckPathAlt.html')
1✔
165

166
    def testPathTraverse(self):
1✔
167
        # need to perform this test with a "real" folder
168
        from OFS.Folder import Folder
1✔
169
        f = self.folder
1✔
170
        self.folder = Folder()
1✔
171
        self.folder.t, self.folder.laf = f.t, f.laf
1✔
172
        self.folder.laf.write('ok')
1✔
173
        self.assert_expected(self.folder.t, 'CheckPathTraverse.html')
1✔
174

175
    def testBatchIteration(self):
1✔
176
        self.assert_expected(self.folder.t, 'CheckBatchIteration.html')
1✔
177

178
    def testUnicodeInserts(self):
1✔
179
        self.assert_expected_unicode(self.folder.t, 'CheckUnicodeInserts.html')
1✔
180

181
    def testI18nTranslate(self):
1✔
182
        self.assert_expected(self.folder.t, 'CheckI18nTranslate.html')
1✔
183

184
    def testImportOldStyleClass(self):
1✔
185
        self.assert_expected(self.folder.t, 'CheckImportOldStyleClass.html')
1✔
186

187
    def testRepeatVariable(self):
1✔
188
        self.assert_expected(self.folder.t, 'RepeatVariable.html')
1✔
189

190
    def testBooleanAttributes(self):
1✔
191
        # Test rendering an attribute that should be empty or left out
192
        # if the value is non-True
193
        self.assert_expected(self.folder.t, 'BooleanAttributes.html')
1✔
194

195
    def testBooleanAttributesAndDefault(self):
1✔
196
        # Zope 2.9 and below support the semantics that an HTML
197
        # "boolean" attribute (e.g. 'selected', 'disabled', etc.) can
198
        # be used together with 'default'.
199
        self.assert_expected(self.folder.t, 'BooleanAttributesAndDefault.html')
1✔
200

201
    def testInterpolationInContent(self):
1✔
202
        # the chameleon template engine supports ``${path}``
203
        # interpolations not only as part of ``string`` expressions
204
        # but globally
205
        self.assert_expected(self.folder.t, 'InterpolationInContent.html')
1✔
206

207
    def testBadExpression(self):
1✔
208
        t = self.folder.t
1✔
209
        t.write("<p tal:define='p a//b' />")
1✔
210
        with self.assertRaises(ExpressionError):
1✔
211
            t()
1✔
212

213
    def testPathAlternativesWithSpaces(self):
1✔
214
        self.assert_expected(self.folder.t, 'PathAlternativesWithSpaces.html')
1✔
215

216
    def testDefaultKeywordHandling(self):
1✔
217
        self.assert_expected(self.folder.t, 'Default.html')
1✔
218

219
    def testSwitch(self):
1✔
220
        self.assert_expected(self.folder.t, 'switch.html')
1✔
221

222
    def test_unicode_conflict_resolution(self):
1✔
223
        # override with the more "demanding" resolver
224
        provideUtility(PreferredCharsetResolver)
1✔
225
        t = PageTemplate()
1✔
226
        self.assert_expected(t, 'UnicodeResolution.html')
1✔
227

228
    def test_underscore_traversal(self):
1✔
229
        t = self.folder.t
1✔
230

231
        t.write('<p tal:define="p context/__class__" />')
1✔
232
        with self.assertRaises(NotFound):
1✔
233
            t()
1✔
234

235
        t.write('<p tal:define="p nocall: random/_itertools/repeat"/>')
1✔
236
        with self.assertRaises((NotFound, LocationError)):
1✔
237
            t()
1✔
238

239
        t.write('<p tal:content="random/_itertools/repeat/foobar"/>')
1✔
240
        with self.assertRaises((NotFound, LocationError)):
1✔
241
            t()
1✔
242

243
    def test_module_traversal(self):
1✔
244
        t = self.folder.z
1✔
245

246
        # Need to reset to the standard security policy so AccessControl
247
        # checks are actually performed. The test setup initializes
248
        # a policy that circumvents those checks.
249
        SecurityManager.setSecurityPolicy(self.oldPolicy)
1✔
250
        noSecurityManager()
1✔
251

252
        # The getSecurityManager function is explicitly allowed
253
        content = ('<p tal:define="a nocall:%s"'
1✔
254
                   '   tal:content="python: a().getUser().getUserName()"/>')
255
        t.write(content % 'modules/AccessControl/getSecurityManager')
1✔
256
        self.assertEqual(t(), '<p>Anonymous User</p>')
1✔
257

258
        # Anything else should be unreachable and raise NotFound:
259
        # Direct access through AccessControl
260
        t.write('<p tal:define="a nocall:modules/AccessControl/users"/>')
1✔
261
        with self.assertRaises(NotFound):
1✔
262
            t()
1✔
263

264
        # Indirect access through an intermediary variable
265
        content = ('<p tal:define="mod nocall:modules/AccessControl;'
1✔
266
                   '               must_fail nocall:mod/users"/>')
267
        t.write(content)
1✔
268
        with self.assertRaises(NotFound):
1✔
269
            t()
1✔
270

271
        # Indirect access through an intermediary variable and a dictionary
272
        content = ('<p tal:define="mod nocall:modules/AccessControl;'
1✔
273
                   '               a_dict python: {\'unsafe\': mod};'
274
                   '               must_fail nocall: a_dict/unsafe/users"/>')
275
        t.write(content)
1✔
276
        with self.assertRaises(NotFound):
1✔
277
            t()
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc