-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Add unittest for module pythonforandroid.archs
#1842
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
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,261 @@ | ||
import os | ||
|
||
import unittest | ||
|
||
try: | ||
from unittest import mock | ||
except ImportError: | ||
# `Python 2` or lower than `Python 3.3` does not | ||
# have the `unittest.mock` module built-in | ||
import mock | ||
from pythonforandroid.bootstrap import Bootstrap | ||
from pythonforandroid.distribution import Distribution | ||
from pythonforandroid.recipe import Recipe | ||
from pythonforandroid.build import Context | ||
from pythonforandroid.util import BuildInterruptingException | ||
from pythonforandroid.archs import ( | ||
Arch, | ||
ArchARM, | ||
ArchARMv7_a, | ||
ArchAarch_64, | ||
Archx86, | ||
Archx86_64, | ||
) | ||
|
||
expected_env_gcc_keys = { | ||
"CFLAGS", | ||
"LDFLAGS", | ||
"CXXFLAGS", | ||
"TOOLCHAIN_PREFIX", | ||
"TOOLCHAIN_VERSION", | ||
"CC", | ||
"CXX", | ||
"AR", | ||
"RANLIB", | ||
"LD", | ||
"LDSHARED", | ||
"STRIP", | ||
"MAKE", | ||
"READELF", | ||
"NM", | ||
"BUILDLIB_PATH", | ||
"PATH", | ||
"ARCH", | ||
"NDK_API", | ||
} | ||
|
||
|
||
class ArchSetUpBaseClass(object): | ||
ctx = None | ||
|
||
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) | ||
|
||
|
||
class TestArch(ArchSetUpBaseClass, unittest.TestCase): | ||
def test_arch(self): | ||
arch = Arch(self.ctx) | ||
with self.assertRaises(AttributeError) as e1: | ||
arch.__str__() | ||
self.assertEqual( | ||
e1.exception.args[0], "'Arch' object has no attribute 'arch'" | ||
) | ||
with self.assertRaises(AttributeError) as e2: | ||
getattr(arch, "target") | ||
self.assertEqual( | ||
e2.exception.args[0], "'NoneType' object has no attribute 'split'" | ||
) | ||
self.assertIsNone(arch.toolchain_prefix) | ||
self.assertIsNone(arch.command_prefix) | ||
self.assertIsInstance(arch.include_dirs, list) | ||
|
||
|
||
class TestArchARM(ArchSetUpBaseClass, unittest.TestCase): | ||
# Here we mock two functions: | ||
# - `ensure_dir` because we don't want to create any directory | ||
# - `find_executable` because otherwise we will | ||
# get an error when trying to find the compiler (we are setting some fake | ||
# paths for our android sdk and ndk so probably will not exist) | ||
@mock.patch("pythonforandroid.archs.find_executable") | ||
@mock.patch("pythonforandroid.build.ensure_dir") | ||
def test_arch_arm(self, mock_ensure_dir, mock_find_executable): | ||
mock_find_executable.return_value = "arm-linux-androideabi-gcc" | ||
mock_ensure_dir.return_value = True | ||
|
||
arch = ArchARM(self.ctx) | ||
self.assertEqual(arch.arch, "armeabi") | ||
self.assertEqual(arch.__str__(), "armeabi") | ||
self.assertEqual(arch.toolchain_prefix, "arm-linux-androideabi") | ||
self.assertEqual(arch.command_prefix, "arm-linux-androideabi") | ||
self.assertEqual(arch.target, "armv7a-none-linux-androideabi") | ||
self.assertEqual(arch.platform_dir, "arch-arm") | ||
arch = ArchARM(self.ctx) | ||
|
||
# Check environment flags | ||
env = arch.get_env() | ||
self.assertIsInstance(env, dict) | ||
self.assertEqual( | ||
expected_env_gcc_keys, set(env.keys()) & expected_env_gcc_keys | ||
) | ||
|
||
# check gcc compilers | ||
self.assertEqual(env["CC"].split()[0], "arm-linux-androideabi-gcc") | ||
self.assertEqual(env["CXX"].split()[0], "arm-linux-androideabi-g++") | ||
# check android binaries | ||
self.assertEqual(env["AR"], "arm-linux-androideabi-ar") | ||
self.assertEqual(env["LD"], "arm-linux-androideabi-ld") | ||
self.assertEqual(env["RANLIB"], "arm-linux-androideabi-ranlib") | ||
self.assertEqual( | ||
env["STRIP"].split()[0], "arm-linux-androideabi-strip" | ||
) | ||
self.assertEqual( | ||
env["READELF"].split()[0], "arm-linux-androideabi-readelf" | ||
) | ||
self.assertEqual(env["NM"].split()[0], "arm-linux-androideabi-nm") | ||
|
||
# check that cflags are in gcc | ||
self.assertIn(env["CFLAGS"], env["CC"]) | ||
|
||
# check that flags aren't in gcc and also check ccache | ||
self.ctx.ccache = "/usr/bin/ccache" | ||
env = arch.get_env(with_flags_in_cc=False) | ||
self.assertNotIn(env["CFLAGS"], env["CC"]) | ||
self.assertEqual(env["USE_CCACHE"], "1") | ||
self.assertEqual(env["NDK_CCACHE"], "/usr/bin/ccache") | ||
|
||
# Check exception in case that CC is not found | ||
mock_find_executable.return_value = None | ||
with self.assertRaises(BuildInterruptingException) as e: | ||
arch.get_env() | ||
self.assertEqual( | ||
e.exception.args[0], | ||
"Couldn't find executable for CC. This indicates a problem " | ||
"locating the arm-linux-androideabi-gcc executable in the Android " | ||
"NDK, not that you don't have a normal compiler installed. " | ||
"Exiting.", | ||
) | ||
|
||
|
||
class TestArchARMv7a(ArchSetUpBaseClass, unittest.TestCase): | ||
# Here we mock the same functions than the previous tests plus `glob`, | ||
# so we make sure that the glob result is the expected even if the folder | ||
# doesn't exist, which is probably the case. This has to be done because | ||
# here we tests the `get_env` with clang | ||
@mock.patch("pythonforandroid.archs.glob") | ||
@mock.patch("pythonforandroid.archs.find_executable") | ||
@mock.patch("pythonforandroid.build.ensure_dir") | ||
def test_arch_armv7a( | ||
AndreMiras marked this conversation as resolved.
Show resolved
Hide resolved
|
||
self, mock_ensure_dir, mock_find_executable, mock_glob | ||
): | ||
mock_find_executable.return_value = "arm-linux-androideabi-gcc" | ||
mock_ensure_dir.return_value = True | ||
mock_glob.return_value = ["llvm"] | ||
|
||
arch = ArchARMv7_a(self.ctx) | ||
self.assertEqual(arch.arch, "armeabi-v7a") | ||
self.assertEqual(arch.__str__(), "armeabi-v7a") | ||
self.assertEqual(arch.toolchain_prefix, "arm-linux-androideabi") | ||
self.assertEqual(arch.command_prefix, "arm-linux-androideabi") | ||
self.assertEqual(arch.target, "armv7a-none-linux-androideabi") | ||
self.assertEqual(arch.platform_dir, "arch-arm") | ||
|
||
env = arch.get_env(clang=True) | ||
# check clang | ||
build_platform = "{system}-{machine}".format( | ||
system=os.uname()[0], machine=os.uname()[-1] | ||
).lower() | ||
self.assertEqual( | ||
env["CC"].split()[0], | ||
"{ndk_dir}/toolchains/llvm/prebuilt/" | ||
"{build_platform}/bin/clang".format( | ||
ndk_dir=self.ctx._ndk_dir, build_platform=build_platform | ||
), | ||
) | ||
self.assertEqual( | ||
env["CXX"].split()[0], | ||
"{ndk_dir}/toolchains/llvm/prebuilt/" | ||
"{build_platform}/bin/clang++".format( | ||
ndk_dir=self.ctx._ndk_dir, build_platform=build_platform | ||
), | ||
) | ||
|
||
# For armeabi-v7a we expect some extra cflags | ||
self.assertIn( | ||
" -march=armv7-a -mfloat-abi=softfp -mfpu=vfp -mthumb", | ||
env["CFLAGS"], | ||
) | ||
|
||
|
||
class TestArchX86(ArchSetUpBaseClass, unittest.TestCase): | ||
@mock.patch("pythonforandroid.archs.find_executable") | ||
@mock.patch("pythonforandroid.build.ensure_dir") | ||
def test_arch_x86(self, mock_ensure_dir, mock_find_executable): | ||
mock_find_executable.return_value = "arm-linux-androideabi-gcc" | ||
mock_ensure_dir.return_value = True | ||
|
||
arch = Archx86(self.ctx) | ||
self.assertEqual(arch.arch, "x86") | ||
self.assertEqual(arch.__str__(), "x86") | ||
self.assertEqual(arch.toolchain_prefix, "x86") | ||
self.assertEqual(arch.command_prefix, "i686-linux-android") | ||
self.assertEqual(arch.target, "i686-none-linux-android") | ||
self.assertEqual(arch.platform_dir, "arch-x86") | ||
|
||
# For x86 we expect some extra cflags in our `environment` | ||
env = arch.get_env() | ||
self.assertIn( | ||
" -march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32", | ||
env["CFLAGS"], | ||
) | ||
|
||
|
||
class TestArchX86_64(ArchSetUpBaseClass, unittest.TestCase): | ||
@mock.patch("pythonforandroid.archs.find_executable") | ||
@mock.patch("pythonforandroid.build.ensure_dir") | ||
def test_arch_x86_64(self, mock_ensure_dir, mock_find_executable): | ||
mock_find_executable.return_value = "arm-linux-androideabi-gcc" | ||
mock_ensure_dir.return_value = True | ||
|
||
arch = Archx86_64(self.ctx) | ||
self.assertEqual(arch.arch, "x86_64") | ||
self.assertEqual(arch.__str__(), "x86_64") | ||
self.assertEqual(arch.toolchain_prefix, "x86_64") | ||
self.assertEqual(arch.command_prefix, "x86_64-linux-android") | ||
self.assertEqual(arch.target, "x86_64-none-linux-android") | ||
self.assertEqual(arch.platform_dir, "arch-x86_64") | ||
|
||
# For x86_64 we expect some extra cflags in our `environment` | ||
env = arch.get_env() | ||
self.assertIn( | ||
" -march=x86-64 -msse4.2 -mpopcnt -m64 -mtune=intel", env["CFLAGS"] | ||
) | ||
|
||
|
||
class TestArchAArch64(ArchSetUpBaseClass, unittest.TestCase): | ||
@mock.patch("pythonforandroid.archs.find_executable") | ||
@mock.patch("pythonforandroid.build.ensure_dir") | ||
def test_arch_aarch_64(self, mock_ensure_dir, mock_find_executable): | ||
mock_find_executable.return_value = "arm-linux-androideabi-gcc" | ||
mock_ensure_dir.return_value = True | ||
|
||
arch = ArchAarch_64(self.ctx) | ||
self.assertEqual(arch.arch, "arm64-v8a") | ||
self.assertEqual(arch.__str__(), "arm64-v8a") | ||
self.assertEqual(arch.toolchain_prefix, "aarch64-linux-android") | ||
self.assertEqual(arch.command_prefix, "aarch64-linux-android") | ||
self.assertEqual(arch.target, "aarch64-none-linux-android") | ||
self.assertEqual(arch.platform_dir, "arch-arm64") | ||
|
||
# For x86_64 we expect to find an extra key in`environment` | ||
env = arch.get_env() | ||
self.assertIn("EXTRA_CFLAGS", env.keys()) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.