import importlib
from tests import mock_importlib

import os
from test import test_support
import unittest


class ChainingPathHook(unittest.TestCase):

    """Tests for importlib.chaining_fs_path_hook."""

    def test_single_hook(self):
        # A single hook argument should work as expected.
        # Also tests acceptance of a relative path.
        hook = importlib.chaining_fs_path_hook(mock_importlib.SucceedImporter())
        self.assert_(hook('.'))
        hook = importlib.chaining_fs_path_hook(mock_importlib.PassImporter())
        self.assertRaises(ImportError, hook, '.')

    def test_path_acceptance(self):
        # Valid paths should be accepted, but non-existent paths should be
        # rejected outright.
        succeed_hook = mock_importlib.SucceedImporter()
        hook = importlib.chaining_fs_path_hook(succeed_hook)
        self.assert_(hook('.'))
        self.assertRaises(ImportError, hook, '_nonexistentdirectory')

    def test_multiple_hooks(self):
        # Multiple hooks should work.
        succeed_hook = mock_importlib.SucceedImporter()
        pass_hook = mock_importlib.PassImporter()
        hook = importlib.chaining_fs_path_hook(pass_hook, succeed_hook)
        self.assert_(hook('.'))
        hook = importlib.chaining_fs_path_hook(succeed_hook, pass_hook)
        self.assert_(hook('.'))
        hook = importlib.chaining_fs_path_hook(pass_hook, pass_hook)
        self.assertRaises(ImportError, hook, '.')

    def test_order_preservation(self):
        # The order of importers to call should be maintained.
        succeed1 = mock_importlib.SucceedImporter()
        succeed2 = mock_importlib.SucceedImporter()
        hook = importlib.chaining_fs_path_hook(succeed1, succeed2)
        importer = hook('.')
        self.assert_(importer._importers[0] is succeed1)
        self.assert_(importer._importers[1] is succeed2)

    def test_absolute_path(self):
        # The path hooks that are called should be passed an absolute path.
        succeed = mock_importlib.SucceedImporter()
        hook = importlib.chaining_fs_path_hook(succeed)
        hook('.')
        absolute_path = os.path.abspath('.')
        self.assertEquals(os.path.normpath(succeed.path_entries[0]), absolute_path)

    def test_reject_file(self):
        # A file should not be accepted.
        succeed = mock_importlib.SucceedImporter()
        hook = importlib.chaining_fs_path_hook(succeed)
        with open(test_support.TESTFN, 'w') as test_file:
            test_file.write('# For testing chained path hook.')
        try:
            self.assertRaises(ImportError, hook, test_support.TESTFN)
        finally:
            test_support.unlink(test_support.TESTFN)

    def test_reject_bad_dir(self):
        # A non-existent directory should be rejected.
        succeed = mock_importlib.SucceedImporter()
        hook = importlib.chaining_fs_path_hook(succeed)
        self.assertRaises(ImportError, hook, '_asdfasdfasdf')


class ChainedImporterTests(unittest.TestCase):

    """Tests for importlib.ChainedImporter."""

    def test_single_importer(self):
        # There should be no issue with a single importer.
        succeed = mock_importlib.SucceedImporter()
        importer = importlib.ChainedImporter(succeed)
        self.assert_(importer.find_module('blah') is succeed)
        self.assertEqual(succeed.find_request[0], 'blah')
        pass_ = mock_importlib.PassImporter()
        importer = importlib.ChainedImporter(pass_)
        self.assert_(importer.find_module(pass_) is None)

    def test_multiple_importers(self):
        # Test that multiple importers work.
        succeed = mock_importlib.SucceedImporter()
        pass_ = mock_importlib.PassImporter()
        importer = importlib.ChainedImporter(succeed, pass_)
        self.assert_(importer.find_module('blah') is succeed)
        self.assert_(succeed.find_request[0], 'blah')
        importer = importlib.ChainedImporter(pass_, succeed)
        self.assert_(importer.find_module('blah') is succeed)
        self.assert_(succeed.find_request[0], 'blah')

    def test_order(self):
        # Make sure that the importers are called in the proper order.
        succeed = mock_importlib.SucceedImporter()
        pass_ = mock_importlib.PassImporter()
        assert not hasattr(pass_, 'find_request')
        assert not hasattr(succeed, 'find_request')
        importer = importlib.ChainedImporter(pass_, succeed)
        importer.find_module('blah')
        self.assert_(hasattr(pass_, 'find_request'))
        self.assertEqual(pass_.find_request[0], 'blah')
        self.assert_(hasattr(succeed, 'find_request'))
        self.assertEqual(succeed.find_request[0], 'blah')
        succeed = mock_importlib.SucceedImporter()
        succeed2 = mock_importlib.SucceedImporter()
        importer = importlib.ChainedImporter(succeed, succeed2)
        importer.find_module('blah')
        self.assert_(hasattr(succeed, 'find_request'))
        self.assertEqual(succeed.find_request[0], 'blah')
        self.assert_(not hasattr(succeed2, 'find_request'))


def test_main():
    test_support.run_unittest(ChainingPathHook, ChainedImporterTests)


if __name__ == '__main__':
    test_main()
