Skip to content

Commit 47743c0

Browse files
committed
[tests] Add unittest for module pythonforandroid.archs
1 parent ccb0f8e commit 47743c0

File tree

1 file changed

+247
-0
lines changed

1 file changed

+247
-0
lines changed

tests/test_archs.py

Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
import os
2+
3+
import unittest
4+
5+
try:
6+
from unittest import mock
7+
except ImportError:
8+
# `Python 2` or lower than `Python 3.3` does not
9+
# have the `unittest.mock` module built-in
10+
import mock
11+
from pythonforandroid.bootstrap import Bootstrap
12+
from pythonforandroid.distribution import Distribution
13+
from pythonforandroid.recipe import Recipe
14+
from pythonforandroid.build import Context
15+
from pythonforandroid.util import BuildInterruptingException
16+
from pythonforandroid.archs import (
17+
Arch,
18+
ArchARM,
19+
ArchARMv7_a,
20+
ArchAarch_64,
21+
Archx86,
22+
Archx86_64,
23+
)
24+
25+
expected_env_gcc_keys = {
26+
"CFLAGS",
27+
"LDFLAGS",
28+
"CXXFLAGS",
29+
"TOOLCHAIN_PREFIX",
30+
"TOOLCHAIN_VERSION",
31+
"CC",
32+
"CXX",
33+
"AR",
34+
"RANLIB",
35+
"LD",
36+
"LDSHARED",
37+
"STRIP",
38+
"MAKE",
39+
"READELF",
40+
"NM",
41+
"BUILDLIB_PATH",
42+
"PATH",
43+
"ARCH",
44+
"NDK_API",
45+
}
46+
47+
48+
class TestArch(unittest.TestCase):
49+
def setUp(self):
50+
self.ctx = Context()
51+
self.ctx.ndk_api = 21
52+
self.ctx.android_api = 27
53+
self.ctx._sdk_dir = "/opt/android/android-sdk"
54+
self.ctx._ndk_dir = "/opt/android/android-ndk"
55+
self.ctx.setup_dirs(os.getcwd())
56+
self.ctx.bootstrap = Bootstrap().get_bootstrap("sdl2", self.ctx)
57+
self.ctx.bootstrap.distribution = Distribution.get_distribution(
58+
self.ctx, name="sdl2", recipes=["python3", "kivy"]
59+
)
60+
self.ctx.python_recipe = Recipe.get_recipe("python3", self.ctx)
61+
62+
def test_arch(self):
63+
arch = Arch(self.ctx)
64+
with self.assertRaises(AttributeError) as e1:
65+
arch.__str__()
66+
self.assertEqual(
67+
e1.exception.args[0], "'Arch' object has no attribute 'arch'"
68+
)
69+
with self.assertRaises(AttributeError) as e2:
70+
getattr(arch, "target")
71+
self.assertEqual(
72+
e2.exception.args[0], "'NoneType' object has no attribute 'split'"
73+
)
74+
self.assertIsNone(arch.toolchain_prefix)
75+
self.assertIsNone(arch.command_prefix)
76+
self.assertIsInstance(arch.include_dirs, list)
77+
78+
# Here we mock two functions:
79+
# - `ensure_dir` because we don't want to create any directory
80+
# - `find_executable` because otherwise we will
81+
# get an error when trying to find the compiler (we are setting some fake
82+
# paths for our android sdk and ndk so probably will not exist)
83+
@mock.patch("pythonforandroid.archs.find_executable")
84+
@mock.patch("pythonforandroid.build.ensure_dir")
85+
def test_arch_arm(self, mock_ensure_dir, mock_find_executable):
86+
mock_find_executable.return_value = "arm-linux-androideabi-gcc"
87+
mock_ensure_dir.return_value = True
88+
89+
arch = ArchARM(self.ctx)
90+
self.assertEqual(arch.arch, "armeabi")
91+
self.assertEqual(arch.__str__(), "armeabi")
92+
self.assertEqual(arch.toolchain_prefix, "arm-linux-androideabi")
93+
self.assertEqual(arch.command_prefix, "arm-linux-androideabi")
94+
self.assertEqual(arch.target, "armv7a-none-linux-androideabi")
95+
self.assertEqual(arch.platform_dir, "arch-arm")
96+
arch = ArchARM(self.ctx)
97+
98+
# Check environment flags
99+
env = arch.get_env()
100+
self.assertIsInstance(env, dict)
101+
102+
for k in expected_env_gcc_keys:
103+
self.assertIn(k, env)
104+
105+
# check gcc compilers
106+
self.assertEqual(env["CC"].split()[0], "arm-linux-androideabi-gcc")
107+
self.assertEqual(env["CXX"].split()[0], "arm-linux-androideabi-g++")
108+
# check android binaries
109+
self.assertEqual(env["AR"], "arm-linux-androideabi-ar")
110+
self.assertEqual(env["LD"], "arm-linux-androideabi-ld")
111+
self.assertEqual(env["RANLIB"], "arm-linux-androideabi-ranlib")
112+
self.assertEqual(
113+
env["STRIP"].split()[0], "arm-linux-androideabi-strip"
114+
)
115+
self.assertEqual(
116+
env["READELF"].split()[0], "arm-linux-androideabi-readelf"
117+
)
118+
self.assertEqual(env["NM"].split()[0], "arm-linux-androideabi-nm")
119+
120+
# check that cflags are in gcc
121+
self.assertIn(env["CFLAGS"], env["CC"])
122+
123+
# check that flags aren't in gcc and also check ccache
124+
self.ctx.ccache = "/usr/bin/ccache"
125+
env = arch.get_env(with_flags_in_cc=False)
126+
self.assertNotIn(env["CFLAGS"], env["CC"])
127+
self.assertEqual(env["USE_CCACHE"], "1")
128+
self.assertEqual(env["NDK_CCACHE"], "/usr/bin/ccache")
129+
130+
# Check exception in case that CC is not found
131+
mock_find_executable.return_value = None
132+
with self.assertRaises(BuildInterruptingException) as e:
133+
arch.get_env()
134+
self.assertEqual(
135+
e.exception.args[0],
136+
"Couldn't find executable for CC. This indicates a problem "
137+
"locating the arm-linux-androideabi-gcc executable in the Android "
138+
"NDK, not that you don't have a normal compiler installed. "
139+
"Exiting.",
140+
)
141+
142+
# Here we mock the same functions than the previous tests plus `glob`,
143+
# so we make sure that the glob result is the expected even if the folder
144+
# doesn't exist, which is probably the case. This has to be done because
145+
# here we tests the `get_env` with clang
146+
@mock.patch("pythonforandroid.archs.glob")
147+
@mock.patch("pythonforandroid.archs.find_executable")
148+
@mock.patch("pythonforandroid.build.ensure_dir")
149+
def test_arch_armv7a(
150+
self, mock_ensure_dir, mock_find_executable, mock_glob
151+
):
152+
mock_find_executable.return_value = "arm-linux-androideabi-gcc"
153+
mock_ensure_dir.return_value = True
154+
mock_glob.return_value = ["llvm"]
155+
156+
arch = ArchARMv7_a(self.ctx)
157+
self.assertEqual(arch.arch, "armeabi-v7a")
158+
self.assertEqual(arch.__str__(), "armeabi-v7a")
159+
self.assertEqual(arch.toolchain_prefix, "arm-linux-androideabi")
160+
self.assertEqual(arch.command_prefix, "arm-linux-androideabi")
161+
self.assertEqual(arch.target, "armv7a-none-linux-androideabi")
162+
self.assertEqual(arch.platform_dir, "arch-arm")
163+
164+
env = arch.get_env(clang=True)
165+
# check clang
166+
build_platform = "{system}-{machine}".format(
167+
system=os.uname()[0], machine=os.uname()[-1]
168+
).lower()
169+
self.assertEqual(
170+
env["CC"].split()[0],
171+
"{ndk_dir}/toolchains/llvm/prebuilt/"
172+
"{build_platform}/bin/clang".format(
173+
ndk_dir=self.ctx._ndk_dir, build_platform=build_platform
174+
),
175+
)
176+
self.assertEqual(
177+
env["CXX"].split()[0],
178+
"{ndk_dir}/toolchains/llvm/prebuilt/"
179+
"{build_platform}/bin/clang++".format(
180+
ndk_dir=self.ctx._ndk_dir, build_platform=build_platform
181+
),
182+
)
183+
184+
# For armeabi-v7a we expect some extra cflags
185+
self.assertIn(
186+
" -march=armv7-a -mfloat-abi=softfp -mfpu=vfp -mthumb",
187+
env["CFLAGS"],
188+
)
189+
190+
@mock.patch("pythonforandroid.archs.find_executable")
191+
@mock.patch("pythonforandroid.build.ensure_dir")
192+
def test_arch_x86(self, mock_ensure_dir, mock_find_executable):
193+
mock_find_executable.return_value = "arm-linux-androideabi-gcc"
194+
mock_ensure_dir.return_value = True
195+
196+
arch = Archx86(self.ctx)
197+
self.assertEqual(arch.arch, "x86")
198+
self.assertEqual(arch.__str__(), "x86")
199+
self.assertEqual(arch.toolchain_prefix, "x86")
200+
self.assertEqual(arch.command_prefix, "i686-linux-android")
201+
self.assertEqual(arch.target, "i686-none-linux-android")
202+
self.assertEqual(arch.platform_dir, "arch-x86")
203+
204+
# For x86 we expect some extra cflags in our `environment`
205+
env = arch.get_env()
206+
self.assertIn(
207+
" -march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32",
208+
env["CFLAGS"],
209+
)
210+
211+
@mock.patch("pythonforandroid.archs.find_executable")
212+
@mock.patch("pythonforandroid.build.ensure_dir")
213+
def test_arch_x86_64(self, mock_ensure_dir, mock_find_executable):
214+
mock_find_executable.return_value = "arm-linux-androideabi-gcc"
215+
mock_ensure_dir.return_value = True
216+
217+
arch = Archx86_64(self.ctx)
218+
self.assertEqual(arch.arch, "x86_64")
219+
self.assertEqual(arch.__str__(), "x86_64")
220+
self.assertEqual(arch.toolchain_prefix, "x86_64")
221+
self.assertEqual(arch.command_prefix, "x86_64-linux-android")
222+
self.assertEqual(arch.target, "x86_64-none-linux-android")
223+
self.assertEqual(arch.platform_dir, "arch-x86_64")
224+
225+
# For x86_64 we expect some extra cflags in our `environment`
226+
env = arch.get_env()
227+
self.assertIn(
228+
" -march=x86-64 -msse4.2 -mpopcnt -m64 -mtune=intel", env["CFLAGS"]
229+
)
230+
231+
@mock.patch("pythonforandroid.archs.find_executable")
232+
@mock.patch("pythonforandroid.build.ensure_dir")
233+
def test_arch_aarch_64(self, mock_ensure_dir, mock_find_executable):
234+
mock_find_executable.return_value = "arm-linux-androideabi-gcc"
235+
mock_ensure_dir.return_value = True
236+
237+
arch = ArchAarch_64(self.ctx)
238+
self.assertEqual(arch.arch, "arm64-v8a")
239+
self.assertEqual(arch.__str__(), "arm64-v8a")
240+
self.assertEqual(arch.toolchain_prefix, "aarch64-linux-android")
241+
self.assertEqual(arch.command_prefix, "aarch64-linux-android")
242+
self.assertEqual(arch.target, "aarch64-none-linux-android")
243+
self.assertEqual(arch.platform_dir, "arch-arm64")
244+
245+
# For x86_64 we expect to find an extra key in`environment`
246+
env = arch.get_env()
247+
self.assertIn("EXTRA_CFLAGS", env.keys())

0 commit comments

Comments
 (0)