Commits

Arnaud Grausem committed a705246

Unit tests

  • Participants
  • Parent commits 7bfd54e

Comments (0)

Files changed (13)

+.PHONY: test
+
+test:
+	@coverage run --omit=/tmp/*,*tests/* -m unittest discover src/adama/tests
+
+report: test
+	@coverage html
+	@chromium-browser htmlcov/index.html

src/adama/commandment.py

             description=self.__doc__, option_list=self.options,
             version=self.version, epilog='')
 
-    def explanations(self):
+    def explanations(self, in_shell=True):
         """Help on command
         """
-        self.decrypter.print_help()
+        if in_shell:
+            self.decrypter.print_help()
         return 1
 
     def decrypt(self, args):

src/adama/exceptions.py

     def __str__(self):
         return self.message
 
-    def __call__(self):
-        print(self.print_error())
+    def __call__(self, in_shell=True):
+        if in_shell:
+            print(self.print_error())
         return self.number
 
 

src/adama/orders/__init__.py

     """
     if path and path not in sys.path:
         sys.path.append(path)
-    try:
-        module = __import__(module_name)
-    except ImportError as e:
-        raise OrderError(str(e))
-    return module
+    return __import__(module_name)
 
 
 def get_command(name, module):

src/adama/orders/create_order.py

 
         # adds a path to pythonpath if options has been selected
         # and if it is not already there and returns a module
-        module = get_module(args[0], options['pythonpath'])
+        try:
+            module = get_module(args[0], options['pythonpath'])
+        except ImportError as e:
+            raise OrderError(str(e), self)
         name = args[1]
 
         # Constructs, searches and creates the orders path

src/adama/orders/create_program.py

             raise OrderError('The create_program order has one required argument',
                 self)
 
-        module = get_module(args[0], options['pythonpath'])
+        try:
+            module = get_module(args[0], options['pythonpath'])
+        except ImportError as e:
+            raise OrderError(str(e), self)
 
         # Checks if entered path exists and create it
         if not os.path.isdir(options['path']):

src/adama/tests/__init__.py

+# -*- coding: utf-8 -*-
+
+"""Test getting orders
+"""
+
+import unittest
+import os
+import sys
+import shutil
+
+from adama.commandment import QG
+from adama.exceptions import AdamaError
+
+
+class TestBaseOrders(unittest.TestCase):
+    """Base test initializer
+    """
+
+    def setUp(self):
+        self.base_path = '/tmp/pyproject'
+        self.orders_path = self.base_path + '/orders'
+        self.module = 'pyproject'
+        self.command = 'pyp'
+        # Creating temporary directories
+        os.makedirs(self.orders_path)
+        # Making packages
+        for path in (self.base_path, self.orders_path):
+            filename = os.path.join(path, '__init__.py')
+            with file(filename, 'a'):
+                os.utime(filename, None)
+
+    def tearDown(self):
+        # Removing temporary files
+        shutil.rmtree(self.base_path)
+        # Removing attributes
+        del self.base_path
+        del self.orders_path
+        del self.module
+        del self.command
+
+    def _create_orders(self, *orders):
+        """Creating some empty orders module"""
+        orders_template_path = os.path.join(
+            __import__('adama').__path__[0],
+            'templates',
+            'order.template'
+        )
+        with open(orders_template_path, 'r') as template:
+            order = template.read().format(self.module, self.command)
+            for filename in orders:
+                with open(os.path.join(self.orders_path, filename), 'a') \
+                    as new_order:
+                    new_order.write(order)
+
+    def _add_to_syspath(self):
+        """Adds a path to sys.path"""
+        sys.path.append(os.path.dirname(self.base_path))
+
+    def _remove_from_syspath(self):
+        """Removes a path to sys.path and modules from sys.modules"""
+        for mod in [mod for mod in sys.modules if mod.startswith(self.module)]:
+            del sys.modules[mod]
+        sys.path.remove(os.path.dirname(self.base_path))
+
+
+def no_shell_printing(f):
+    """No shell printing for help when lauching tests
+    """
+    print_functions = (QG.explanations, AdamaError.__call__)
+    def wrap(**kwargs):
+        for function in print_functions:
+            function.im_func.func_defaults = (False, )
+        result = f(**kwargs)
+        for function in print_functions:
+            function.im_func.func_defaults = (True, )
+        return result
+    return wrap
+
+
+def encapsulate_test_with_syspath(*orders):
+    """Creates orders, adds path to sys path before launching test
+    and removes path and modules
+    """
+    def wrap(f):
+        def wrapped_f(instance, *args, **kwargs):
+            instance._create_orders(*orders)
+            instance._add_to_syspath()
+            f(instance, *args, **kwargs)
+            instance._remove_from_syspath()
+        return wrapped_f
+    return wrap

src/adama/tests/test_commandment.py

+# -*- coding utf-8 -*-
+
+"""
+"""
+
+import unittest
+import sys
+
+from adama.tests import TestBaseOrders
+from adama.commandment import Commander
+
+
+class TestCommander(TestBaseOrders):
+    """Tests the usage generated by the API for a command
+    """
+
+    def setUp(self):
+        super(TestCommander, self).setUp()
+        self.commander = Commander(self.module, self.command)
+
+    def tearDown(self):
+        del self.commander
+        super(TestCommander, self).tearDown()
+
+    def test_usage(self):
+        assert self.commander.usage() == 'Usage: {0} order [options] [args]'.format(self.command)
+
+    def test_run_not_implemented(self):
+        self.assertRaises(NotImplementedError, self.commander, [])
+
+if __name__ == '__main__':
+    unittest.main()

src/adama/tests/test_exceptions.py

+# -*- coding utf-8 -*-
+
+"""
+"""
+
+import unittest
+import sys
+
+from adama import call_order
+from adama.tests import TestBaseOrders, no_shell_printing
+from adama.exceptions import AdamaError, OrderError
+
+
+class TestBaseException(unittest.TestCase):
+    """Test the implementation of adama's base exception
+    """
+
+    def runTest(self):
+        base_exception = AdamaError('Base exception')
+        self.assertRaises(NotImplementedError, base_exception.print_error)
+        assert no_shell_printing(base_exception)() == 1
+
+
+class TestOrderError(unittest.TestCase):
+    """Tests errors catched in execution of orders
+    """
+
+    def runTest(self):
+        with self.assertRaises(OrderError) as order_error:
+            call_order('adama', 'create_program')
+        exception = order_error.exception
+        assert exception.print_error() == 'The create_program order has one required argument\nUsage: adama create_program [options] module\n'
+        assert repr(exception) == '<OrderError: create_program>'
+        assert no_shell_printing(exception)() == 12
+
+
+if __name__ == '__main__':
+    unittest.main()

src/adama/tests/test_orders.py

+# -*- coding utf-8 -*-
+
+"""
+"""
+
+import unittest
+import sys
+import os
+import shutil
+
+from adama import call_order
+from adama.tests import TestBaseOrders, no_shell_printing
+from adama.exceptions import AdamaError, OrderError
+
+
+class TestCreateProgram(TestBaseOrders):
+    """Tests the creating program with the adama order
+    """
+
+    def setUp(self):
+        super(TestCreateProgram, self).setUp()
+        self.destination = os.path.join(self.base_path, 'bin')
+
+    def tearDown(self):
+        del self.destination
+        super(TestCreateProgram, self).tearDown()
+
+    def _isfile(self, filename):
+        return os.path.isfile(os.path.join(self.destination, filename))
+
+    def test_no_arg(self):
+        """No argument passed to the order
+        """
+        with self.assertRaises(OrderError) as order_error:
+            call_order('adama', 'create_program')
+        exception = order_error.exception
+        assert exception.message == 'The create_program order has one required argument'
+
+    def test_command_name(self):
+        """Tests creating a command with a name defined
+        """
+        call_order('adama', 'create_program', self.module, name=self.command, pythonpath='/tmp', path=self.destination)
+        self.assertTrue(self._isfile(self.command))
+        self._remove_from_syspath()
+
+    def test_no_command_name(self):
+        """Tests creating a command with no name defined
+        """
+        call_order('adama', 'create_program', self.module, name='', pythonpath='/tmp', path=self.destination)
+        self.assertTrue(self._isfile(self.module))
+        self._remove_from_syspath()
+
+    def test_in_syspath(self):
+        """Tests searching module with no pythonpath add and module in syspath
+        """
+        self._add_to_syspath()
+        call_order('adama', 'create_program', self.module, name=self.command, pythonpath='', path=self.destination)
+        self.assertTrue(self._isfile(self.command))
+        self._remove_from_syspath()
+
+    def test_not_in_syspath(self):
+        """Tests searching module with no pythonpath add and module not in syspath
+        """
+        self.assertRaises(OrderError, call_order, 'adama', 'create_program', self.module, name=self.command, pythonpath='', path=self.destination)
+
+
+class TestCreateOrder(TestBaseOrders):
+    """ Tests creating new orders with the adama order
+    """
+
+    def  _isfile(self, order_file):
+        return os.path.isfile(os.path.join(self.orders_path, order_file))
+
+    def test_no_arg(self):
+        """No argument passed to the order
+        """
+        with self.assertRaises(OrderError) as order_error:
+            call_order('adama', 'create_order')
+        exception = order_error.exception
+        assert exception.message == 'The create_order order has two required arguments'
+
+    def test_no_orders_module(self):
+        """The orders module is absent
+        """
+        shutil.rmtree(self.orders_path)
+        call_order('adama', 'create_order', self.module, 'no_module', pythonpath='/tmp', name=self.command)
+        self.assertTrue(self._isfile('no_module.py'))
+        self._remove_from_syspath()
+
+    def test_in_syspath(self):
+        """Tests creating orders in a package that is present in syspath
+        """
+        self._add_to_syspath()
+        call_order('adama', 'create_order', self.module, 'test', pythonpath='', name=self.command)
+        self.assertTrue(self._isfile('test.py'))
+        self._remove_from_syspath()
+
+    def test_not_in_syspath(self):
+        """Tests creating orders in a package that is not present in syspath
+        """
+        self.assertRaises(OrderError, call_order, 'adama', 'create_order', self.module, 'test', pythonpath='', name=self.command)
+
+
+if __name__ == '__main__':
+    unittest.main()

src/adama/tests/test_parsing_args.py

+# -*- coding utf-8 -*-
+
+"""
+"""
+
+import unittest
+import sys
+
+from adama.tests import TestBaseOrders, no_shell_printing, encapsulate_test_with_syspath
+from adama import sir_yes_sir, call_order
+from adama.exceptions import UnknownOrderError
+
+
+sir_yes_sir = no_shell_printing(sir_yes_sir)
+
+
+class TestShellHelp(TestBaseOrders):
+    """Tests the help message and the way they are displayed
+    """
+
+    def test_no_args(self):
+        """
+        """
+        assert sir_yes_sir(module=self.module, argv=[self.command]) == 1
+
+    def test_global_help(self):
+        """
+        """
+        assert sir_yes_sir(module=self.module, argv=[self.command, 'help']) == 1
+
+    @encapsulate_test_with_syspath('add.py')
+    def test_order_help(self):
+        """
+        """
+        assert sir_yes_sir(module=self.module, argv=[self.command, 'help', 'add']) == 1
+
+
+class TestShellNoOrder(TestBaseOrders):
+    """Tests executing an order that doesn't exist
+    """
+
+    def runTest(self):
+        assert sir_yes_sir(module=self.module, argv=[self.command, 'clear']) == 11
+
+
+class TestShellExcuteOrder(TestBaseOrders):
+    """Tests executing an order
+    """
+
+    @encapsulate_test_with_syspath('add.py')
+    def runTest(self):
+        assert sir_yes_sir(module=self.module, argv=[self.command, 'add']) == 0
+
+
+class TestDirectLaunchOrder(TestBaseOrders):
+    """Tests executing orders in python scripts
+    """
+
+    def test_no_order(self):
+        """No order created
+        """
+        self.assertRaises(UnknownOrderError, call_order, self.module, 'add')
+
+    @encapsulate_test_with_syspath('add.py')
+    def test_executing_order(self):
+        """
+        """
+        assert call_order(self.module, 'add') == 0
+
+if __name__ == '__main__':
+    unittest.main()

src/adama/tests/test_searching_orders.py

+# -*- coding: utf-8 -*-
+
+"""Test getting orders
+"""
+
+import unittest
+import sys
+import os
+import shutil
+
+from adama.tests import TestBaseOrders
+
+from adama.commandment import Commander
+from adama.utils import find_orders, is_package, is_file, is_module
+from adama.exceptions import UnknownOrderError
+
+
+class TestFileUtils(unittest.TestCase):
+    """Testing utils function on file
+    """
+
+    def test_is_a_package(self):
+        my_package = '__init__.py'
+        self.assertTrue(is_package(my_package))
+
+    def test_is_not_a_package(self):
+        my_module = 'my_module.py'
+        self.assertFalse(is_package(my_module))
+
+    def test_is_a_module(self):
+        my_module = ('module', '.py')
+        self.assertTrue(is_module(*my_module))
+
+    def test_is_not_a_module(self):
+        my_file = ('file', '.txt')
+        self.assertFalse(is_module(*my_file))
+        my_package = ('__init__', '.py')
+        self.assertFalse(is_module(*my_package))
+
+    def test_is_a_file(self):
+        with open('/tmp/my_module.py', 'w') as module:
+            module.write('I\'m a Python module')
+        self.assertTrue(is_file('/tmp', 'my_module.py'))
+        os.remove('/tmp/my_module.py')
+
+    def test_is_not_a_file(self):
+        self.assertFalse(is_file('/tmp', 'my_other_module.py'))
+        os.mkdir('/tmp/my_directory')
+        self.assertFalse(is_file('/tmp', 'my_directory'))
+        os.rmdir('/tmp/my_directory')
+
+
+class TestFindOrders(TestBaseOrders):
+    """Testing searching files that contains order in the right
+    package of project root path
+    """
+
+    def test_finding_orders(self):
+        """Finding files that don't start with '_' and that are python files
+        in the orders package
+        """
+        self._create_orders('add.py', 'remove.py')
+        self.assertItemsEqual(find_orders(self.base_path), ['add', 'remove'])
+
+    def test_not_finding_orders(self):
+        """No filename matching in package
+        """
+        self._create_orders("add", "remove", "_clean.py")
+        self.assertTrue(not find_orders(self.base_path))
+
+    def test_with_os_error(self):
+        """Package does not exist
+        """
+        self.assertTrue(not find_orders(self.orders_path))
+
+
+class TestGetOrders(TestBaseOrders):
+    """Testing instanciation of found orders
+    """
+
+    def setUp(self):
+        super(TestGetOrders, self).setUp()
+        self._add_to_syspath()
+        self.commander = Commander(self.module, command=self.command)
+
+    def tearDown(self):
+        self._remove_from_syspath()
+        super(TestGetOrders, self).tearDown()
+        del self.commander
+
+    def test_get_orders(self):
+        """Test getting orders
+        """
+        self._create_orders('add.py', 'remove.py')
+        self.assertItemsEqual(self.commander.orders, ['add', 'remove'])
+        self._create_orders('clear.py')
+        self.assertItemsEqual(self.commander.orders, ['add', 'remove'])
+        new_commander = Commander(self.module, command=self.command)
+        self.assertItemsEqual(new_commander.orders, ['add', 'remove', 'clear'])
+
+    def test_get_order(self):
+        """Test getting one order
+        """
+        self._create_orders('clear.py')
+        assert repr(self.commander['clear']) == '<Order: clear>'
+
+    def test_get_not_existing_order(self):
+        """
+        """
+        with self.assertRaises(UnknownOrderError) as error:
+            clear = self.commander['clear']
+        the_error = error.exception
+        self.assertEqual(the_error.number, 11)
+        self.assertRegexpMatches(str(the_error), 'The order "clear" doesn\'t exist')
+        self.assertEqual(repr(the_error), '<UnknownOrderError: {0}>'.format(self.command))
+
+
+class TestNoOrderPackage(TestBaseOrders):
+    """Testing getting orders when no order package is available
+    """
+
+    def setUp(self):
+        super(TestNoOrderPackage, self).setUp()
+        shutil.rmtree(self.orders_path)
+        self._add_to_syspath()
+
+    def tearDown(self):
+        self._remove_from_syspath()
+        super(TestNoOrderPackage, self).tearDown()
+
+    def runTest(self):
+        commander = Commander(self.module)
+        self.assertTrue(not commander.orders)
+
+
+if __name__ == "__main__":
+    unittest.main()

src/adama/utils.py

         return self.description
 
 
+def is_package(filename):
+    """ Checks if filename looks like a Python package
+    """
+    return filename.startswith('_')
+
+
+def is_module(name, extension):
+    """ Checks if file looks like a Python module
+    """
+    return not is_package(name + extension) and extension == '.py'
+
+
+def is_file(path, element):
+    """ Checks if an element from directory tree is a file
+    """
+    return os.path.isfile(os.path.join(path, element))
+
+
 def find_orders(path):
     """
     """
-    order_path = os.path.join(path, 'orders')
+    DEFAULT_ORDER_DIRECTORY = 'orders'
+    # returns only python modules name found in orders path
     try:
-        return [order[:-3] for order in os.listdir(order_path)
-            if not order.startswith('_') and order.endswith('.py')]
+        orders_path = os.path.join(path, DEFAULT_ORDER_DIRECTORY)
+        splitted_files = [os.path.splitext(element) for element
+            in os.listdir(orders_path) if is_file(orders_path, element)]
+        return [filename for filename, extension in splitted_files
+            if is_module(filename, extension)]
     except OSError:
         return []