Skip to content
Merged
Show file tree
Hide file tree
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
38 changes: 38 additions & 0 deletions .github/workflows/native-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Native tests

# Builds and runs the native C++ engine unit tests (app/src/main/jni/tests) on a plain Linux
# host via the standalone CMake build (jni/CMakeLists.txt) — no AOSP platform tree needed. This
# covers the dictionary/suggest/geometry engine that the JVM/Robolectric suite cannot reach.
on:
push:
branches: [dev]
paths: ['app/src/main/jni/**']
pull_request:
branches: [dev, main]
paths: ['app/src/main/jni/**']

jobs:
native-host-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

# find_package(JNI) needs JDK headers (jni.h + linux/jni_md.h); setup-java sets JAVA_HOME.
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '17'

- name: Install build tools
run: sudo apt-get update && sudo apt-get install -y cmake g++

- name: Configure
run: cmake -S app/src/main/jni -B build-host-tests -DCMAKE_BUILD_TYPE=Release

- name: Build native tests
run: cmake --build build-host-tests -j"$(nproc)"

- name: Run native unit tests
# FormatUtilsTest.TestDetectFormatVersion is quarantined: a host-toolchain anomaly in code
# that works on-device (the suite had never run in CI before). Tracked in #80.
run: ctest --test-dir build-host-tests --output-on-failure -E 'FormatUtilsTest\.TestDetectFormatVersion'
62 changes: 62 additions & 0 deletions app/src/main/jni/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# SPDX-License-Identifier: Apache-2.0
#
# Standalone HOST build of the native latinime unit tests (issue #78).
#
# This is NOT used by the app build (gradle uses ndkBuild via Android.mk). It exists so the
# existing C++ gtest suite under tests/ can be compiled and run on a plain Linux host (CI) WITHOUT
# an AOSP platform checkout — the legacy run-tests.sh / HostUnitTests.mk require the AOSP build
# system (mmm/lunch/BUILD_HOST_NATIVE_TEST) and cannot run in gradle/NDK CI.
#
# Build & run:
# cmake -S app/src/main/jni -B build-host-tests -DCMAKE_BUILD_TYPE=Release
# cmake --build build-host-tests -j
# ctest --test-dir build-host-tests --output-on-failure
#
# Host build => __ANDROID__ is undefined, so defines.h uses its host fallbacks (no android/log.h).

cmake_minimum_required(VERSION 3.14)
project(latinime_host_tests CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip
)
FetchContent_MakeAvailable(googletest)

set(JNI_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(SRC_DIR ${JNI_DIR}/src)
set(TEST_DIR ${JNI_DIR}/tests)

# Some core engine headers (e.g. suggest/core/dictionary/dictionary.h) include <jni.h> for type
# signatures (JNIEnv / jintArray / ... — header-only, the host tests never call the JNI bridge, so
# no libjvm is linked). CI provides a JDK via actions/setup-java -> find_package(JNI). For a local
# host build without a JDK, pass -DLATINIME_JNI_INCLUDE=<dir> (e.g. the Android NDK's jni.h dir).
if(LATINIME_JNI_INCLUDE)
set(JNI_INCLUDE_DIRS ${LATINIME_JNI_INCLUDE})
else()
find_package(JNI REQUIRED)
endif()

# Engine core: every src/*.cpp EXCEPT the JNI bridge (com_android_*.cpp / jni_common.cpp need
# jni.h and are not part of the host-testable core — see NativeFileList.mk LATIN_IME_CORE_SRC_FILES).
file(GLOB_RECURSE ENGINE_SRC CONFIGURE_DEPENDS ${SRC_DIR}/*.cpp)
list(FILTER ENGINE_SRC EXCLUDE REGEX "(com_android_inputmethod_|jni_common\\.cpp$)")

# gtest suite (LATIN_IME_CORE_TEST_FILES).
file(GLOB_RECURSE TEST_SRC CONFIGURE_DEPENDS ${TEST_DIR}/*.cpp)

add_executable(latinime_host_unittests ${ENGINE_SRC} ${TEST_SRC})
target_include_directories(latinime_host_unittests PRIVATE ${SRC_DIR} ${TEST_DIR} ${JNI_INCLUDE_DIRS})
target_compile_options(latinime_host_unittests PRIVATE
-include ${CMAKE_CURRENT_SOURCE_DIR}/host_test_compat.h
-Wno-unused-parameter -Wno-unused-function)
target_link_libraries(latinime_host_unittests PRIVATE gtest gtest_main)

enable_testing()
include(GoogleTest)
gtest_discover_tests(latinime_host_unittests DISCOVERY_TIMEOUT 60)
14 changes: 14 additions & 0 deletions app/src/main/jni/host_test_compat.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: Apache-2.0
//
// Force-included (via -include) ONLY in the standalone host test build (CMakeLists.txt).
// The engine/test sources were written against AOSP's older clang, which pulled several standard
// headers transitively. Modern host g++ is stricter, so a few TUs reference CHAR_BIT / fixed-width
// ints / mem* without a direct include. This shim provides them globally for the host build
// without touching the shared sources (which compile fine under the NDK for the app).
#pragma once

#include <climits> // CHAR_BIT, INT_MAX, ...
#include <cstdint> // int32_t, uint8_t, ...
#include <cstddef> // size_t, ptrdiff_t
#include <cstring> // memcpy, memset, strlen
#include <cstdio> // snprintf
Loading