def test_get_bootstraps_from_recipes(self): """A test which will initialize a bootstrap and will check if the method :meth:`~pythonforandroid.bootstrap.Bootstrap. get_bootstraps_from_recipes` returns the expected values """ recipes_sdl2 = {"sdl2", "python3", "kivy"} bs = Bootstrap().get_bootstrap_from_recipes(recipes_sdl2, self.ctx) self.assertEqual(bs.name, "sdl2") # test wrong recipes wrong_recipes = {"python2", "python3", "pyjnius"} bs = Bootstrap().get_bootstrap_from_recipes(wrong_recipes, self.ctx) self.assertIsNone(bs)
def test_bootstrap_strip( self, mock_find_executable, mock_glob, mock_ensure_dir, mock_sh_command, mock_sh_print, ): mock_find_executable.return_value = os.path.join( self.ctx._ndk_dir, f"toolchains/llvm/prebuilt/{system().lower()}-x86_64/bin/clang", ) mock_glob.return_value = [ os.path.join(self.ctx._ndk_dir, "toolchains", "llvm") ] # prepare arch, bootstrap, distribution and PythonRecipe arch = ArchARMv7_a(self.ctx) bs = Bootstrap().get_bootstrap(self.bootstrap_name, self.ctx) self.setUp_distribution_with_bootstrap(bs) self.ctx.python_recipe = Recipe.get_recipe("python3", self.ctx) # test that strip_libraries runs with a fake distribution bs.strip_libraries(arch) mock_find_executable.assert_called_once() self.assertEqual( mock_find_executable.call_args[0][0], mock_find_executable.return_value, ) mock_sh_command.assert_called_once_with("arm-linux-androideabi-strip") # check that the other mocks we made are actually called mock_ensure_dir.assert_called() mock_sh_print.assert_called()
def test_bootstrap_strip( self, mock_find_executable, mock_ensure_dir, mock_sh_command, mock_sh_print, ): mock_find_executable.return_value = "arm-linux-androideabi-gcc" # prepare arch, bootstrap, distribution and PythonRecipe arch = ArchARMv7_a(self.ctx) bs = Bootstrap().get_bootstrap(self.bootstrap_name, self.ctx) self.setUp_distribution_with_bootstrap(bs) self.ctx.python_recipe = Recipe.get_recipe("python3", self.ctx) # test that strip_libraries runs with a fake distribution bs.strip_libraries(arch) mock_find_executable.assert_called_once() self.assertEqual( mock_find_executable.call_args[0][0], mock_find_executable.return_value, ) mock_sh_command.assert_called_once_with("arm-linux-androideabi-strip") # check that the other mocks we made are actually called mock_ensure_dir.assert_called() mock_sh_print.assert_called()
def test_get_distributions(self, mock_glob, mock_exists, mock_open_dist_info): """Test that method :meth:`~pythonforandroid.distribution.Distribution.get_distributions` returns some expected values: - A list of instances of class `~pythonforandroid.distribution.Distribution - That one of the distributions returned in the result has the proper values (`name`, `ndk_api` and `recipes`) """ self.setUp_distribution_with_bootstrap(Bootstrap().get_bootstrap( "sdl2", self.ctx)) mock_glob.return_value = ["sdl2-python3"] mock_open_dist_info.side_effect = [ mock.mock_open(read_data=json.dumps(dist_info_data)).return_value ] dists = self.ctx.bootstrap.distribution.get_distributions(self.ctx) self.assertIsInstance(dists, list) self.assertEqual(len(dists), 1) self.assertIsInstance(dists[0], Distribution) self.assertEqual(dists[0].name, "sdl2_dist") self.assertEqual(dists[0].dist_dir, "sdl2-python3") self.assertEqual(dists[0].ndk_api, 21) self.assertEqual( dists[0].recipes, ["hostpython3", "python3", "sdl2", "kivy", "requests"], ) mock_open_dist_info.assert_called_with("sdl2-python3/dist_info.json") mock_open_dist_info.reset_mock()
def test_get_distributions_error_ndk_api_mismatch(self, mock_glob, mock_exists, mock_get_dists): """Test that method :meth:`~pythonforandroid.distribution.Distribution.get_distribution` raises an error in case that we have some distribution already build, with a given `name` and `ndk_api`, and we try to get another distribution with the same `name` but different `ndk_api`. """ expected_dist = Distribution.get_distribution( self.ctx, name="test_prj", recipes=["python3", "kivy"], arch_name=self.TEST_ARCH, ) mock_get_dists.return_value = [expected_dist] mock_glob.return_value = ["sdl2-python3"] with self.assertRaises(BuildInterruptingException) as e: self.setUp_distribution_with_bootstrap( Bootstrap().get_bootstrap("sdl2", self.ctx), allow_replace_dist=False, ndk_api=22, ) self.assertEqual( e.exception.args[0], "Asked for dist with name test_prj with recipes (python3, kivy)" " and NDK API 22, but a dist with this name already exists and has" " either incompatible recipes (python3, kivy) or NDK API 21", )
def test_bootstrap_fry_eggs(self, mock_isdir, mock_sh_mv, mock_sh_rm, mock_listdir): mock_listdir.return_value = [ "jnius", "kivy", "Kivy-1.11.0.dev0-py3.7.egg-info", "pyjnius-1.2.1.dev0-py3.7.egg", ] # prepare bootstrap, context and distribution bs = Bootstrap().get_bootstrap(self.bootstrap_name, self.ctx) self.setUp_distribution_with_bootstrap(bs) # test that fry_eggs runs with a fake distribution site_packages = os.path.join(bs.dist_dir, "_python_bundle", "_python_bundle") bs.fry_eggs(site_packages) mock_listdir.assert_has_calls([ mock.call(site_packages), mock.call( os.path.join(site_packages, "pyjnius-1.2.1.dev0-py3.7.egg")), ]) self.assertEqual(mock_sh_rm.call_args[0][1], "pyjnius-1.2.1.dev0-py3.7.egg") # check that the other mocks we made are actually called mock_isdir.assert_called() mock_sh_mv.assert_called()
def setUp(self): """ Initialize a Context with a Bootstrap and a Distribution to properly test an library recipe, to do so we reuse `BaseClassSetupBootstrap` """ super(TestLibraryRecipe, self).setUp() self.ctx.bootstrap = Bootstrap().get_bootstrap('sdl2', self.ctx) self.setUp_distribution_with_bootstrap(self.ctx.bootstrap)
def test_run_distribute(self, *args): # prepare bootstrap bs = Bootstrap().get_bootstrap(self.bootstrap_name, self.ctx) self.ctx.bootstrap = bs # test dist_dir error with self.assertRaises(SystemExit) as e: bs.run_distribute() self.assertEqual(e.exception.args[0], 1)
def test_get_distribution_no_name(self, mock_exists): """Test that method :meth:`~pythonforandroid.distribution.Distribution.get_distribution` returns the proper result which should `unnamed_dist_1`.""" mock_exists.return_value = False self.ctx.bootstrap = Bootstrap().get_bootstrap("sdl2", self.ctx) dist = Distribution.get_distribution(self.ctx, arch_name=self.TEST_ARCH) self.assertEqual(dist.name, "unnamed_dist_1")
def test_prepare_dist_dir(self, mock_ensure_dir): """A test which will initialize a bootstrap and will check if the method :meth:`~pythonforandroid.bootstrap.Bootstrap.prepare_dist_dir` successfully calls once the method `endure_dir` """ bs = Bootstrap().get_bootstrap("sdl2", self.ctx) bs.prepare_dist_dir("fake_name") mock_ensure_dir.assert_called_once_with(bs.dist_dir)
def test_delete(self, mock_rmtree): """Test that method :meth:`~pythonforandroid.distribution.Distribution.delete` is called once with the proper arguments.""" self.setUp_distribution_with_bootstrap(Bootstrap().get_bootstrap( "sdl2", self.ctx)) self.ctx.bootstrap.distribution.delete() mock_rmtree.assert_called_once_with( self.ctx.bootstrap.distribution.dist_dir)
def setUp(self): """ Initialize a Context with a Bootstrap and a Distribution to properly test a recipe which depends on android's STL library, to do so we reuse `BaseClassSetupBootstrap` """ super().setUp() self.ctx.bootstrap = Bootstrap().get_bootstrap('sdl2', self.ctx) self.setUp_distribution_with_bootstrap(self.ctx.bootstrap) self.ctx.python_recipe = Recipe.get_recipe('python3', self.ctx)
def test_properties(self): """Test that some attributes has the expected result (for now, we check that `__repr__` and `__str__` return the proper values""" self.setUp_distribution_with_bootstrap(Bootstrap().get_bootstrap( "sdl2", self.ctx)) distribution = self.ctx.bootstrap.distribution self.assertEqual(self.ctx, distribution.ctx) expected_repr = ( "<Distribution: name test_prj with recipes (python3, kivy)>") self.assertEqual(distribution.__str__(), expected_repr) self.assertEqual(distribution.__repr__(), expected_repr)
def setUp(self): self.ctx = Context() self.ctx.ndk_api = 21 self.ctx.android_api = 27 self.ctx._sdk_dir = "/opt/android/android-sdk" self.ctx._ndk_dir = "/opt/android/android-ndk" self.ctx.setup_dirs(os.getcwd()) self.ctx.bootstrap = Bootstrap().get_bootstrap("sdl2", self.ctx) self.ctx.bootstrap.distribution = Distribution.get_distribution( self.ctx, name="sdl2", recipes=["python3", "kivy"]) self.ctx.python_recipe = Recipe.get_recipe("python3", self.ctx)
def test_list_bootstraps(self): """A test which will initialize a bootstrap and will check if the method :meth:`~pythonforandroid.bootstrap.Bootstrap.list_bootstraps` returns the expected values, which should be: `empty", `service_only`, `webview` and `sdl2` """ expected_bootstraps = {"empty", "service_only", "webview", "sdl2"} set_of_bootstraps = set(Bootstrap().list_bootstraps()) self.assertEqual( expected_bootstraps, expected_bootstraps & set_of_bootstraps ) self.assertEqual(len(expected_bootstraps), len(set_of_bootstraps))
def test_bootstrap_prepare_build_dir_with_java_src( self, mock_sh_rm, mock_sh_mkdir, mock_listdir, mock_sh_ln, mock_chdir, mock_open, mock_os_unlink, mock_os_path_exists, mock_os_path_isfile, ): """A test which will initialize a bootstrap and will check perform another test for method :meth:`~pythonforandroid.bootstrap.Bootstrap.prepare_build_dir`. In here we will simulate that we have `with_java_src` set to some value. """ self.ctx.symlink_java_src = ["some_java_src"] mock_listdir.return_value = [ "jnius", "kivy", "Kivy-1.11.0.dev0-py3.7.egg-info", "pyjnius-1.2.1.dev0-py3.7.egg", ] # prepare bootstrap bs = Bootstrap().get_bootstrap("sdl2", self.ctx) self.ctx.bootstrap = bs # test that prepare_build_dir runs (notice that we mock # any file/dir creation so we can speed up the tests) bs.prepare_build_dir() # make sure that the open command has been called only once mock_open.assert_called_with("project.properties", "w") # check that the symlink was made 4 times and that self.assertEqual( len(mock_sh_ln.call_args_list), len(mock_listdir.return_value) ) for i, directory in enumerate(mock_listdir.return_value): self.assertTrue( mock_sh_ln.call_args_list[i][0][1].endswith(directory) ) # check that the other mocks we made are actually called mock_sh_rm.assert_called() mock_sh_mkdir.assert_called() mock_chdir.assert_called() mock_os_unlink.assert_called() mock_os_path_exists.assert_called() mock_os_path_isfile.assert_called()
def setUp(self): self.ctx = Context() self.ctx.ndk_api = 21 self.ctx.android_api = 27 self.ctx._sdk_dir = "/opt/android/android-sdk" self.ctx._ndk_dir = "/opt/android/android-ndk" self.ctx.setup_dirs(os.getcwd()) self.ctx.bootstrap = Bootstrap().get_bootstrap("sdl2", self.ctx) self.ctx.bootstrap.distribution = Distribution.get_distribution( self.ctx, name="sdl2", recipes=["python3", "kivy"]) self.ctx.python_recipe = Recipe.get_recipe("python3", self.ctx) # Here we define the expected compiler, which, as per ndk >= r19, # should be the same for all the tests (no more gcc compiler) self.expected_compiler = ("/opt/android/android-ndk/toolchains/" "llvm/prebuilt/linux-x86_64/bin/clang")
def test_save_info(self, mock_open_dist_info, mock_chdir): """Test that method :meth:`~pythonforandroid.distribution.Distribution.save_info` is called once with the proper arguments.""" self.setUp_distribution_with_bootstrap(Bootstrap().get_bootstrap( "sdl2", self.ctx)) self.ctx.hostpython = "/some/fake/hostpython3" self.ctx.python_recipe = Recipe.get_recipe("python3", self.ctx) self.ctx.python_modules = ["requests"] mock_open_dist_info.side_effect = [ mock.mock_open(read_data=json.dumps(dist_info_data)).return_value ] self.ctx.bootstrap.distribution.save_info("/fake_dir") mock_open_dist_info.assert_called_once_with("dist_info.json", "w") mock_open_dist_info.reset_mock()
def test_get_distributions_error_extra_dist_dirs(self): """Test that method :meth:`~pythonforandroid.distribution.Distribution.get_distributions` raises an exception of :class:`~pythonforandroid.util.BuildInterruptingException` in case that we supply the kwargs `extra_dist_dirs`. """ self.setUp_distribution_with_bootstrap(Bootstrap().get_bootstrap( "sdl2", self.ctx)) with self.assertRaises(BuildInterruptingException) as e: self.ctx.bootstrap.distribution.get_distributions( self.ctx, extra_dist_dirs=["/fake/extra/dist_dirs"]) self.assertEqual( e.exception.args[0], "extra_dist_dirs argument to get" "_distributions is not yet implemented", )
def test_build_dist_dirs(self): """A test which will initialize a bootstrap and will check if the directories we set has the values that we expect. Here we test methods: - :meth:`~pythonforandroid.bootstrap.Bootstrap.get_build_dir` - :meth:`~pythonforandroid.bootstrap.Bootstrap.get_dist_dir` - :meth:`~pythonforandroid.bootstrap.Bootstrap.get_common_dir` """ bs = Bootstrap().get_bootstrap("sdl2", self.ctx) self.assertTrue( bs.get_build_dir().endswith("build/bootstrap_builds/sdl2-python3") ) self.assertTrue(bs.get_dist_dir("test_prj").endswith("dists/test_prj")) self.assertTrue( bs.get_common_dir().endswith("pythonforandroid/bootstraps/common") )
def test_attributes(self): """A test which will initialize a bootstrap and will check if the values are the expected. """ bs = Bootstrap().get_bootstrap("sdl2", self.ctx) self.assertEqual(bs.name, "sdl2") self.assertEqual(bs.jni_dir, "sdl2/jni") self.assertEqual(bs.get_build_dir_name(), "sdl2-python3") # test dist_dir error bs.distribution = None with self.assertRaises(SystemExit) as e: bs.dist_dir self.assertEqual(e.exception.args[0], 1) # test dist_dir success self.setUp_distribution_with_bootstrap(bs) self.assertTrue(bs.dist_dir.endswith("dists/test_prj"))
def test_attributes(self): """A test which will initialize a bootstrap and will check if the values are the expected. """ bs = Bootstrap().get_bootstrap("sdl2", self.ctx) self.assertEqual(bs.name, "sdl2") self.assertEqual(bs.jni_dir, "sdl2/jni") self.assertEqual(bs.get_build_dir_name(), "sdl2-python3") # bs.dist_dir should raise an error if there is no distribution to query bs.distribution = None with self.assertRaises(BuildInterruptingException): bs.dist_dir # test dist_dir success self.setUp_distribution_with_bootstrap(bs) expected_folder_name = generate_dist_folder_name( 'test_prj', [self.TEST_ARCH]) self.assertTrue(bs.dist_dir.endswith(f"dists/{expected_folder_name}"))
def test_get_distributions_error_ndk_api(self, mock_glob, mock_exists, mock_open_dist_info): """Test method :meth:`~pythonforandroid.distribution.Distribution.get_distributions` in case that `ndk_api` is not set..which should return a `None`. """ dist_info_data_no_ndk_api = dist_info_data.copy() dist_info_data_no_ndk_api.pop("ndk_api") self.setUp_distribution_with_bootstrap(Bootstrap().get_bootstrap( "sdl2", self.ctx)) mock_glob.return_value = ["sdl2-python3"] mock_open_dist_info.side_effect = [ mock.mock_open( read_data=json.dumps(dist_info_data_no_ndk_api)).return_value ] dists = self.ctx.bootstrap.distribution.get_distributions(self.ctx) self.assertEqual(dists[0].ndk_api, None) mock_open_dist_info.assert_called_with("sdl2-python3/dist_info.json") mock_open_dist_info.reset_mock()
def test_get_distributions_possible_dists(self, mock_get_dists): """Test that method :meth:`~pythonforandroid.distribution.Distribution.get_distributions` returns the proper `:class:`~pythonforandroid.distribution.Distribution` in case that we already have it build and we request the same `:class:`~pythonforandroid.distribution.Distribution`. """ expected_dist = Distribution.get_distribution( self.ctx, name="test_prj", recipes=["python3", "kivy"], arch_name=self.TEST_ARCH, ) mock_get_dists.return_value = [expected_dist] self.setUp_distribution_with_bootstrap(Bootstrap().get_bootstrap( "sdl2", self.ctx), name="test_prj") dists = self.ctx.bootstrap.distribution.get_distributions(self.ctx) self.assertEqual(dists[0], expected_dist)
def test_bootstrap_prepare_build_dir(self, mock_os_makedirs, mock_shutil_copy, mock_chdir, mock_open): """A test which will initialize a bootstrap and will check if the method :meth:`~pythonforandroid.bootstrap.Bootstrap.prepare_build_dir` successfully calls the methods that we need to prepare a build dir. """ # prepare bootstrap bs = Bootstrap().get_bootstrap("service_only", self.ctx) self.ctx.bootstrap = bs # test that prepare_build_dir runs (notice that we mock # any file/dir creation so we can speed up the tests) bs.prepare_build_dir() # make sure that the open command has been called only once mock_open.assert_called_once_with("project.properties", "w") # check that the other mocks we made are actually called mock_os_makedirs.assert_called() mock_shutil_copy.assert_called() mock_chdir.assert_called()
def test_distribute_methods(self, mock_build_dir, mock_bs_dir, mock_glob, mock_shprint): # prepare arch, bootstrap and distribution arch = ArchARMv7_a(self.ctx) bs = Bootstrap().get_bootstrap(self.bootstrap_name, self.ctx) self.setUp_distribution_with_bootstrap(bs) # a convenient method to reset mocks in one shot def reset_mocks(): mock_glob.reset_mock() mock_shprint.reset_mock() mock_build_dir.reset_mock() mock_bs_dir.reset_mock() # test distribute_libs mock_glob.return_value = [ "/fake_dir/libsqlite3.so", "/fake_dir/libpng16.so", ] bs.distribute_libs(arch, [self.ctx.get_libs_dir(arch.arch)]) libs_dir = os.path.join("libs", arch.arch) # we expect two calls to glob/copy command via shprint self.assertEqual(len(mock_glob.call_args_list), 2) self.assertEqual(len(mock_shprint.call_args_list), 2) for i, lib in enumerate(mock_glob.return_value): self.assertEqual( mock_shprint.call_args_list[i], mock.call(sh.cp, "-a", lib, libs_dir), ) mock_build_dir.assert_called() mock_bs_dir.assert_called_once_with(libs_dir) reset_mocks() # test distribute_javaclasses mock_glob.return_value = ["/fakedir/java_file.java"] bs.distribute_javaclasses(self.ctx.javaclass_dir) mock_glob.assert_called_once_with(self.ctx.javaclass_dir) mock_build_dir.assert_called_with(self.ctx.javaclass_dir) mock_bs_dir.assert_called_once_with("src") self.assertEqual( mock_shprint.call_args, mock.call(sh.cp, "-a", "/fakedir/java_file.java", "src"), ) reset_mocks() # test distribute_aars mock_glob.return_value = ["/fakedir/file.aar"] bs.distribute_aars(arch) mock_build_dir.assert_called_with(self.ctx.aars_dir) # We expect three calls to shprint: unzip, cp, cp zip_call, kw = mock_shprint.call_args_list[0] self.assertEqual(zip_call[0], sh.unzip) self.assertEqual(zip_call[2], "/fakedir/file.aar") cp_java_call, kw = mock_shprint.call_args_list[1] self.assertEqual(cp_java_call[0], sh.cp) self.assertTrue(cp_java_call[2].endswith("classes.jar")) self.assertEqual(cp_java_call[3], "libs/file.jar") cp_libs_call, kw = mock_shprint.call_args_list[2] self.assertEqual(cp_libs_call[0], sh.cp) self.assertEqual(cp_libs_call[2], "/fakedir/file.aar") self.assertEqual(cp_libs_call[3], libs_dir) mock_bs_dir.assert_has_calls([mock.call("libs"), mock.call(libs_dir)]) mock_glob.assert_called()
def test_run_distribute( self, mock_sh_cp, mock_sh_rm, mock_listdir, mock_chdir, mock_ensure_dir, mock_strip_libraries, mock_create_python_bundle, mock_open_dist_files, mock_open_sdl2_files, mock_open_webview_files, mock_open_service_only_files, ): """ A test for any overwritten method of `~pythonforandroid.bootstrap.Bootstrap.run_distribute`. Here we mock any file/dir operation that it could slow down our tests, and there is a lot to mock, because the `run_distribute` method it should take care of prepare all compiled files to generate the final `apk`. The targets of this test will be: - :meth:`~pythonforandroid.bootstraps.sdl2.BootstrapSdl2 .run_distribute` - :meth:`~pythonforandroid.bootstraps.service_only .ServiceOnlyBootstrap.run_distribute` - :meth:`~pythonforandroid.bootstraps.webview.WebViewBootstrap .run_distribute` - :meth:`~pythonforandroid.bootstraps.empty.EmptyBootstrap. run_distribute` Here we will tests all those methods that are specific for each class. """ # prepare bootstrap and distribution bs = Bootstrap().get_bootstrap(self.bootstrap_name, self.ctx) bs.build_dir = bs.get_build_dir() self.setUp_distribution_with_bootstrap(bs) self.ctx.hostpython = "/some/fake/hostpython3" self.ctx.python_recipe = Recipe.get_recipe("python3", self.ctx) self.ctx.python_modules = ["requests"] self.ctx.archs = [ArchARMv7_a(self.ctx)] bs.run_distribute() mock_open_dist_files.assert_called_once_with("dist_info.json", "w") mock_open_bootstraps = { "sdl2": mock_open_sdl2_files, "webview": mock_open_webview_files, "service_only": mock_open_service_only_files, } expected_open_calls = { "sdl2": [ mock.call("local.properties", "w"), mock.call("blacklist.txt", "a"), ], "webview": [mock.call("local.properties", "w")], "service_only": [mock.call("local.properties", "w")], } mock_open_bs = mock_open_bootstraps[self.bootstrap_name] # test that the expected calls has been called for expected_call in expected_open_calls[self.bootstrap_name]: self.assertIn(expected_call, mock_open_bs.call_args_list) # test that the write function has been called with the expected args self.assertIn( mock.call().__enter__().write("sdk.dir=/opt/android/android-sdk"), mock_open_bs.mock_calls, ) if self.bootstrap_name == "sdl2": self.assertIn( mock.call().__enter__().write( "\nsqlite3/*\nlib-dynload/_sqlite3.so\n"), mock_open_bs.mock_calls, ) # check that the other mocks we made are actually called mock_sh_rm.assert_called() mock_sh_cp.assert_called() mock_chdir.assert_called() mock_listdir.assert_called() mock_strip_libraries.assert_called() mock_create_python_bundle.assert_called()