source: main/waeup.kofa/trunk/src/waeup/kofa/utils/tests/test_helpers.py @ 9372

Last change on this file since 9372 was 9372, checked in by uli, 12 years ago

Add a helper to provide a (Python 3 compatible) product calculator for sequences of numbers.

  • Property svn:keywords set to Id
File size: 16.7 KB
Line 
1# -*- coding: utf-8 -*-
2
3## $Id: test_helpers.py 9372 2012-10-21 10:43:54Z uli $
4##
5## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
6## This program is free software; you can redistribute it and/or modify
7## it under the terms of the GNU General Public License as published by
8## the Free Software Foundation; either version 2 of the License, or
9## (at your option) any later version.
10##
11## This program is distributed in the hope that it will be useful,
12## but WITHOUT ANY WARRANTY; without even the implied warranty of
13## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14## GNU General Public License for more details.
15##
16## You should have received a copy of the GNU General Public License
17## along with this program; if not, write to the Free Software
18## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19##
20
21import datetime
22import os
23import pytz
24import shutil
25import tempfile
26import unittest
27import doctest
28from cStringIO import StringIO
29from zope import schema
30from zope.interface import Interface, Attribute, implements
31from zope.security.testing import Principal, Participation
32from zope.security.management import newInteraction, endInteraction
33from waeup.kofa.utils import helpers
34
35class IFakeObject(Interface):
36    """Some marker interface."""
37
38class FakeObject(object):
39    implements(IFakeObject)
40
41class SimpleHelpersTestCase(unittest.TestCase):
42    # Tests for simple functions in `helpers`.
43    def test_product(self):
44        # the product will return zero without input
45        result1 = helpers.product([])
46        result2 = helpers.product([1,2,3])
47        result3 = helpers.product([], start=5)
48        result4 = helpers.product([1,2,3], start=5)
49        self.assertEqual(result1, 0)
50        self.assertEqual(result2, 6)
51        self.assertEqual(result3, 0)
52        self.assertEqual(result4, 30)
53        return
54
55class RemoveFileOrDirectoryTestCase(unittest.TestCase):
56
57    def setUp(self):
58        self.dirpath = tempfile.mkdtemp()
59        self.filepath = os.path.join(self.dirpath, 'somefile')
60        self.non_file = os.path.join(self.dirpath, 'nonfile')
61        open(self.filepath, 'wb').write('Hi!')
62        return
63
64    def tearDown(self):
65        if os.path.exists(self.dirpath):
66            shutil.rmtree(self.dirpath)
67        return
68
69    def test_handle_not_existing_path(self):
70        result = helpers.remove_file_or_directory(self.non_file)
71        self.assertTrue(result is None)
72        return
73
74    def test_handle_dir(self):
75        helpers.remove_file_or_directory(self.dirpath)
76        self.assertFalse(
77            os.path.exists(self.dirpath)
78            )
79        return
80
81    def test_handle_file(self):
82        helpers.remove_file_or_directory(self.filepath)
83        self.assertFalse(
84            os.path.exists(self.filepath)
85            )
86        return
87
88class CopyFileSystemTreeTestCase(unittest.TestCase):
89    # Test edge cases of copy_filesystem_tree().
90    #
91    # This is a typical case of tests not written as doctest as it is
92    # normally not interesting for developers and we only want to make
93    # sure everything works as expected.
94    def setUp(self):
95        self.existing_src = tempfile.mkdtemp()
96        self.filepath = os.path.join(self.existing_src, 'somefile')
97        open(self.filepath, 'wb').write('Hi!')
98        self.existing_dst = tempfile.mkdtemp()
99        self.not_existing_dir = tempfile.mkdtemp()
100        shutil.rmtree(self.not_existing_dir)
101
102        pass
103
104    def tearDown(self):
105        shutil.rmtree(self.existing_src)
106        shutil.rmtree(self.existing_dst)
107        pass
108
109    def test_source_and_dst_existing(self):
110        helpers.copy_filesystem_tree(self.existing_src, self.existing_dst)
111        self.assertTrue(
112            os.path.exists(
113                os.path.join(self.existing_dst, 'somefile')
114                )
115            )
116        return
117
118    def test_source_not_existing(self):
119        self.assertRaises(
120            ValueError,
121            helpers.copy_filesystem_tree,
122            self.not_existing_dir,
123            self.existing_dst
124            )
125        return
126
127    def test_dest_not_existing(self):
128        self.assertRaises(
129            ValueError,
130            helpers.copy_filesystem_tree,
131            self.existing_src,
132            self.not_existing_dir
133            )
134        return
135
136    def test_src_not_a_dir(self):
137        self.assertRaises(
138            ValueError,
139            helpers.copy_filesystem_tree,
140            self.filepath,
141            self.existing_dst
142            )
143        return
144
145    def test_dst_not_a_dir(self):
146        self.assertRaises(
147            ValueError,
148            helpers.copy_filesystem_tree,
149            self.existing_src,
150            self.filepath
151            )
152        return
153
154class ReST2HTMLTestCase(unittest.TestCase):
155
156    def setUp(self):
157        self.expected = u'<div class="document">\n\n\n<p>Some '
158        self.expected += u'test with \xfcmlaut</p>\n</div>'
159        return
160
161    def test_ascii_umlauts(self):
162        # Make sure we convert umlauts correctly to unicode.
163        source = 'Some test with ümlaut'
164        result = helpers.ReST2HTML(source)
165        self.assertEqual(result, self.expected)
166
167    def test_unicode_umlauts(self):
168        # Make sure we convert umlauts correctly to unicode.
169        source = u'Some test with ümlaut'
170        result = helpers.ReST2HTML(source)
171        self.assertEqual(result, self.expected)
172
173    def test_unicode_output_from_ascii(self):
174        source = 'Some test with ümlaut'
175        self.assertTrue(isinstance(helpers.ReST2HTML(source), unicode))
176
177    def test_unicode_output_from_unicode(self):
178        source = u'Some test with ümlaut'
179        self.assertTrue(isinstance(helpers.ReST2HTML(source), unicode))
180
181
182class FactoryBaseTestCase(unittest.TestCase):
183
184    def test_ifaces(self):
185        # We test all relevant parts in the docstring. But the interfaces
186        # method has to be tested to please the coverage report as well.
187        factory = helpers.FactoryBase()
188        factory.factory = FakeObject
189        self.assertTrue(factory.getInterfaces()(IFakeObject))
190        return
191
192class CurrentPrincipalTestCase(unittest.TestCase):
193
194    def tearDown(test):
195        endInteraction() # Just in case, one is still lingering around
196
197    def test_existing_principal(self):
198        # We can get the current principal if one is involved
199        principal = Principal('myprincipal')
200        newInteraction(Participation(principal))
201        result = helpers.get_current_principal()
202        self.assertTrue(result is principal)
203
204    def test_no_participation(self):
205        # Interactions without participation are handled correctly
206        newInteraction()
207        result = helpers.get_current_principal()
208        self.assertTrue(result is None)
209
210    def test_not_existing_principal(self):
211        # Missing interactions do not raise errors.
212        result = helpers.get_current_principal()
213        self.assertTrue(result is None)
214
215class CmpFilesTestCase(unittest.TestCase):
216
217    def setUp(self):
218        self.workdir = tempfile.mkdtemp()
219
220    def tearDown(self):
221        shutil.rmtree(self.workdir)
222
223    def test_equal(self):
224        p1 = os.path.join(self.workdir, 'sample1')
225        p2 = os.path.join(self.workdir, 'sample2')
226        open(p1, 'wb').write('Hi!')
227        open(p2, 'wb').write('Hi!')
228        assert helpers.cmp_files(open(p1, 'r'), open(p2, 'r')) is True
229
230    def test_unequal(self):
231        p1 = os.path.join(self.workdir, 'sample1')
232        p2 = os.path.join(self.workdir, 'sample2')
233        open(p1, 'wb').write('Hi!')
234        open(p2, 'wb').write('Ho!')
235        assert helpers.cmp_files(open(p1, 'r'), open(p2, 'r')) is False
236
237class FileSizeTestCase(unittest.TestCase):
238
239    def setUp(self):
240        self.workdir = tempfile.mkdtemp()
241
242    def tearDown(self):
243        shutil.rmtree(self.workdir)
244
245    def test_real_file(self):
246        # we can get the size of real files
247        path = os.path.join(self.workdir, 'sample.txt')
248        open(path, 'wb').write('My content')
249        self.assertEqual(
250            int(helpers.file_size(open(path, 'rb'))), 10)
251        return
252
253    def test_stringio_file(self):
254        # we can get the size of file-like objects
255        self.assertEqual(
256            helpers.file_size(StringIO('my sample content')), 17)
257
258class IfaceNamesTestCase(unittest.TestCase):
259
260    def test_iface_names(self):
261        class I1(Interface):
262            foo = Attribute("""Some Foo""")
263            def bar(blah):
264                pass
265            i1_name = schema.TextLine(title=u'i1 name')
266        class I2(I1):
267            baz = schema.TextLine(title=u'some baz')
268        class I3(I2):
269            pass
270
271        result1 = helpers.iface_names(I3)
272        result2 = helpers.iface_names(I2)
273        result3 = helpers.iface_names(I1)
274        result4 = helpers.iface_names(I3, exclude_attribs=False)
275        result5 = helpers.iface_names(I3, exclude_methods=False)
276        result6 = helpers.iface_names(I3, omit='i1_name')
277        self.assertEqual(sorted(result1), ['baz', 'i1_name'])
278        self.assertEqual(sorted(result2), ['baz', 'i1_name'])
279        self.assertEqual(sorted(result3), ['i1_name'])
280        self.assertEqual(sorted(result4), ['baz', 'foo', 'i1_name'])
281        self.assertEqual(sorted(result5), ['bar', 'baz', 'i1_name'])
282        self.assertEqual(sorted(result6), ['baz'])
283        return
284
285class DateTimeHelpersTestCase(unittest.TestCase):
286
287    def test_now(self):
288        tz_berlin = pytz.timezone('Europe/Berlin')
289        result1 = helpers.now()
290        result2 = helpers.now(tz_berlin)
291        self.assertEqual(result1.tzinfo, pytz.utc)
292        self.assertFalse(result2.tzinfo == pytz.utc)
293        self.assertFalse(result2.tzinfo is None)
294        return
295
296    def test_to_timezone(self):
297        fmt = '%Y-%m-%d %H:%M:%S %Z%z'
298        tz_berlin = pytz.timezone('Europe/Berlin')
299        tz_lagos = pytz.timezone('Africa/Lagos')
300        dt1 = datetime.datetime(2012, 1, 1, 0, 0)
301        dt2 = datetime.datetime(2012, 1, 1, 0, 0, tzinfo=tz_berlin)
302        dt3 = datetime.datetime(2012, 6, 1, 0, 0, tzinfo=tz_lagos)
303        dt4 = datetime.datetime(2012, 6, 1, 0, 0, tzinfo=tz_berlin)
304        result1 = helpers.to_timezone(dt1)
305        result2 = helpers.to_timezone(dt1, pytz.utc)
306        result3 = helpers.to_timezone(dt2)
307        result4 = helpers.to_timezone(dt2, tz_lagos)
308        result5 = helpers.to_timezone(dt3, tz_berlin)
309        result6 = helpers.to_timezone(dt4, tz_lagos)
310        self.assertEqual(
311            result1.strftime(fmt), '2012-01-01 00:00:00 UTC+0000')
312        self.assertEqual(
313            result2.strftime(fmt), '2012-01-01 00:00:00 UTC+0000')
314        self.assertEqual(
315            result3.strftime(fmt), '2011-12-31 23:00:00 UTC+0000')
316        self.assertEqual(
317            result4.strftime(fmt), '2012-01-01 00:00:00 WAT+0100')
318        self.assertEqual(
319            result5.strftime(fmt), '2012-06-01 01:46:00 CEST+0200')
320        self.assertEqual(
321            result6.strftime(fmt), '2012-06-01 00:00:00 WAT+0100')
322        return
323
324    def test_to_timezone_no_dt(self):
325        # the to_timezone function copes with dates (!= datetimes)
326        d = datetime.date(2012, 12, 1)
327        result1 = helpers.to_timezone(d)
328        result2 = helpers.to_timezone(d, pytz.utc)
329        self.assertEqual(result1, d)
330        self.assertEqual(result2, d)
331        return
332
333class GetFileFormatTestCase(unittest.TestCase):
334    # Tests for the get_fileformat helper.
335
336    def setUp(self):
337        self.valid_jpg_path = os.path.join(
338            os.path.dirname(__file__), 'sample_jpg_valid.jpg')
339        self.valid_jpg = open(self.valid_jpg_path, 'rb').read()
340        self.valid_png_path = os.path.join(
341            os.path.dirname(__file__), 'sample_png_valid.png')
342        self.valid_png = open(self.valid_png_path, 'rb').read()
343        self.valid_pdf_path = os.path.join(
344            os.path.dirname(__file__), 'sample_pdf_valid.pdf')
345        self.valid_pdf = open(self.valid_pdf_path, 'rb').read()
346        return
347
348    def test_none(self):
349        # ``None`` is not a file and not a valid file format
350        self.assertEqual(helpers.get_fileformat(None), None)
351        return
352
353    def test_path_and_bytestream(self):
354        # get_fileformat accepts bytestreams and paths as arg.
355        self.assertEqual(
356            helpers.get_fileformat(None, self.valid_jpg), 'jpg')
357        self.assertEqual(
358            helpers.get_fileformat(self.valid_jpg_path), 'jpg')
359        # path is ignored when giving a bytestream
360        self.assertEqual(
361            helpers.get_fileformat('blah', self.valid_jpg), 'jpg')
362        return
363
364    def test_jpg(self):
365        # we recognize jpeg images.
366        self.assertEqual(
367            helpers.get_fileformat(self.valid_jpg_path), 'jpg')
368        self.assertEqual(
369            helpers.get_fileformat(None, self.valid_jpg), 'jpg')
370        return
371
372    def test_png(self):
373        # we recognize png images.
374        self.assertEqual(
375            helpers.get_fileformat(self.valid_png_path), 'png')
376        self.assertEqual(
377            helpers.get_fileformat(None, self.valid_png), 'png')
378        return
379
380    def test_pdf(self):
381        # we recognize pdf documents.
382        self.assertEqual(
383            helpers.get_fileformat(self.valid_pdf_path), 'pdf')
384        self.assertEqual(
385            helpers.get_fileformat(None, self.valid_pdf), 'pdf')
386        return
387
388class MergeCSVFileTestCase(unittest.TestCase):
389
390    def setUp(self):
391        self.workdir = tempfile.mkdtemp()
392        self.path1 = os.path.join(self.workdir, 'myfile1')
393        self.path2 = os.path.join(self.workdir, 'myfile2')
394        self.result_path = None
395        return
396
397    def tearDown(self):
398        shutil.rmtree(self.workdir)
399        if self.result_path is not None and os.path.exists(self.result_path):
400            os.unlink(self.result_path)
401        return
402
403    def test_basic(self):
404        # we can merge very basic CSV files
405        open(self.path1, 'wb').write('name,age\nManfred,32\n')
406        open(self.path2, 'wb').write('name,age\nBarney,28\n')
407        self.result_path = helpers.merge_csv_files(self.path1, self.path2)
408        contents = open(self.result_path, 'r').read()
409        self.assertEqual(
410            contents,
411            'age,name\r\n'
412            '32,Manfred\r\n'
413            '28,Barney\r\n')
414        return
415
416    def test_different_col_order(self):
417        # if cols of both files have different order, that won't stop us
418        open(self.path1, 'wb').write('name,age\nManfred,32\n')
419        open(self.path2, 'wb').write('age,name\n28,Barney\n')
420        self.result_path = helpers.merge_csv_files(self.path1, self.path2)
421        contents = open(self.result_path, 'r').read()
422        self.assertEqual(
423            contents,
424            'age,name\r\n'
425            '32,Manfred\r\n'
426            '28,Barney\r\n')
427        return
428
429    def test_different_cols_at_all(self):
430        # also cols available only in one file will work.
431        open(self.path1, 'wb').write('name,age\nManfred,32\n')
432        open(self.path2, 'wb').write('name,age,buddy\nBarney,28,Manfred\n')
433        self.result_path = helpers.merge_csv_files(self.path1, self.path2)
434        contents = open(self.result_path, 'r').read()
435        self.assertEqual(
436            contents,
437            'age,buddy,name\r\n'
438            '32,,Manfred\r\n'
439            '28,Manfred,Barney\r\n')
440        return
441
442    def test_one_empty_input(self):
443        # we cope even with nearly empty input (one file with no data)
444        open(self.path1, 'wb').write('\n')
445        open(self.path2, 'wb').write('name,age\nManfred,32\n')
446        self.result_path = helpers.merge_csv_files(self.path1, self.path2)
447        contents = open(self.result_path, 'r').read()
448        self.assertEqual(
449            contents,
450            'age,name\r\n'
451            '32,Manfred\r\n')
452        return
453
454    def test_two_empty_inputs(self):
455        # we cope even with empty input (two files with no data)
456        open(self.path1, 'wb').write('\n')
457        open(self.path2, 'wb').write('\n')
458        self.result_path = helpers.merge_csv_files(self.path1, self.path2)
459        contents = open(self.result_path, 'r').read()
460        self.assertEqual(
461            contents, '\r\n')
462        return
463
464
465def test_suite():
466    suite = unittest.TestSuite()
467    # Register local test cases...
468    for testcase in [
469        ReST2HTMLTestCase,
470        FactoryBaseTestCase,
471        CopyFileSystemTreeTestCase,
472        RemoveFileOrDirectoryTestCase,
473        CurrentPrincipalTestCase,
474        CmpFilesTestCase,
475        FileSizeTestCase,
476        IfaceNamesTestCase,
477        DateTimeHelpersTestCase,
478        GetFileFormatTestCase,
479        MergeCSVFileTestCase,
480        SimpleHelpersTestCase,
481        ]:
482        suite.addTests(
483            unittest.TestLoader().loadTestsFromTestCase(testcase)
484            )
485    # Add tests from docstrings in helpers.py...
486    suite.addTests(
487        doctest.DocTestSuite(
488            helpers,
489            optionflags = doctest.ELLIPSIS + doctest.REPORT_NDIFF,
490            )
491        )
492    return suite
493
494if __name__ == '__main__':
495    unittest.main(defaultTest='test_suite')
Note: See TracBrowser for help on using the repository browser.