Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TargetAndroid tests #1127

Merged
merged 2 commits into from
May 28, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 136 additions & 39 deletions tests/targets/test_android.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import os
import pytest
import codecs
import tempfile
from unittest import mock

import pytest

import buildozer as buildozer_module
from buildozer import Buildozer
from buildozer.targets.android import TargetAndroid
from unittest import mock


def patch_buildozer(method):
Expand Down Expand Up @@ -51,25 +52,110 @@ def patch_platform(platform):


class TestTargetAndroid:

@staticmethod
def default_specfile_path():
return os.path.join(os.path.dirname(buildozer_module.__file__), "default.spec")

def setup_method(self):
"""Creates a temporary spec file containing the content of the default.spec."""
self.specfile = tempfile.NamedTemporaryFile(suffix=".spec", delete=False)
default_spec = codecs.open(self.default_specfile_path(), encoding="utf-8")
self.specfile.write(default_spec.read().encode("utf-8"))
self.specfile.close()
self.buildozer = Buildozer(filename=self.specfile.name, target="android")
self.target_android = TargetAndroid(self.buildozer)
"""
Create a temporary directory that will contain the spec file and will
serve as the root_dir.
"""
self.temp_dir = tempfile.TemporaryDirectory()

def tear_method(self):
"""Deletes the temporary spec file."""
os.unlink(self.specfile.name)
"""
Remove the temporary directory created in self.setup_method.
"""
self.temp_dir.cleanup()

def init_target(self, options=None):
"""
Create a buildozer.spec file in the temporary directory and init the
Buildozer and TargetAndroid instances.

The optional argument can be used to overwrite the config options in
the buildozer.spec file, e.g.:

self.init_target({'title': 'Test App'})

will replace line 4 of the default spec file.
"""
if options is None:
options = {}

spec_path = os.path.join(self.temp_dir.name, 'buildozer.spec')

with open(TestTargetAndroid.default_specfile_path()) as f:
default_spec = f.readlines()

spec = []
for line in default_spec:
if line.strip():
key = line.split()[0]

if key.startswith('#'):
key = key[1:]

if key in options:
line = '{} = {}\n'.format(key, options[key])

spec.append(line)

with open(spec_path, 'w') as f:
f.writelines(spec)

self.buildozer = Buildozer(filename=spec_path, target='android')
self.target_android = TargetAndroid(self.buildozer)

def call_build_package(self):
"""
Call the build_package() method of the tested TargetAndroid instance,
patching the functions that would otherwise produce side-effects.

Return the mocked execute_build_package() method of the TargetAndroid
instance so that tests can easily check which command-line arguments
would be passed on to python-for-android's toolchain.
"""
expected_dist_dir = (
'{buildozer_dir}/android/platform/build-armeabi-v7a/dists/myapp__armeabi-v7a'.format(
buildozer_dir=self.buildozer.buildozer_dir)
)

with patch_target_android(
'_update_libraries_references'
) as m_update_libraries_references, patch_target_android(
'_generate_whitelist'
) as m_generate_whitelist, mock.patch(
'buildozer.targets.android.TargetAndroid.execute_build_package'
) as m_execute_build_package, mock.patch(
'buildozer.targets.android.copyfile'
) as m_copyfile, mock.patch(
'buildozer.targets.android.os.listdir'
) as m_listdir:
m_listdir.return_value = ['30.0.0-rc2']
self.target_android.build_package()

assert m_listdir.call_count == 1
assert m_update_libraries_references.call_args_list == [
mock.call(expected_dist_dir)
]
assert m_generate_whitelist.call_args_list == [mock.call(expected_dist_dir)]
assert m_copyfile.call_args_list == [
mock.call(
'{expected_dist_dir}/bin/MyApplication-0.1-debug.apk'.format(
expected_dist_dir=expected_dist_dir
),
'{bin_dir}/myapp-0.1-armeabi-v7a-debug.apk'.format(bin_dir=self.buildozer.bin_dir),
)
]

return m_execute_build_package

def test_init(self):
"""Tests init defaults."""
self.init_target()
assert self.target_android._arch == "armeabi-v7a"
assert self.target_android._build_dir.endswith(
".buildozer/android/platform/build-armeabi-v7a"
Expand Down Expand Up @@ -100,6 +186,7 @@ def test_init_positional_buildozer(self):

def test_sdkmanager(self):
"""Tests the _sdkmanager() method."""
self.init_target()
kwargs = {}
with patch_buildozer_cmd() as m_cmd, patch_buildozer_cmd_expect() as m_cmd_expect, patch_os_isfile() as m_isfile:
m_isfile.return_value = True
Expand All @@ -119,6 +206,7 @@ def test_sdkmanager(self):

def test_check_requirements(self):
"""Basic tests for the check_requirements() method."""
self.init_target()
assert not hasattr(self.target_android, "adb_cmd")
assert not hasattr(self.target_android, "javac_cmd")
assert "PATH" not in self.buildozer.environ
Expand All @@ -139,6 +227,7 @@ def test_check_requirements(self):

def test_check_configuration_tokens(self):
"""Basic tests for the check_configuration_tokens() method."""
self.init_target()
with mock.patch(
"buildozer.targets.android.Target.check_configuration_tokens"
) as m_check_configuration_tokens:
Expand All @@ -148,6 +237,7 @@ def test_check_configuration_tokens(self):
@pytest.mark.parametrize("platform", ["linux", "darwin"])
def test_install_android_sdk(self, platform):
"""Basic tests for the _install_android_sdk() method."""
self.init_target()
with patch_buildozer_file_exists() as m_file_exists, patch_buildozer_download() as m_download:
m_file_exists.return_value = True
sdk_dir = self.target_android._install_android_sdk()
Expand Down Expand Up @@ -178,28 +268,8 @@ def test_install_android_sdk(self, platform):

def test_build_package(self):
"""Basic tests for the build_package() method."""
expected_dist_dir = (
"{buildozer_dir}/android/platform/build-armeabi-v7a/dists/myapp__armeabi-v7a".format(
buildozer_dir=self.buildozer.buildozer_dir)
)
with patch_target_android(
"_update_libraries_references"
) as m_update_libraries_references, patch_target_android(
"_generate_whitelist"
) as m_generate_whitelist, mock.patch(
"buildozer.targets.android.TargetAndroid.execute_build_package"
) as m_execute_build_package, mock.patch(
"buildozer.targets.android.copyfile"
) as m_copyfile, mock.patch(
"buildozer.targets.android.os.listdir"
) as m_listdir:
m_listdir.return_value = ["30.0.0-rc2"]
self.target_android.build_package()
assert m_listdir.call_count == 1
assert m_update_libraries_references.call_args_list == [
mock.call(expected_dist_dir)
]
assert m_generate_whitelist.call_args_list == [mock.call(expected_dist_dir)]
self.init_target()
m_execute_build_package = self.call_build_package()
assert m_execute_build_package.call_args_list == [
mock.call(
[
Expand All @@ -217,11 +287,38 @@ def test_build_package(self):
]
)
]
assert m_copyfile.call_args_list == [

def test_build_package_intent_filters(self):
"""
The build_package() method should honour the manifest.intent_filters
config option.
"""
filters_path = os.path.join(self.temp_dir.name, 'filters.xml')

with open(filters_path, 'w') as f:
f.write('<?xml version="1.0" encoding="utf-8"?>')

self.init_target({
'android.manifest.intent_filters': 'filters.xml'
})

m_execute_build_package = self.call_build_package()

assert m_execute_build_package.call_args_list == [
mock.call(
"{expected_dist_dir}/bin/MyApplication-0.1-debug.apk".format(
expected_dist_dir=expected_dist_dir
),
"{bin_dir}/myapp-0.1-armeabi-v7a-debug.apk".format(bin_dir=self.buildozer.bin_dir),
[
('--name', "'My Application'"),
('--version', '0.1'),
('--package', 'org.test.myapp'),
('--minsdk', '21'),
('--ndk-api', '21'),
('--private', '{buildozer_dir}/android/app'.format(buildozer_dir=self.buildozer.buildozer_dir)),
('--android-entrypoint', 'org.kivy.android.PythonActivity'),
('--android-apptheme', '@android:style/Theme.NoTitleBar'),
('--orientation', 'portrait'),
('--window',),
('--intent-filters', os.path.realpath(filters_path)),
('debug',),
]
)
]