aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside6/tests/tools/pyside6-android-deploy/test_pyside6_android_deploy.py
diff options
context:
space:
mode:
Diffstat (limited to 'sources/pyside6/tests/tools/pyside6-android-deploy/test_pyside6_android_deploy.py')
-rw-r--r--sources/pyside6/tests/tools/pyside6-android-deploy/test_pyside6_android_deploy.py274
1 files changed, 274 insertions, 0 deletions
diff --git a/sources/pyside6/tests/tools/pyside6-android-deploy/test_pyside6_android_deploy.py b/sources/pyside6/tests/tools/pyside6-android-deploy/test_pyside6_android_deploy.py
new file mode 100644
index 000000000..ec575e923
--- /dev/null
+++ b/sources/pyside6/tests/tools/pyside6-android-deploy/test_pyside6_android_deploy.py
@@ -0,0 +1,274 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import importlib
+import os
+import re
+import shutil
+import sys
+import tempfile
+import unittest
+import subprocess
+from pathlib import Path
+from unittest import mock
+from unittest.mock import patch
+
+sys.path.append(os.fspath(Path(__file__).resolve().parents[2]))
+from init_paths import init_test_paths # noqa: E402
+init_test_paths(False)
+
+
+class DeployTestBase(unittest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ cls.pyside_root = Path(__file__).parents[5].resolve()
+ cls.example_root = cls.pyside_root / "examples"
+ cls.temp_dir = tempfile.mkdtemp()
+ cls.current_dir = Path.cwd()
+ cls.pyside_wheel = Path("/tmp/PySide6-6.5.0a1-6.5.0-cp37-abi3-android_x86_64.whl")
+ cls.shiboken_wheel = Path("/tmp/shiboken6-6.5.0a1-6.5.0-cp37-abi3-android_x86_64.whl")
+ cls.ndk_path = Path("/tmp/android_sdk/ndk/25.2.9519653")
+ cls.sdk_path = Path("/tmp/android_sdk")
+ pyside_tools = cls.pyside_root / "sources" / "pyside-tools"
+
+ # install extra python dependencies
+ android_requirements_file = pyside_tools / "requirements-android.txt"
+ with open(android_requirements_file, 'r', encoding='UTF-8') as file:
+ while line := file.readline():
+ dependent_package = line.rstrip()
+ if not bool(importlib.util.find_spec(dependent_package)):
+ command = [sys.executable, "-m", "pip", "install", dependent_package]
+ subprocess.run(command)
+
+ sys.path.append(str(pyside_tools))
+ cls.deploy_lib = importlib.import_module("deploy_lib")
+ cls.android_deploy = importlib.import_module("android_deploy")
+ sys.modules["android_deploy"] = cls.android_deploy
+
+ # required for comparing long strings
+ cls.maxDiff = None
+
+ # print no outputs to stdout
+ sys.stdout = mock.MagicMock()
+
+ def tearDown(self) -> None:
+ super().tearDown()
+ os.chdir(self.current_dir)
+
+ @classmethod
+ def tearDownClass(cls) -> None:
+ shutil.rmtree(Path(cls.temp_dir))
+
+
+@patch("deploy_lib.android.android_config.extract_and_copy_jar")
+class TestPySide6AndroidDeployWidgets(DeployTestBase):
+ @classmethod
+ def setUpClass(cls):
+ super().setUpClass()
+ example_widget_application = cls.example_root / "gui" / "analogclock"
+ cls.temp_example = Path(
+ shutil.copytree(example_widget_application, Path(cls.temp_dir) / "analogclock")
+ ).resolve()
+
+ def setUp(self):
+ os.chdir(self.temp_example)
+ self.config_file = self.temp_example / "pysidedeploy.spec"
+ self.buildozer_config = self.temp_example / "buildozer.spec"
+
+ @patch("deploy_lib.android.android_config.AndroidConfig._find_local_libs")
+ @patch("deploy_lib.android.android_config.AndroidConfig._find_dependent_qt_modules")
+ @patch("deploy_lib.android.android_config.find_qtlibs_in_wheel")
+ def test_dry_run(self, mock_qtlibs, mock_extraqtmodules, mock_local_libs, mock_extract_jar):
+ mock_qtlibs.return_value = self.pyside_wheel / "PySide6/Qt/lib"
+ mock_extraqtmodules.return_value = []
+ dependent_plugins = ["platforms_qtforandroid",
+ "platforminputcontexts_qtvirtualkeyboardplugin",
+ "iconengines_qsvgicon"]
+ mock_local_libs.return_value = [], dependent_plugins
+ self.android_deploy.main(name="android_app", shiboken_wheel=self.shiboken_wheel,
+ pyside_wheel=self.pyside_wheel, ndk_path=self.ndk_path,
+ dry_run=True, force=True)
+
+ self.assertEqual(mock_extract_jar.call_count, 0)
+ self.assertEqual(mock_qtlibs.call_count, 1)
+ self.assertEqual(mock_extraqtmodules.call_count, 1)
+ self.assertEqual(mock_local_libs.call_count, 1)
+
+ @patch("deploy_lib.android.buildozer.BuildozerConfig._BuildozerConfig__find_jars")
+ @patch("deploy_lib.android.android_config.AndroidConfig.recipes_exist")
+ @patch("deploy_lib.android.android_config.AndroidConfig._find_dependent_qt_modules")
+ @patch("deploy_lib.android.android_config.find_qtlibs_in_wheel")
+ def test_config(self, mock_qtlibs, mock_extraqtmodules, mock_recipes_exist, mock_find_jars,
+ mock_extract_jar):
+ jar_dir = "tmp/jar/PySide6/jar"
+ mock_extract_jar.return_value = Path(jar_dir)
+ mock_qtlibs.return_value = self.pyside_wheel / "PySide6/Qt/lib"
+ mock_extraqtmodules.return_value = []
+ mock_recipes_exist.return_value = True
+ jars, init_classes = ["/tmp/jar/PySide6/jar/Qt6Android.jar",
+ "/tmp/jar/PySide6/jar/Qt6AndroidBindings.jar"], []
+ mock_find_jars.return_value = jars, init_classes
+
+ self.android_deploy.main(name="android_app", shiboken_wheel=self.shiboken_wheel,
+ pyside_wheel=self.pyside_wheel, ndk_path=self.ndk_path,
+ init=True, force=True, keep_deployment_files=True)
+
+ self.assertEqual(mock_extract_jar.call_count, 1)
+ self.assertEqual(mock_qtlibs.call_count, 1)
+ self.assertEqual(mock_extraqtmodules.call_count, 1)
+ self.assertEqual(mock_recipes_exist.call_count, 1)
+ self.assertEqual(mock_find_jars.call_count, 1)
+ self.assertTrue(self.config_file.exists())
+ self.assertTrue(self.buildozer_config.exists())
+
+ # test config file contents
+ config_obj = self.deploy_lib.BaseConfig(config_file=self.config_file)
+ self.assertEqual(config_obj.get_value("app", "input_file"), "main.py")
+ self.assertEqual(config_obj.get_value("python", "android_packages"),
+ "buildozer==1.5.0,cython==0.29.33")
+ self.assertEqual(config_obj.get_value("android", "wheel_pyside"),
+ str(self.pyside_wheel.resolve()))
+ self.assertEqual(config_obj.get_value("android", "wheel_shiboken"),
+ str(self.shiboken_wheel.resolve()))
+ self.assertEqual(config_obj.get_value("buildozer", "mode"), "debug")
+ self.assertEqual(config_obj.get_value("buildozer", "recipe_dir"),
+ '')
+ self.assertEqual(config_obj.get_value("buildozer", "jars_dir"),
+ str(self.temp_example / jar_dir))
+ self.assertIn(str(self.ndk_path), config_obj.get_value("buildozer", "ndk_path"))
+ self.assertEqual(config_obj.get_value("buildozer", "sdk_path"), '')
+ expected_modules = {"Core", "Gui"}
+ obtained_modules = set(config_obj.get_value("qt", "modules").split(","))
+ self.assertEqual(obtained_modules, expected_modules)
+ expected_local_libs = ""
+ self.assertEqual(config_obj.get_value("buildozer", "local_libs"),
+ expected_local_libs)
+ self.assertEqual(config_obj.get_value("buildozer", "arch"), "x86_64")
+
+ # test buildozer config file contents
+ buildozer_config_obj = self.deploy_lib.BaseConfig(config_file=self.buildozer_config)
+ obtained_jars = set(buildozer_config_obj.get_value("app", "android.add_jars").split(','))
+ expected_jars = set(jars)
+ self.assertEqual(obtained_jars, expected_jars)
+ obtained_extra_args = buildozer_config_obj.get_value("app", "p4a.extra_args")
+ extra_args_patrn = re.compile("--qt-libs=(?P<modules>.*) --load-local-libs="
+ "(?P<local_libs>.*) --init-classes=(?P<init_classes>.*)")
+ match = extra_args_patrn.search(obtained_extra_args)
+ obtained_modules = match.group("modules").split(',')
+ obtained_local_libs = match.group("local_libs")
+ obtained_init_classes = match.group("init_classes")
+ self.assertEqual(set(obtained_modules), expected_modules)
+ self.assertEqual(obtained_local_libs, expected_local_libs)
+ self.assertEqual(obtained_init_classes, '')
+ expected_include_exts = "py,png,jpg,kv,atlas,qml,js"
+ obtained_include_exts = buildozer_config_obj.get_value("app", "source.include_exts")
+ self.assertEqual(expected_include_exts, obtained_include_exts)
+
+ self.config_file.unlink()
+ self.buildozer_config.unlink()
+
+ def test_errors(self, mock_extract_jar):
+ # test if error raises for non existing NDK
+ with self.assertRaises(FileNotFoundError) as context:
+ self.android_deploy.main(name="android_app", shiboken_wheel=self.shiboken_wheel,
+ pyside_wheel=self.pyside_wheel, force=True)
+ self.assertTrue("Unable to find Android NDK" in str(context.exception))
+
+ # test when cwd() is not project_dir
+ os.chdir(self.current_dir)
+ with self.assertRaises(RuntimeError) as context:
+ self.android_deploy.main(name="android_app", shiboken_wheel=self.shiboken_wheel,
+ pyside_wheel=self.pyside_wheel, init=True, force=True)
+ self.assertTrue("For Android deployment to work" in str(context.exception))
+
+
+@patch("deploy_lib.config.run_qmlimportscanner")
+@patch("deploy_lib.android.android_config.extract_and_copy_jar")
+class TestPySide6AndroidDeployQml(DeployTestBase):
+ @classmethod
+ def setUpClass(cls):
+ super().setUpClass()
+ # setting up example
+ example_qml_application = cls.example_root / "quick" / "models" / "stringlistmodel"
+ cls.temp_qml_example = Path(
+ shutil.copytree(example_qml_application, Path(cls.temp_dir) / "stringlistmodel")
+ ).resolve()
+
+ def setUp(self):
+ os.chdir(self.temp_qml_example)
+ self.config_file = self.temp_qml_example / "pysidedeploy.spec"
+ self.buildozer_config_file = self.temp_qml_example / "buildozer.spec"
+ (self.temp_qml_example / "stringlistmodel.py").rename(self.temp_qml_example / "main.py")
+ (self.temp_qml_example / "stringlistmodel.pyproject").unlink()
+
+ @patch("deploy_lib.android.android_config.AndroidConfig._find_local_libs")
+ @patch("deploy_lib.android.buildozer.BuildozerConfig._BuildozerConfig__find_jars")
+ @patch("deploy_lib.android.android_config.AndroidConfig.recipes_exist")
+ @patch("deploy_lib.android.android_config.AndroidConfig._find_dependent_qt_modules")
+ @patch("deploy_lib.android.android_config.find_qtlibs_in_wheel")
+ def test_config_with_Qml(self, mock_qtlibs, mock_extraqtmodules, mock_recipes_exist,
+ mock_find_jars, mock_local_libs, mock_extract_jar,
+ mock_qmlimportscanner):
+ # setting up mocks
+ jar_dir = "tmp/jar/PySide6/jar"
+ mock_extract_jar.return_value = Path(jar_dir)
+ mock_qtlibs.return_value = self.pyside_wheel / "PySide6/Qt/lib"
+ mock_extraqtmodules.return_value = ['Qml', 'Network', 'QmlModels', 'OpenGL']
+ mock_recipes_exist.return_value = True
+ jars, init_classes = ["/tmp/jar/PySide6/jar/Qt6Android.jar",
+ "/tmp/jar/PySide6/jar/Qt6AndroidBindings.jar",
+ "/tmp/jar/PySide6/jar/Qt6AndroidNetworkInformationBackend.jar",
+ "/tmp/jar/PySide6/jar/Qt6AndroidNetwork.jar"], []
+ mock_find_jars.return_value = jars, init_classes
+ dependent_plugins = ["platforms_qtforandroid",
+ "platforminputcontexts_qtvirtualkeyboardplugin",
+ "iconengines_qsvgicon"]
+ mock_local_libs.return_value = [], dependent_plugins
+ mock_qmlimportscanner.return_value = ["QtQuick"]
+
+ self.android_deploy.main(name="android_app", shiboken_wheel=self.shiboken_wheel,
+ pyside_wheel=self.pyside_wheel, ndk_path=self.ndk_path,
+ init=True, force=True, keep_deployment_files=True)
+
+ self.assertEqual(mock_extract_jar.call_count, 1)
+ self.assertEqual(mock_qtlibs.call_count, 1)
+ self.assertEqual(mock_extraqtmodules.call_count, 1)
+ self.assertEqual(mock_recipes_exist.call_count, 1)
+ self.assertEqual(mock_find_jars.call_count, 1)
+ self.assertEqual(mock_qmlimportscanner.call_count, 1)
+ self.assertTrue(self.config_file.exists())
+ self.assertTrue(self.buildozer_config_file.exists())
+
+ config_obj = self.deploy_lib.BaseConfig(config_file=self.config_file)
+ expected_modules = {"Quick", "Core", "Gui", "Network", "Qml", "QmlModels", "OpenGL"}
+ obtained_modules = set(config_obj.get_value("qt", "modules").split(","))
+ self.assertEqual(obtained_modules, expected_modules)
+ expected_local_libs = ""
+ self.assertEqual(config_obj.get_value("buildozer", "local_libs"),
+ expected_local_libs)
+ expected_qt_plugins = set(dependent_plugins)
+ obtained_qt_plugins = set(config_obj.get_value("android", "plugins").split(","))
+ self.assertEqual(expected_qt_plugins, obtained_qt_plugins)
+
+ # test buildozer config file contents
+ buildozer_config_obj = self.deploy_lib.BaseConfig(config_file=self.buildozer_config_file)
+ obtained_jars = set(buildozer_config_obj.get_value("app", "android.add_jars").split(','))
+ expected_jars = set(jars)
+ self.assertEqual(obtained_jars, expected_jars)
+ obtained_extra_args = buildozer_config_obj.get_value("app", "p4a.extra_args")
+ extra_args_patrn = re.compile("--qt-libs=(?P<modules>.*) --load-local-libs="
+ "(?P<local_libs>.*) --init-classes=(?P<init_classes>.*)")
+ match = extra_args_patrn.search(obtained_extra_args)
+ obtained_modules = match.group("modules").split(',')
+ obtained_local_libs = match.group("local_libs")
+ obtained_init_classes = match.group("init_classes")
+ self.assertEqual(set(obtained_modules), expected_modules)
+ self.assertEqual(obtained_local_libs, expected_local_libs)
+ self.assertEqual(obtained_init_classes, '')
+
+ self.config_file.unlink()
+ self.buildozer_config_file.unlink()
+
+
+if __name__ == "__main__":
+ unittest.main()