Skip to content

Commit 464d198

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

File tree

1 file changed

+261
-0
lines changed

1 file changed

+261
-0
lines changed

tests/test_archs.py

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

0 commit comments

Comments
 (0)