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

zopefoundation / Products.CMFCore / 6246931310

20 Sep 2023 09:54AM UTC coverage: 86.008% (-0.3%) from 86.266%
6246931310

Pull #131

github

mauritsvanrees
gha: don't need setup-python on 27 as we use the 27 container.
Pull Request #131: Make decodeFolderFilter and encodeFolderFilter non-public.

2466 of 3689 branches covered (0.0%)

Branch coverage included in aggregate %.

6 of 6 new or added lines in 1 file covered. (100.0%)

17297 of 19289 relevant lines covered (89.67%)

0.9 hits per line

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

93.85
/src/Products/CMFCore/tests/test_FSFile.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
""" Unit tests for FSFile module.
1✔
14
"""
15

16
import os
1✔
17
import unittest
1✔
18
import warnings
1✔
19

20
import six
1✔
21

22
from zope.component import getSiteManager
1✔
23
from zope.datetime import rfc1123_date
1✔
24
from zope.testing.cleanup import cleanUp
1✔
25

26
from ..interfaces import ICachingPolicyManager
1✔
27
from .base.dummy import FAKE_ETAG
1✔
28
from .base.dummy import DummyCachingManager
1✔
29
from .base.dummy import DummyCachingManagerWithPolicy
1✔
30
from .base.testcase import FSDVTest
1✔
31
from .base.testcase import TransactionalTest
1✔
32

33

34
class FSFileTests(TransactionalTest, FSDVTest):
1✔
35

36
    def setUp(self):
1✔
37
        TransactionalTest.setUp(self)
1✔
38
        FSDVTest.setUp(self)
1✔
39

40
    def tearDown(self):
1✔
41
        cleanUp()
1✔
42
        FSDVTest.tearDown(self)
1✔
43
        TransactionalTest.tearDown(self)
1✔
44

45
    def _makeOne(self, id, filename):
1✔
46
        from ..FSFile import FSFile
1✔
47
        from ..FSMetadata import FSMetadata
1✔
48

49
        full_path = os.path.join(self.skin_path_name, filename)
1✔
50
        metadata = FSMetadata(full_path)
1✔
51
        metadata.read()
1✔
52
        return FSFile(id, full_path, properties=metadata.getProperties())
1✔
53

54
    def _extractFile(self, filename):
1✔
55
        path = os.path.join(self.skin_path_name, filename)
1✔
56
        f = open(path, 'rb')
1✔
57
        try:
1✔
58
            data = f.read()
1✔
59
        finally:
60
            f.close()
1✔
61

62
        return path, data
1✔
63

64
    def test_ctor(self):
1✔
65
        _path, ref = self._extractFile('test_file.swf')
1✔
66

67
        file = self._makeOne('test_file', 'test_file.swf')
1✔
68
        file = file.__of__(self.app)
1✔
69

70
        self.assertEqual(file.get_size(), len(ref))
1✔
71
        self.assertEqual(file._readFile(0), ref)
1✔
72

73
    def test_bytes(self):
1✔
74
        _path, ref = self._extractFile('test_file.swf')
1✔
75
        file = self._makeOne('test_file', 'test_file.swf')
1✔
76
        file = file.__of__(self.app)
1✔
77
        self.assertEqual(len(bytes(file)), len(bytes(ref)))
1✔
78

79
    def test_str(self):
1✔
80
        from ZPublisher.HTTPRequest import default_encoding
1✔
81

82
        if six.PY2:
1!
83
            # This test only makes sense under Python 2. The file
84
            # being loaded is a binary string, which is what ``str``
85
            # under Python 2 returns. Under Python 3 this will lead
86
            # to a decoding attempt, which will fail or destroy the data.
87
            _path, ref = self._extractFile('test_file.swf')
×
88
            file = self._makeOne('test_file', 'test_file.swf')
×
89
            file = file.__of__(self.app)
×
90
            self.assertEqual(len(str(file)), len(str(ref)))
×
91

92
        encoded = b'Th\xc3\xaes \xc3\xaes s\xc3\xb6me t\xc3\xa9xt.'
1✔
93

94
        # This file contains UTF-8 text data
95
        file = self._makeOne('test_text', 'test_text.txt')
1✔
96
        data = str(file).strip()
1✔
97

98
        self.assertIsInstance(data, str)
1✔
99
        if six.PY2:
1!
100
            self.assertEqual(data, encoded)
×
101
        else:
102
            self.assertEqual(data, encoded.decode(default_encoding))
1✔
103

104
        # This file contains latin-1 test data
105
        file = self._makeOne('test_text', 'test_text_latin1.txt')
1✔
106
        data = str(file).strip()
1✔
107

108
        self.assertIsInstance(data, str)
1✔
109
        if six.PY2:
1!
110
            l1_data = encoded.decode(default_encoding).encode('latin-1')
×
111
            self.assertEqual(data, l1_data)
×
112
        else:
113
            self.assertEqual(data, encoded.decode(default_encoding))
1✔
114

115
        # This file contains non-text binary data
116
        file = self._makeOne('test_binary', 'test_image.gif')
1✔
117
        _path, real_data = self._extractFile('test_image.gif')
1✔
118

119
        self.assertIsInstance(data, str)
1✔
120
        if six.PY2:
1!
121
            self.assertEqual(str(file), real_data)
×
122
        else:
123
            # Calling ``__str__`` on non-text binary data in Python 3
124
            # will raise a DeprecationWarning because it makes no sense.
125
            # Ignore it here, the warning is irrelevant for the test.
126
            with warnings.catch_warnings():
1✔
127
                warnings.simplefilter('ignore')
1✔
128
                self.assertRaises(UnicodeDecodeError, file.__str__)
1✔
129

130
    def test_index_html(self):
1✔
131
        path, ref = self._extractFile('test_file.swf')
1✔
132
        mod_time = os.stat(path)[8]
1✔
133

134
        file = self._makeOne('test_file', 'test_file.swf')
1✔
135
        file = file.__of__(self.app)
1✔
136

137
        data = file.index_html(self.REQUEST, self.RESPONSE)
1✔
138

139
        self.assertEqual(len(data), len(ref))
1✔
140
        self.assertEqual(data, ref)
1✔
141
        # ICK!  'HTTPResponse.getHeader' doesn't case-flatten the key!
142
        self.assertEqual(self.RESPONSE.getHeader('Content-Length'.lower()),
1✔
143
                         str(len(ref)))
144
        self.assertEqual(self.RESPONSE.getHeader('Content-Type'.lower()),
1✔
145
                         'application/octet-stream')
146
        self.assertEqual(self.RESPONSE.getHeader('Last-Modified'.lower()),
1✔
147
                         rfc1123_date(mod_time))
148

149
    def test_index_html_with_304(self):
1✔
150
        path, _ref = self._extractFile('test_file.swf')
1✔
151
        mod_time = os.stat(path)[8]
1✔
152

153
        file = self._makeOne('test_file', 'test_file.swf')
1✔
154
        file = file.__of__(self.app)
1✔
155

156
        self.REQUEST.environ['IF_MODIFIED_SINCE'] = '%s;' % \
1✔
157
            rfc1123_date(mod_time + 3600)
158

159
        data = file.index_html(self.REQUEST, self.RESPONSE)
1✔
160

161
        self.assertEqual(data, '')
1✔
162
        # test that we don't supply a content-length
163
        self.assertEqual(self.RESPONSE.getHeader('Content-Length'.lower()),
1✔
164
                         None)
165
        self.assertEqual(self.RESPONSE.getStatus(), 304)
1✔
166

167
    def test_index_html_without_304(self):
1✔
168
        path, _ref = self._extractFile('test_file.swf')
1✔
169
        mod_time = os.stat(path)[8]
1✔
170

171
        file = self._makeOne('test_file', 'test_file.swf')
1✔
172
        file = file.__of__(self.app)
1✔
173

174
        self.REQUEST.environ['IF_MODIFIED_SINCE'] = '%s;' % \
1✔
175
            rfc1123_date(mod_time - 3600)
176

177
        data = file.index_html(self.REQUEST, self.RESPONSE)
1✔
178

179
        self.assertTrue(data, '')
1✔
180
        self.assertEqual(self.RESPONSE.getStatus(), 200)
1✔
181

182
    def test_index_html_with_304_from_cpm(self):
1✔
183
        cpm = DummyCachingManagerWithPolicy()
1✔
184
        getSiteManager().registerUtility(cpm, ICachingPolicyManager)
1✔
185
        path, _ref = self._extractFile('test_file.swf')
1✔
186
        file = self._makeOne('test_file', 'test_file.swf')
1✔
187
        file = file.__of__(self.app)
1✔
188

189
        mod_time = os.stat(path).st_mtime
1✔
190

191
        self.REQUEST.environ['IF_MODIFIED_SINCE'] = '%s;' % \
1✔
192
            rfc1123_date(mod_time)
193

194
        self.REQUEST.environ['IF_NONE_MATCH'] = '%s;' % FAKE_ETAG
1✔
195

196
        data = file.index_html(self.REQUEST, self.RESPONSE)
1✔
197
        self.assertEqual(len(data), 0)
1✔
198
        self.assertEqual(self.RESPONSE.getStatus(), 304)
1✔
199
        self.assertNotEqual(self.RESPONSE.getHeader('x-cache-headers-set-by'),
1✔
200
                            None)
201

202
    def test_index_html_200_with_cpm(self):
1✔
203
        # should behave the same as without cpm installed
204
        cpm = DummyCachingManagerWithPolicy()
1✔
205
        getSiteManager().registerUtility(cpm, ICachingPolicyManager)
1✔
206
        path, ref = self._extractFile('test_file.swf')
1✔
207
        file = self._makeOne('test_file', 'test_file.swf')
1✔
208
        file = file.__of__(self.app)
1✔
209

210
        mod_time = os.stat(path).st_mtime
1✔
211

212
        data = file.index_html(self.REQUEST, self.RESPONSE)
1✔
213

214
        self.assertEqual(len(data), len(ref))
1✔
215
        self.assertEqual(data, ref)
1✔
216
        # ICK!  'HTTPResponse.getHeader' doesn't case-flatten the key!
217
        self.assertEqual(self.RESPONSE.getHeader('Content-Length'.lower()),
1✔
218
                         str(len(ref)))
219
        self.assertEqual(self.RESPONSE.getHeader('Content-Type'.lower()),
1✔
220
                         'application/octet-stream')
221
        self.assertEqual(self.RESPONSE.getHeader('Last-Modified'.lower()),
1✔
222
                         rfc1123_date(mod_time))
223

224
    def test_caching(self):
1✔
225
        cpm = DummyCachingManager()
1✔
226
        getSiteManager().registerUtility(cpm, ICachingPolicyManager)
1✔
227
        original_len = len(self.RESPONSE.headers)
1✔
228
        obj = self._makeOne('test_file', 'test_file.swf')
1✔
229
        obj = obj.__of__(self.app)
1✔
230
        obj.index_html(self.REQUEST, self.RESPONSE)
1✔
231
        headers = self.RESPONSE.headers
1✔
232
        self.assertTrue(len(headers) >= original_len + 3)
1✔
233
        self.assertTrue('foo' in headers)
1✔
234
        self.assertTrue('bar' in headers)
1✔
235
        self.assertEqual(headers['test_path'], '/test_file')
1✔
236

237
    def test_forced_content_type(self):
1✔
238
        path, ref = self._extractFile('test_file_two.swf')
1✔
239
        mod_time = os.stat(path)[8]
1✔
240

241
        file = self._makeOne('test_file', 'test_file_two.swf')
1✔
242
        file = file.__of__(self.app)
1✔
243

244
        data = file.index_html(self.REQUEST, self.RESPONSE)
1✔
245

246
        self.assertEqual(len(data), len(ref))
1✔
247
        self.assertEqual(data, ref)
1✔
248
        # ICK!  'HTTPResponse.getHeader' doesn't case-flatten the key!
249
        self.assertEqual(self.RESPONSE.getHeader('Content-Length'.lower()),
1✔
250
                         str(len(ref)))
251
        self.assertEqual(self.RESPONSE.getHeader('Content-Type'.lower()),
1✔
252
                         'application/x-shockwave-flash')
253
        self.assertEqual(self.RESPONSE.getHeader('Last-Modified'.lower()),
1✔
254
                         rfc1123_date(mod_time))
255

256
    def test_utf8charset_detection(self):
1✔
257
        import mimetypes
1✔
258

259
        file_name = 'testUtf8.js'
1✔
260
        mtype, _ignore_enc = mimetypes.guess_type(file_name)
1✔
261
        file = self._makeOne(file_name, file_name)
1✔
262
        file = file.__of__(self.app)
1✔
263
        file.index_html(self.REQUEST, self.RESPONSE)
1✔
264
        self.assertEqual(self.RESPONSE.getHeader('content-type'),
1✔
265
                         '%s; charset=utf-8' % mtype)
266

267
    def test_unnecessary_invalidation_avoidance(self):
1✔
268
        # See https://bugs.launchpad.net/zope-cmf/+bug/325246
269
        invalidated = []
1✔
270

271
        def fake_invalidate(*args, **kw):
1✔
272
            invalidated.append(True)
1✔
273

274
        file = self._makeOne('test_file', 'test_file.swf')
1✔
275
        file.ZCacheable_invalidate = fake_invalidate
1✔
276

277
        # First pass: The internal file modification representation
278
        # equals the filesystem modification time.
279
        del invalidated[:]
1✔
280
        file._readFile(True)
1✔
281
        self.assertFalse(invalidated)
1✔
282

283
        del invalidated[:]
1✔
284
        file._parsed = False
1✔
285
        file._updateFromFS()
1✔
286
        self.assertFalse(invalidated)
1✔
287

288
        # Second pass: Forcing a different internal file modification
289
        # time onto the instance. Now the file will be invalidated.
290
        del invalidated[:]
1✔
291
        file._file_mod_time = 0
1✔
292
        file._readFile(True)
1✔
293
        self.assertTrue(invalidated)
1✔
294

295
        del invalidated[:]
1✔
296
        file._file_mod_time = 0
1✔
297
        file._parsed = False
1✔
298
        file._updateFromFS()
1✔
299
        self.assertTrue(invalidated)
1✔
300

301

302
def test_suite():
1✔
303
    return unittest.TestSuite((
1✔
304
        unittest.makeSuite(FSFileTests),
305
        ))
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