diff --git a/.github/workflows/scripts-android.yml b/.github/workflows/scripts-android.yml index b1ba7def43..39b97d955e 100644 --- a/.github/workflows/scripts-android.yml +++ b/.github/workflows/scripts-android.yml @@ -14,7 +14,7 @@ name: Test Android build scripts jobs: build-android: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm steps: - uses: actions/checkout@v4 - name: Setup workspace @@ -23,3 +23,36 @@ jobs: run: ./scripts/build-android-port.sh -q -DskipTests - name: Build Hello Codename One Android app run: ./scripts/build-android-app.sh -q -DskipTests + - name: Add Android instrumentation test + run: ./scripts/add-android-instrumentation-test.sh + - name: Run Android instrumentation tests on emulator + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: 35 + target: google_apis + arch: arm64-v8a + force-avd-creation: true + disable-animations: true + emulator-options: >- + -no-window -no-boot-anim -gpu swiftshader_indirect + -no-snapshot -camera-back none -camera-front none + -accel off + script: ./scripts/run-android-instrumentation-tests.sh + - name: Export Android emulator screenshot path + if: always() + run: | + set -euo pipefail + echo "ANDROID_SCREENSHOT=" >> "$GITHUB_ENV" + if [ -f scripts/.android-build-info ]; then + # shellcheck disable=SC1090 + source scripts/.android-build-info + if [ -n "${SCREENSHOT_PATH:-}" ] && [ -f "$SCREENSHOT_PATH" ]; then + echo "ANDROID_SCREENSHOT=$SCREENSHOT_PATH" >> "$GITHUB_ENV" + fi + fi + - name: Upload Android emulator screenshot + if: ${{ always() && env.ANDROID_SCREENSHOT != '' }} + uses: actions/upload-artifact@v4 + with: + name: android-emulator-screenshot + path: ${{ env.ANDROID_SCREENSHOT }} diff --git a/scripts/add-android-instrumentation-test.sh b/scripts/add-android-instrumentation-test.sh new file mode 100755 index 0000000000..dac7529017 --- /dev/null +++ b/scripts/add-android-instrumentation-test.sh @@ -0,0 +1,99 @@ +#!/usr/bin/env bash +# Inject an instrumentation test into the generated Codename One Android Gradle project. +set -euo pipefail + +log() { echo "[add-android-instrumentation-test] $1"; } + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +cd "$REPO_ROOT" + +TMPDIR="${TMPDIR:-/tmp}" +TMPDIR="${TMPDIR%/}" + +TOOLS_ENV_DIR="$TMPDIR/codenameone-tools/tools" +ENV_FILE="$TOOLS_ENV_DIR/env.sh" +if [ -f "$ENV_FILE" ]; then + # shellcheck disable=SC1090 + source "$ENV_FILE" +else + log "Workspace tools not provisioned. Run scripts/setup-workspace.sh first." >&2 + exit 1 +fi + +if [ -z "${JAVA17_HOME:-}" ] || [ ! -x "$JAVA17_HOME/bin/java" ]; then + log "JAVA17_HOME is not configured. Run scripts/setup-workspace.sh to provision Java 17." >&2 + exit 1 +fi + +export JAVA_HOME="$JAVA17_HOME" +export PATH="$JAVA17_HOME/bin:$PATH" + +BUILD_INFO_FILE="$SCRIPT_DIR/.android-build-info" +if [ ! -f "$BUILD_INFO_FILE" ]; then + log "Android build metadata not found at $BUILD_INFO_FILE. Run scripts/build-android-app.sh first." >&2 + exit 1 +fi + +# shellcheck disable=SC1090 +source "$BUILD_INFO_FILE" + +required_vars=(GRADLE_PROJECT_DIR PACKAGE_NAME ARTIFACT_ID WORK_DIR) +for var in "${required_vars[@]}"; do + if [ -z "${!var:-}" ]; then + log "Required build metadata '$var' is missing. Regenerate the Android project." >&2 + exit 1 + fi +done + +ANDROID_APP_MODULE_DIR="$GRADLE_PROJECT_DIR/app" +if [ ! -d "$ANDROID_APP_MODULE_DIR" ]; then + log "Android app module directory not found at $ANDROID_APP_MODULE_DIR" >&2 + exit 1 +fi + +PACKAGE_PATH="${PACKAGE_NAME//.//}" +ANDROID_TEST_DIR="$ANDROID_APP_MODULE_DIR/src/androidTest/java/$PACKAGE_PATH" +mkdir -p "$ANDROID_TEST_DIR" + +TEMPLATE_FILE="$SCRIPT_DIR/templates/AndroidPackageInstrumentationTest.java.tmpl" +if [ ! -f "$TEMPLATE_FILE" ]; then + log "Instrumentation test template not found at $TEMPLATE_FILE" >&2 + exit 1 +fi + +TEST_FILE="$ANDROID_TEST_DIR/PackageNameInstrumentationTest.java" +sed -e "s|@PACKAGE@|$PACKAGE_NAME|g" "$TEMPLATE_FILE" > "$TEST_FILE" +log "Wrote instrumentation test to $TEST_FILE" + +GRADLE_APP_BUILD_FILE="$ANDROID_APP_MODULE_DIR/build.gradle" +if [ ! -f "$GRADLE_APP_BUILD_FILE" ]; then + log "Gradle build file not found at $GRADLE_APP_BUILD_FILE" >&2 + exit 1 +fi + +python3 - "$GRADLE_APP_BUILD_FILE" <<'PY' +import re +import sys +from pathlib import Path + +build_file = Path(sys.argv[1]) +contents = build_file.read_text() + +missing_lines = [] +if "androidx.test.ext:junit" not in contents: + missing_lines.append("androidTestImplementation 'androidx.test.ext:junit:1.1.5'") +if "androidx.test.espresso:espresso-core" not in contents: + missing_lines.append("androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'") + +if missing_lines: + match = re.search(r'dependencies\s*\{', contents) + if not match: + raise SystemExit("dependencies block not found in app build.gradle") + insertion = ''.join(f"\n {line}" for line in missing_lines) + idx = match.end() + contents = contents[:idx] + insertion + contents[idx:] + build_file.write_text(contents) +PY +log "Ensured Android test dependencies are declared in $GRADLE_APP_BUILD_FILE" + diff --git a/scripts/build-android-app.sh b/scripts/build-android-app.sh index f424546247..315e42b40a 100755 --- a/scripts/build-android-app.sh +++ b/scripts/build-android-app.sh @@ -12,6 +12,23 @@ TMPDIR="${TMPDIR:-/tmp}"; TMPDIR="${TMPDIR%/}" DOWNLOAD_DIR="${TMPDIR%/}/codenameone-tools" ENV_DIR="$DOWNLOAD_DIR/tools" EXTRA_MVN_ARGS=("$@") +HOST_OS="$(uname -s)" +HOST_ARCH="$(uname -m)" + +detect_local_repo() { + local repo="${LOCAL_MAVEN_REPO:-}" + for arg in "${EXTRA_MVN_ARGS[@]}"; do + case "$arg" in + -Dmaven.repo.local=*) + repo="${arg#*=}" + ;; + esac + done + if [ -z "$repo" ]; then + repo="$HOME/.m2/repository" + fi + printf '%s' "${repo%/}" +} ENV_FILE="$ENV_DIR/env.sh" ba_log "Loading workspace environment from $ENV_FILE" @@ -62,6 +79,11 @@ ba_log "Using JAVA17_HOME at $JAVA17_HOME" ba_log "Using Maven installation at $MAVEN_HOME" export PATH="$JAVA_HOME/bin:$MAVEN_HOME/bin:$PATH" +if [ "$HOST_OS" = "Linux" ] && { [ "$HOST_ARCH" = "arm64" ] || [ "$HOST_ARCH" = "aarch64" ]; }; then + ba_log "Ensuring codenameone-cef stub artifact is installed for Linux ARM builds" + MAVEN_BIN="$MAVEN_HOME/bin/mvn" LOCAL_MAVEN_REPO="$LOCAL_MAVEN_REPO" ./scripts/ensure-cef-stub.sh +fi + ANDROID_SDK_ROOT="${ANDROID_SDK_ROOT:-${ANDROID_HOME:-}}" if [ -z "$ANDROID_SDK_ROOT" ]; then if [ -d "/usr/local/lib/android/sdk" ]; then ANDROID_SDK_ROOT="/usr/local/lib/android/sdk" @@ -91,7 +113,7 @@ if [ ! -d "$SOURCE_PROJECT" ]; then fi ba_log "Using source project template at $SOURCE_PROJECT" -LOCAL_MAVEN_REPO="${LOCAL_MAVEN_REPO:-$HOME/.m2/repository}" +LOCAL_MAVEN_REPO="$(detect_local_repo)" ba_log "Using local Maven repository at $LOCAL_MAVEN_REPO" mkdir -p "$LOCAL_MAVEN_REPO" MAVEN_CMD=( @@ -282,4 +304,16 @@ export JAVA_HOME="$ORIGINAL_JAVA_HOME" APK_PATH=$(find "$GRADLE_PROJECT_DIR" -path "*/outputs/apk/debug/*.apk" | head -n 1 || true) [ -n "$APK_PATH" ] || { ba_log "Gradle build completed but no APK was found" >&2; exit 1; } -ba_log "Successfully built Android APK at $APK_PATH" \ No newline at end of file +ba_log "Successfully built Android APK at $APK_PATH" + +BUILD_INFO_FILE="$SCRIPT_DIR/.android-build-info" +ba_log "Recording Android build metadata for downstream stages at $BUILD_INFO_FILE" +{ + printf "APP_DIR=%q\n" "$APP_DIR" + printf "GRADLE_PROJECT_DIR=%q\n" "$GRADLE_PROJECT_DIR" + printf "PACKAGE_NAME=%q\n" "$PACKAGE_NAME" + printf "ARTIFACT_ID=%q\n" "$ARTIFACT_ID" + printf "WORK_DIR=%q\n" "$WORK_DIR" + printf "APK_PATH=%q\n" "$APK_PATH" +} > "$BUILD_INFO_FILE" + diff --git a/scripts/build-android-port.sh b/scripts/build-android-port.sh index d0395724f9..8d5373f6b2 100755 --- a/scripts/build-android-port.sh +++ b/scripts/build-android-port.sh @@ -18,6 +18,27 @@ log "The DOWNLOAD_DIR is ${DOWNLOAD_DIR}" ENV_DIR="$DOWNLOAD_DIR/tools" ENV_FILE="$ENV_DIR/env.sh" +host_os="$(uname -s)" +host_arch="$(uname -m)" + +detect_local_repo() { + local repo="${LOCAL_MAVEN_REPO:-}" + for arg in "$@"; do + case "$arg" in + -Dmaven.repo.local=*) + repo="${arg#*=}" + ;; + esac + done + if [ -z "$repo" ]; then + repo="$HOME/.m2/repository" + fi + printf '%s' "${repo%/}" +} + +LOCAL_REPO_PATH="$(detect_local_repo "$@")" +mkdir -p "$LOCAL_REPO_PATH" + load_environment() { if [ ! -f "$ENV_FILE" ]; then return 1 @@ -113,6 +134,11 @@ export PATH="$JAVA_HOME/bin:$MAVEN_HOME/bin:$PATH" "$JAVA17_HOME/bin/java" -version "$MAVEN_HOME/bin/mvn" -version +if [ "$host_os" = "Linux" ] && { [ "$host_arch" = "arm64" ] || [ "$host_arch" = "aarch64" ]; }; then + log "Ensuring codenameone-cef stub artifact is installed for Linux ARM builds" + MAVEN_BIN="$MAVEN_HOME/bin/mvn" LOCAL_MAVEN_REPO="$LOCAL_REPO_PATH" ./scripts/ensure-cef-stub.sh +fi + run_maven() { xvfb-run -a "$MAVEN_HOME/bin/mvn" "$@" } diff --git a/scripts/ensure-cef-stub.sh b/scripts/ensure-cef-stub.sh new file mode 100755 index 0000000000..ac4ab14292 --- /dev/null +++ b/scripts/ensure-cef-stub.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env bash +# Ensure the codenameone-cef artifact is available in the local Maven repository on +# platforms where the published binaries are unavailable (e.g., Linux ARM). +set -euo pipefail +[ "${DEBUG:-0}" = "1" ] && set -x + +log() { + echo "[ensure-cef-stub] $1" +} + +os_name="$(uname -s)" +arch_name="$(uname -m)" +if [ "$os_name" != "Linux" ] || { [ "$arch_name" != "arm64" ] && [ "$arch_name" != "aarch64" ]; }; then + log "Host ${os_name}-${arch_name} does not require a CEF stub; skipping" + exit 0 +fi + +MAVEN_BIN="${MAVEN_BIN:-}" +if [ -z "$MAVEN_BIN" ] && [ -n "${MAVEN_HOME:-}" ] && [ -x "$MAVEN_HOME/bin/mvn" ]; then + MAVEN_BIN="$MAVEN_HOME/bin/mvn" +fi +if [ -z "$MAVEN_BIN" ] && command -v mvn >/dev/null 2>&1; then + MAVEN_BIN="$(command -v mvn)" +fi +if [ -z "$MAVEN_BIN" ] || [ ! -x "$MAVEN_BIN" ]; then + log "Maven executable not found. Set MAVEN_HOME, MAVEN_BIN, or ensure mvn is on PATH." >&2 + exit 1 +fi + +LOCAL_MAVEN_REPO="${LOCAL_MAVEN_REPO:-$HOME/.m2/repository}" +LOCAL_MAVEN_REPO="${LOCAL_MAVEN_REPO%/}" +if [ -z "$LOCAL_MAVEN_REPO" ]; then + log "LOCAL_MAVEN_REPO is empty" >&2 + exit 1 +fi +mkdir -p "$LOCAL_MAVEN_REPO" + +CEF_VERSION="84.4.1-M3" +CEF_COORD="com.codenameone:codenameone-cef:$CEF_VERSION" +CEF_REPO_PATH="$LOCAL_MAVEN_REPO/com/codenameone/codenameone-cef/$CEF_VERSION" +CEF_POM="$CEF_REPO_PATH/codenameone-cef-$CEF_VERSION.pom" + +if [ -s "$CEF_POM" ]; then + log "codenameone-cef $CEF_VERSION already present in $LOCAL_MAVEN_REPO" + exit 0 +fi + +log "Installing stub codenameone-cef $CEF_VERSION artifact into $LOCAL_MAVEN_REPO" +mkdir -p "$CEF_REPO_PATH" +stub_pom="$(mktemp "${TMPDIR:-/tmp}/codenameone-cef-stub.XXXXXX.pom")" +trap 'rm -f "$stub_pom"' EXIT + +cat > "$stub_pom" <<'POM' + + + 4.0.0 + com.codenameone + codenameone-cef + 84.4.1-M3 + pom + codenameone-cef stub + Stub artifact to satisfy codenameone-cef dependency on platforms where CEF binaries are unavailable. + +POM + +"$MAVEN_BIN" -B -ntp org.apache.maven.plugins:maven-install-plugin:3.1.2:install-file \ + -Dfile="$stub_pom" \ + -DgroupId=com.codenameone \ + -DartifactId=codenameone-cef \ + -Dversion="$CEF_VERSION" \ + -Dpackaging=pom \ + -DgeneratePom=false \ + -DcreateChecksum=true \ + -DlocalRepositoryPath="$LOCAL_MAVEN_REPO" + +log "Stub $CEF_COORD installed" diff --git a/scripts/run-android-instrumentation-tests.sh b/scripts/run-android-instrumentation-tests.sh new file mode 100755 index 0000000000..dc402cbae0 --- /dev/null +++ b/scripts/run-android-instrumentation-tests.sh @@ -0,0 +1,148 @@ +#!/usr/bin/env bash +# Boot an Android emulator, execute instrumentation tests, and capture a screenshot artifact. +set -euo pipefail + +log() { echo "[run-android-instrumentation-tests] $1"; } + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +cd "$REPO_ROOT" + +TMPDIR="${TMPDIR:-/tmp}" +TMPDIR="${TMPDIR%/}" +TOOLS_ENV_DIR="$TMPDIR/codenameone-tools/tools" +ENV_FILE="$TOOLS_ENV_DIR/env.sh" +if [ -f "$ENV_FILE" ]; then + # shellcheck disable=SC1090 + source "$ENV_FILE" +else + log "Workspace tools not provisioned. Run scripts/setup-workspace.sh first." >&2 + exit 1 +fi + +if [ -z "${JAVA17_HOME:-}" ] || [ ! -x "$JAVA17_HOME/bin/java" ]; then + log "JAVA17_HOME is not configured. Run scripts/setup-workspace.sh to provision Java 17." >&2 + exit 1 +fi + +export JAVA_HOME="$JAVA17_HOME" +export PATH="$JAVA17_HOME/bin:$PATH" + +BUILD_INFO_FILE="$SCRIPT_DIR/.android-build-info" +if [ ! -f "$BUILD_INFO_FILE" ]; then + log "Android build metadata not found at $BUILD_INFO_FILE. Run scripts/build-android-app.sh first." >&2 + exit 1 +fi + +# shellcheck disable=SC1090 +source "$BUILD_INFO_FILE" + +required_vars=(APP_DIR GRADLE_PROJECT_DIR PACKAGE_NAME ARTIFACT_ID WORK_DIR APK_PATH) +for var in "${required_vars[@]}"; do + if [ -z "${!var:-}" ]; then + log "Required build metadata '$var' is missing. Regenerate the Android project." >&2 + exit 1 + fi +done + +ANDROID_SDK_ROOT="${ANDROID_SDK_ROOT:-${ANDROID_HOME:-}}" +if [ -z "$ANDROID_SDK_ROOT" ]; then + if [ -d "/usr/local/lib/android/sdk" ]; then + ANDROID_SDK_ROOT="/usr/local/lib/android/sdk" + elif [ -d "/usr/lib/android-sdk" ]; then + ANDROID_SDK_ROOT="/usr/lib/android-sdk" + elif [ -d "$HOME/Android/Sdk" ]; then + ANDROID_SDK_ROOT="$HOME/Android/Sdk" + fi +fi +if [ -z "$ANDROID_SDK_ROOT" ] || [ ! -d "$ANDROID_SDK_ROOT" ]; then + log "Android SDK not found. Set ANDROID_SDK_ROOT or ANDROID_HOME to a valid installation." >&2 + exit 1 +fi +export ANDROID_SDK_ROOT ANDROID_HOME="$ANDROID_SDK_ROOT" + +ADB_BIN="$ANDROID_SDK_ROOT/platform-tools/adb" + +if [ ! -x "$ADB_BIN" ]; then + log "adb binary not found. Ensure Android platform-tools are installed." >&2 + log "ANDROID_SDK_ROOT=$ANDROID_SDK_ROOT" + exit 1 +fi + +ensure_emulator_ready() { + log "Waiting for emulator to register with adb" + "$ADB_BIN" start-server >/dev/null 2>&1 || true + + local adb_device_timeout=180 + for _ in $(seq 1 "$adb_device_timeout"); do + EMULATOR_SERIAL=$("$ADB_BIN" devices | awk 'NR>1 && /^emulator-/{print $1; exit}') || true + if [ -n "${EMULATOR_SERIAL:-}" ]; then + break + fi + sleep 1 + done + + if [ -z "${EMULATOR_SERIAL:-}" ]; then + log "No emulator appeared in adb devices within ${adb_device_timeout}s" >&2 + "$ADB_BIN" devices >&2 || true + cat <<'EOF' >&2 +Ensure an Android emulator is booted before invoking this script. In CI, run it +inside the reactivecircus/android-emulator-runner action (see scripts-android.yml). +EOF + exit 1 + fi + + log "Waiting for emulator to boot" + local boot_completed="0" + for _ in $(seq 1 120); do + boot_completed=$("$ADB_BIN" -s "$EMULATOR_SERIAL" shell getprop sys.boot_completed 2>/dev/null | tr -d '\r') || true + if [ "$boot_completed" = "1" ]; then + break + fi + sleep 5 + done + + if [ "$boot_completed" != "1" ]; then + log "Emulator did not boot in the allotted time" >&2 + exit 1 + fi +} + +ensure_emulator_ready + +log "Executing connected Android tests" +chmod +x "$GRADLE_PROJECT_DIR/gradlew" +ORIGINAL_JAVA_HOME="$JAVA_HOME" +export JAVA_HOME="$JAVA17_HOME" +( + cd "$GRADLE_PROJECT_DIR" + ./gradlew --no-daemon connectedDebugAndroidTest +) +export JAVA_HOME="$ORIGINAL_JAVA_HOME" + +log "Launching application to capture screenshot" +"$ADB_BIN" -s "$EMULATOR_SERIAL" shell monkey -p "$PACKAGE_NAME" -c android.intent.category.LAUNCHER 1 >/dev/null 2>&1 || true +sleep 10 + +ARTIFACTS_DIR="$WORK_DIR/artifacts" +mkdir -p "$ARTIFACTS_DIR" +SCREENSHOT_PATH="$ARTIFACTS_DIR/${ARTIFACT_ID}-emulator.png" +log "Capturing screenshot at $SCREENSHOT_PATH" +"$ADB_BIN" -s "$EMULATOR_SERIAL" exec-out screencap -p > "$SCREENSHOT_PATH" +log "Screenshot captured" + +persist_build_info() { + { + printf "APP_DIR=%q\n" "$APP_DIR" + printf "GRADLE_PROJECT_DIR=%q\n" "$GRADLE_PROJECT_DIR" + printf "PACKAGE_NAME=%q\n" "$PACKAGE_NAME" + printf "ARTIFACT_ID=%q\n" "$ARTIFACT_ID" + printf "WORK_DIR=%q\n" "$WORK_DIR" + printf "APK_PATH=%q\n" "$APK_PATH" + printf "SCREENSHOT_PATH=%q\n" "$SCREENSHOT_PATH" + } > "$BUILD_INFO_FILE" +} + +persist_build_info +log "Updated build metadata with screenshot information" + diff --git a/scripts/setup-workspace.sh b/scripts/setup-workspace.sh index fd59ef20d7..b0081d619d 100755 --- a/scripts/setup-workspace.sh +++ b/scripts/setup-workspace.sh @@ -60,6 +60,25 @@ case "$arch_name" in *) echo "Unsupported architecture: $arch_name" >&2; exit 1 ;; esac +detect_local_repo() { + local repo="${LOCAL_MAVEN_REPO:-}" + for arg in "$@"; do + case "$arg" in + -Dmaven.repo.local=*) + repo="${arg#*=}" + ;; + esac + done + if [ -z "$repo" ]; then + repo="$HOME/.m2/repository" + fi + printf '%s' "${repo%/}" +} + +LOCAL_MAVEN_REPO="$(detect_local_repo "$@")" +log "Using local Maven repository at $LOCAL_MAVEN_REPO" +mkdir -p "$LOCAL_MAVEN_REPO" + # Determine platform-specific JDK download URLs arch_jdk8="$arch" if [ "$os" = "mac" ] && [ "$arch" = "aarch64" ]; then @@ -148,6 +167,11 @@ else log "Using existing Maven at $MAVEN_HOME" fi +if [ "$os" = "linux" ] && [ "$arch" = "aarch64" ]; then + log "Ensuring codenameone-cef stub artifact is installed for Linux ARM builds" + MAVEN_BIN="$MAVEN_HOME/bin/mvn" LOCAL_MAVEN_REPO="$LOCAL_MAVEN_REPO" ./scripts/ensure-cef-stub.sh +fi + ARCHETYPE_PLUGIN_COORD="org.apache.maven.plugins:maven-archetype-plugin:3.2.1" log "Preloading Maven archetype plugin ($ARCHETYPE_PLUGIN_COORD) for offline project generation" if "$MAVEN_HOME/bin/mvn" -B -N "$ARCHETYPE_PLUGIN_COORD:help" -Ddetail -Dgoal=generate >/dev/null 2>&1; then diff --git a/scripts/templates/AndroidPackageInstrumentationTest.java.tmpl b/scripts/templates/AndroidPackageInstrumentationTest.java.tmpl new file mode 100644 index 0000000000..2f5ff40df1 --- /dev/null +++ b/scripts/templates/AndroidPackageInstrumentationTest.java.tmpl @@ -0,0 +1,25 @@ +package @PACKAGE@; + +import static org.junit.Assert.assertEquals; + +import android.content.Context; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; + +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Basic instrumentation test that verifies the generated application's package name. + */ +@RunWith(AndroidJUnit4.class) +public class PackageNameInstrumentationTest { + + @Test + public void appContextMatchesPackage() { + Context targetContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + assertEquals("@PACKAGE@", targetContext.getPackageName()); + } +} +