Repository: kivy/python-for-android

Issue:
Unit test recipes (reportlab to begin with)
The test suite is currently running full integration tests for a bunch of recipes.
While integration tests are good, we cannot currently use them for all recipes because they run for too long.
However having unit tests for all recipes should be feasible and may still cover some issues like https://github.com/kivy/python-for-android/pull/1357#issuecomment-423614116.
Unit tests were recently enabled the following pull request https://github.com/kivy/python-for-android/pull/1379. So the idea is to increase the coverage start from reportlab recipe as a use case.


Discussion:

Resolving patch:
diff --git a/pythonforandroid/recipes/reportlab/__init__.py b/pythonforandroid/recipes/reportlab/__init__.py
--- a/pythonforandroid/recipes/reportlab/__init__.py
+++ b/pythonforandroid/recipes/reportlab/__init__.py
@@ -26,16 +26,15 @@ def prebuild_arch(self, arch):
             info('reportlab recipe: ft_lib_dir={}'.format(ft_lib_dir))
             info('reportlab recipe: ft_inc_dir={}'.format(ft_inc_dir))
             with current_directory(recipe_dir):
-                sh.ls('-lathr')
                 ensure_dir(tmp_dir)
                 pfbfile = os.path.join(tmp_dir, "pfbfer-20070710.zip")
                 if not os.path.isfile(pfbfile):
                     sh.wget("http://www.reportlab.com/ftp/pfbfer-20070710.zip", "-O", pfbfile)
                 sh.unzip("-u", "-d", os.path.join(recipe_dir, "src", "reportlab", "fonts"), pfbfile)
                 if os.path.isfile("setup.py"):
-                    with open('setup.py', 'rb') as f:
+                    with open('setup.py', 'r') as f:
                         text = f.read().replace('_FT_LIB_', ft_lib_dir).replace('_FT_INC_', ft_inc_dir)
-                    with open('setup.py', 'wb') as f:
+                    with open('setup.py', 'w') as f:
                         f.write(text)
 
 


Test patch:
diff --git a/tests/recipes/test_reportlab.py b/tests/recipes/test_reportlab.py
new file mode 100644
--- /dev/null
+++ b/tests/recipes/test_reportlab.py
@@ -0,0 +1,55 @@
+import os
+import tempfile
+import unittest
+from mock import patch
+from pythonforandroid.archs import ArchARMv7_a
+from pythonforandroid.build import Context
+from pythonforandroid.graph import get_recipe_order_and_bootstrap
+from pythonforandroid.recipe import Recipe
+from pythonforandroid.util import ensure_dir
+
+
+class TestReportLabRecipe(unittest.TestCase):
+
+    def setUp(self):
+        """
+        Setups recipe and context.
+        """
+        self.context = Context()
+        self.arch = ArchARMv7_a(self.context)
+        self.recipe = Recipe.get_recipe('reportlab', self.context)
+        self.recipe.ctx = self.context
+        self.bootstrap = None
+        recipe_build_order, python_modules, bootstrap = \
+            get_recipe_order_and_bootstrap(
+                self.context, [self.recipe.name], self.bootstrap)
+        self.context.recipe_build_order = recipe_build_order
+        self.context.python_modules = python_modules
+        self.context.setup_dirs(tempfile.gettempdir())
+        self.bootstrap = bootstrap
+        self.recipe_dir = self.recipe.get_build_dir(self.arch.arch)
+        ensure_dir(self.recipe_dir)
+
+    def test_prebuild_arch(self):
+        """
+        Makes sure `prebuild_arch()` runs without error and patches `setup.py`
+        as expected.
+        """
+        # `prebuild_arch()` dynamically replaces strings in the `setup.py` file
+        setup_path = os.path.join(self.recipe_dir, 'setup.py')
+        with open(setup_path, 'w') as setup_file:
+            setup_file.write('_FT_LIB_\n')
+            setup_file.write('_FT_INC_\n')
+
+        # these sh commands are not relevant for the test and need to be mocked
+        with \
+                patch('sh.patch'), \
+                patch('sh.touch'), \
+                patch('sh.unzip'), \
+                patch('os.path.isfile'):
+            self.recipe.prebuild_arch(self.arch)
+        # makes sure placeholder got replaced with library and include paths
+        with open(setup_path, 'r') as setup_file:
+            lines = setup_file.readlines()
+        self.assertTrue(lines[0].endswith('freetype/objs/.libs\n'))
+        self.assertTrue(lines[1].endswith('freetype/include\n'))