from unittest import mock from platform import system from tests.recipes.recipe_ctx import RecipeCtx class BaseTestForMakeRecipe(RecipeCtx): """ An unittest for testing any recipe using the standard build commands (`configure/make`). .. note:: Note that Some cmake recipe may need some more specific testing ...but this should cover the basics. """ recipe_name = None expected_compiler = ( "{android_ndk}/toolchains/llvm/prebuilt/{system}-x86_64/bin/clang" ) sh_command_calls = ["./configure"] """The expected commands that the recipe runs via `sh.command`.""" extra_env_flags = {} """ This must be a dictionary containing pairs of key (env var) and value. """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.recipes = ["python3", "kivy", self.recipe_name] self.recipe_build_order = [ "hostpython3", self.recipe_name, "python3", "sdl2", "kivy" ] print(f"We are testing recipe: {self.recipe_name}") @mock.patch("pythonforandroid.recipe.Recipe.check_recipe_choices") @mock.patch("pythonforandroid.build.ensure_dir") @mock.patch("pythonforandroid.archs.find_executable") def test_get_recipe_env( self, mock_find_executable, mock_ensure_dir, mock_check_recipe_choices, ): """ Test that get_recipe_env contains some expected arch flags and that some internal methods has been called. """ mock_find_executable.return_value = self.expected_compiler.format( android_ndk=self.ctx._ndk_dir, system=system().lower() ) mock_check_recipe_choices.return_value = sorted( self.ctx.recipe_build_order ) # make sure the arch flags are in env env = self.recipe.get_recipe_env(self.arch) for flag in self.arch.arch_cflags: self.assertIn(flag, env["CFLAGS"]) self.assertIn( f"-target {self.arch.target}", env["CFLAGS"], ) for flag, value in self.extra_env_flags.items(): self.assertIn(value, env[flag]) # make sure that the mocked methods are actually called mock_ensure_dir.assert_called() mock_find_executable.assert_called() mock_check_recipe_choices.assert_called() @mock.patch("pythonforandroid.util.chdir") @mock.patch("pythonforandroid.build.ensure_dir") @mock.patch("pythonforandroid.archs.find_executable") def test_build_arch( self, mock_find_executable, mock_ensure_dir, mock_current_directory, ): mock_find_executable.return_value = self.expected_compiler.format( android_ndk=self.ctx._ndk_dir, system=system().lower() ) # Since the following mocks are dynamic, # we mock it inside a Context Manager with mock.patch( f"pythonforandroid.recipes.{self.recipe_name}.sh.Command" ) as mock_sh_command, mock.patch( f"pythonforandroid.recipes.{self.recipe_name}.sh.make" ) as mock_make: self.recipe.build_arch(self.arch) # make sure that the mocked methods are actually called for command in self.sh_command_calls: self.assertIn( mock.call(command), mock_sh_command.mock_calls, ) mock_make.assert_called() mock_ensure_dir.assert_called() mock_current_directory.assert_called() mock_find_executable.assert_called() class BaseTestForCmakeRecipe(BaseTestForMakeRecipe): """ An unittest for testing any recipe using `cmake`. It inherits from `BaseTestForMakeRecipe` but we override the build method to match the cmake build method. .. note:: Note that Some cmake recipe may need some more specific testing ...but this should cover the basics. """ @mock.patch("pythonforandroid.util.chdir") @mock.patch("pythonforandroid.build.ensure_dir") @mock.patch("pythonforandroid.archs.find_executable") def test_build_arch( self, mock_find_executable, mock_ensure_dir, mock_current_directory, ): mock_find_executable.return_value = self.expected_compiler.format( android_ndk=self.ctx._ndk_dir, system=system().lower() ) # Since the following mocks are dynamic, # we mock it inside a Context Manager with mock.patch( f"pythonforandroid.recipes.{self.recipe_name}.sh.make" ) as mock_make, mock.patch( f"pythonforandroid.recipes.{self.recipe_name}.sh.cmake" ) as mock_cmake: self.recipe.build_arch(self.arch) # make sure that the mocked methods are actually called mock_cmake.assert_called() mock_make.assert_called() mock_ensure_dir.assert_called() mock_current_directory.assert_called() mock_find_executable.assert_called()