blob: 47c3ff9090648bfd65335e1b1e99833871002602 [file] [log] [blame]
#
# Copyright (C) 2018 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
from __future__ import absolute_import
import glob
import os
from typing import List, Set
import ndk.paths
from ndk.test.spec import BuildConfiguration, CMakeToolchainFile
from ndk.test.types import (
CMakeBuildTest,
LibcxxTest,
NdkBuildTest,
PythonBuildTest,
ShellBuildTest,
Test,
)
class TestScanner:
"""Creates a Test objects for a given test directory.
A test scanner is used to turn a test directory into a list of Tests for
any of the test types found in the directory.
"""
def find_tests(self, path: str, name: str) -> List[Test]:
"""Searches a directory for tests.
Args:
path: Path to the test directory.
name: Name of the test.
Returns: List of Tests, possibly empty.
"""
raise NotImplementedError
class BuildTestScanner(TestScanner):
def __init__(self, ndk_path: str, dist: bool = True) -> None:
self.ndk_path = ndk_path
self.dist = dist
self.build_configurations: Set[BuildConfiguration] = set()
def add_build_configuration(self, spec: BuildConfiguration) -> None:
self.build_configurations.add(spec)
def find_tests(self, path: str, name: str) -> List[Test]:
# If we have a build.sh, that takes precedence over the Android.mk.
build_sh_path = os.path.join(path, 'build.sh')
if os.path.exists(build_sh_path):
return self.make_build_sh_tests(path, name)
# Same for test.py
build_sh_path = os.path.join(path, 'test.py')
if os.path.exists(build_sh_path):
return self.make_test_py_tests(path, name)
# But we can have both ndk-build and cmake tests in the same directory.
tests: List[Test] = []
# NB: This isn't looking for Android.mk specifically (even though on
# that would mostly be a better test) because we have a test that
# verifies that ndk-build still works when APP_BUILD_SCRIPT is set to
# something _other_ than a file named Android.mk.
mk_glob = glob.glob(os.path.join(path, 'jni/*.mk'))
if mk_glob:
tests.extend(self.make_ndk_build_tests(path, name))
cmake_lists_path = os.path.join(path, 'CMakeLists.txt')
if os.path.exists(cmake_lists_path):
tests.extend(self.make_cmake_tests(path, name))
return tests
def make_build_sh_tests(self, path: str, name: str) -> List[Test]:
return [
ShellBuildTest(name, path, config, self.ndk_path)
for config in self.build_configurations
if config.toolchain_file == CMakeToolchainFile.Default
]
def make_test_py_tests(self, path: str, name: str) -> List[Test]:
return [
PythonBuildTest(name, path, config, self.ndk_path)
for config in self.build_configurations
if config.toolchain_file == CMakeToolchainFile.Default
]
def make_ndk_build_tests(self, path: str, name: str) -> List[Test]:
return [
NdkBuildTest(name, path, config, self.ndk_path, self.dist)
for config in self.build_configurations
if config.toolchain_file == CMakeToolchainFile.Default
]
def make_cmake_tests(self, path: str, name: str) -> List[Test]:
return [
CMakeBuildTest(name, path, config, self.ndk_path, self.dist)
for config in self.build_configurations
]
class LibcxxTestScanner(TestScanner):
ALL_TESTS: List[str] = []
LIBCXX_SRC = ndk.paths.ANDROID_DIR / 'toolchain/llvm-project/libcxx'
def __init__(self, ndk_path: str) -> None:
self.ndk_path = ndk_path
self.build_configurations: Set[BuildConfiguration] = set()
LibcxxTestScanner.find_all_libcxx_tests()
def add_build_configuration(self, spec: BuildConfiguration) -> None:
self.build_configurations.add(spec)
def find_tests(self, path: str, name: str) -> List[Test]:
return [
LibcxxTest('libc++', path, config, self.ndk_path)
for config in self.build_configurations
if config.toolchain_file == CMakeToolchainFile.Default
]
@classmethod
def find_all_libcxx_tests(cls) -> None:
# If we instantiate multiple LibcxxTestScanners, we still only need to
# initialize this once. We only create these in the main thread, so
# there's no risk of race.
if cls.ALL_TESTS:
return
test_base_dir = os.path.join(cls.LIBCXX_SRC, 'test')
for root, _dirs, files in os.walk(test_base_dir, followlinks=True):
for test_file in files:
if test_file.endswith('.cpp') or test_file.endswith('.mm'):
test_path = ndk.paths.to_posix_path(os.path.relpath(
os.path.join(root, test_file), test_base_dir))
cls.ALL_TESTS.append(test_path)