# -*- coding: utf-8 -*-

## $Id: test_helpers.py 7196 2011-11-25 07:44:52Z henrik $
##
## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
## 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
import shutil
import tempfile
import unittest
import doctest
from cStringIO import StringIO
from zope.security.testing import Principal, Participation
from zope.security.management import newInteraction, endInteraction
from waeup.sirp.utils import helpers

from zope.interface import Interface, implements
class IFakeObject(Interface):
    """Some marker interface."""

class FakeObject(object):
    implements(IFakeObject)

class RemoveFileOrDirectoryTestCase(unittest.TestCase):

    def setUp(self):
        self.dirpath = tempfile.mkdtemp()
        self.filepath = os.path.join(self.dirpath, 'somefile')
        self.non_file = os.path.join(self.dirpath, 'nonfile')
        open(self.filepath, 'wb').write('Hi!')
        return

    def tearDown(self):
        if os.path.exists(self.dirpath):
            shutil.rmtree(self.dirpath)
        return

    def test_handle_not_existing_path(self):
        result = helpers.remove_file_or_directory(self.non_file)
        self.assertTrue(result is None)
        return

    def test_handle_dir(self):
        helpers.remove_file_or_directory(self.dirpath)
        self.assertFalse(
            os.path.exists(self.dirpath)
            )
        return

    def test_handle_file(self):
        helpers.remove_file_or_directory(self.filepath)
        self.assertFalse(
            os.path.exists(self.filepath)
            )
        return

class CopyFileSystemTreeTestCase(unittest.TestCase):
    # Test edge cases of copy_filesystem_tree().
    #
    # This is a typical case of tests not written as doctest as it is
    # normally not interesting for developers and we only want to make
    # sure everything works as expected.
    def setUp(self):
        self.existing_src = tempfile.mkdtemp()
        self.filepath = os.path.join(self.existing_src, 'somefile')
        open(self.filepath, 'wb').write('Hi!')
        self.existing_dst = tempfile.mkdtemp()
        self.not_existing_dir = tempfile.mkdtemp()
        shutil.rmtree(self.not_existing_dir)

        pass

    def tearDown(self):
        shutil.rmtree(self.existing_src)
        shutil.rmtree(self.existing_dst)
        pass

    def test_source_and_dst_existing(self):
        helpers.copy_filesystem_tree(self.existing_src, self.existing_dst)
        self.assertTrue(
            os.path.exists(
                os.path.join(self.existing_dst, 'somefile')
                )
            )
        return

    def test_source_not_existing(self):
        self.assertRaises(
            ValueError,
            helpers.copy_filesystem_tree,
            self.not_existing_dir,
            self.existing_dst
            )
        return

    def test_dest_not_existing(self):
        self.assertRaises(
            ValueError,
            helpers.copy_filesystem_tree,
            self.existing_src,
            self.not_existing_dir
            )
        return

    def test_src_not_a_dir(self):
        self.assertRaises(
            ValueError,
            helpers.copy_filesystem_tree,
            self.filepath,
            self.existing_dst
            )
        return

    def test_dst_not_a_dir(self):
        self.assertRaises(
            ValueError,
            helpers.copy_filesystem_tree,
            self.existing_src,
            self.filepath
            )
        return

class ReST2HTMLTestCase(unittest.TestCase):

    def setUp(self):
        self.expected = u'<div class="document">\n\n\n<p>Some '
        self.expected += u'test with \xfcmlaut</p>\n</div>'
        return

    def test_ascii_umlauts(self):
        # Make sure we convert umlauts correctly to unicode.
        source = 'Some test with ümlaut'
        result = helpers.ReST2HTML(source)
        self.assertEqual(result, self.expected)

    def test_unicode_umlauts(self):
        # Make sure we convert umlauts correctly to unicode.
        source = u'Some test with ümlaut'
        result = helpers.ReST2HTML(source)
        self.assertEqual(result, self.expected)

    def test_unicode_output_from_ascii(self):
        source = 'Some test with ümlaut'
        self.assertTrue(isinstance(helpers.ReST2HTML(source), unicode))

    def test_unicode_output_from_unicode(self):
        source = u'Some test with ümlaut'
        self.assertTrue(isinstance(helpers.ReST2HTML(source), unicode))


class FactoryBaseTestCase(unittest.TestCase):

    def test_ifaces(self):
        # We test all relevant parts in the docstring. But the interfaces
        # method has to be tested to please the coverage report as well.
        factory = helpers.FactoryBase()
        factory.factory = FakeObject
        self.assertTrue(factory.getInterfaces()(IFakeObject))
        return

class CurrentPrincipalTestCase(unittest.TestCase):

    def tearDown(test):
        endInteraction() # Just in case, one is still lingering around

    def test_existing_principal(self):
        # We can get the current principal if one is involved
        principal = Principal('myprincipal')
        newInteraction(Participation(principal))
        result = helpers.get_current_principal()
        self.assertTrue(result is principal)

    def test_no_participation(self):
        # Interactions without participation are handled correctly
        newInteraction()
        result = helpers.get_current_principal()
        self.assertTrue(result is None)

    def test_not_existing_principal(self):
        # Missing interactions do not raise errors.
        result = helpers.get_current_principal()
        self.assertTrue(result is None)

class CmpFilesTestCase(unittest.TestCase):

    def setUp(self):
        self.workdir = tempfile.mkdtemp()

    def tearDown(self):
        shutil.rmtree(self.workdir)

    def test_equal(self):
        p1 = os.path.join(self.workdir, 'sample1')
        p2 = os.path.join(self.workdir, 'sample2')
        f1 = open(p1, 'wb').write('Hi!')
        f2 = open(p2, 'wb').write('Hi!')
        assert helpers.cmp_files(open(p1, 'r'), open(p2, 'r')) is True

    def test_unequal(self):
        p1 = os.path.join(self.workdir, 'sample1')
        p2 = os.path.join(self.workdir, 'sample2')
        f1 = open(p1, 'wb').write('Hi!')
        f2 = open(p2, 'wb').write('Ho!')
        assert helpers.cmp_files(open(p1, 'r'), open(p2, 'r')) is False

class FileSizeTestCase(unittest.TestCase):

    def setUp(self):
        self.workdir = tempfile.mkdtemp()

    def tearDown(self):
        shutil.rmtree(self.workdir)

    def test_real_file(self):
        # we can get the size of real files
        path = os.path.join(self.workdir, 'sample.txt')
        open(path, 'wb').write('My content')
        self.assertEqual(
            int(helpers.file_size(open(path, 'rb'))), 10)
        return

    def test_stringio_file(self):
        # we can get the size of file-like objects
        self.assertEqual(
            helpers.file_size(StringIO('my sample content')), 17)

def test_suite():
    suite = unittest.TestSuite()
    # Register local test cases...
    for testcase in [
        ReST2HTMLTestCase,
        FactoryBaseTestCase,
        CopyFileSystemTreeTestCase,
        RemoveFileOrDirectoryTestCase,
        CurrentPrincipalTestCase,
        CmpFilesTestCase,
        FileSizeTestCase,
        ]:
        suite.addTests(
            unittest.TestLoader().loadTestsFromTestCase(testcase)
            )
    # Add tests from docstrings in helpers.py...
    suite.addTests(
        doctest.DocTestSuite(
            helpers,
            optionflags = doctest.ELLIPSIS + doctest.REPORT_NDIFF,
            )
        )
    return suite

if __name__ == '__main__':
    unittest.main(defaultTest='test_suite')
