@@ -201,6 +201,7 @@ xmlstarlet sel -N "$NS" -t -c "/mvn:project/mvn:build/mvn:plugins" -n "$ROOT_POM
201201[ -f " $APP_DIR /build.sh" ] && chmod +x " $APP_DIR /build.sh"
202202
203203SETTINGS_FILE=" $APP_DIR /common/codenameone_settings.properties"
204+ echo " codename1.arg.android.useAndroidX=true" >> " $SETTINGS_FILE "
204205[ -f " $SETTINGS_FILE " ] || { ba_log " codenameone_settings.properties not found at $SETTINGS_FILE " >&2 ; exit 1; }
205206
206207# --- Read settings ---
@@ -269,109 +270,131 @@ ba_log "Configuring instrumentation test sources in $GRADLE_PROJECT_DIR"
269270APP_BUILD_GRADLE=" $GRADLE_PROJECT_DIR /app/build.gradle"
270271if [ -f " $APP_BUILD_GRADLE " ]; then
271272 python3 - " $APP_BUILD_GRADLE " << 'PYTHON '
272- import pathlib
273- import re
274- import sys
273+ import pathlib, re, sys
274+ p = pathlib.Path(sys.argv[1 ])
275+ t = p.read_text()
276+ orig = t
275277
276- path = pathlib.Path(sys.argv[1 ])
277- text = path.read_text()
278278modified = False
279279
280- if " android.test.InstrumentationTestRunner" not in text:
281- def add_runner (match ):
282- prefix = match.group(0 )
283- return prefix + " \n testInstrumentationRunner \" android.test.InstrumentationTestRunner\" "
280+ # 1) Ensure defaultConfig { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" }
281+ if " androidx.test.runner.AndroidJUnitRunner" not in t:
282+ # Replace legacy runner if present
283+ t, n = re.subn(r ' testInstrumentationRunner\s * ". *? "' ,
284+ ' testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"' , t)
285+ if n == 0 :
286+ # Insert inside defaultConfig { ... }
287+ t, n = re.subn(r ' ( defaultConfig\s * \{ ) ' ,
288+ r ' \1 \n testInstrumentationRunner "androidx. test. runner. AndroidJUnitRunner"' , t, count = 1 )
289+ modified = modified or (n != 0 )
290+
291+ # 2) Remove old android.test.* useLibrary lines
292+ t2, n = re.subn(r ' ^ \s * useLibrary\s + \' android\. test\. ( base| mock| runner) \' \s * \n ? ' , ' ' , t, flags = re.MULTILINE )
293+ if n:
294+ t = t2
295+ modified = True
284296
285- new_text, count = re.subn(r " ( defaultConfig\s * \{ ) " , add_runner, text, count = 1 , flags = re.MULTILINE )
286- if count:
287- text = new_text
288- modified = True
297+ # 3) Ensure androidTestImplementation deps exist (idempotent)
298+ def ensure_dep (body : str , dep : str ) -> str :
299+ if dep in body:
300+ return body
301+ # Try to find dependencies { ... }
302+ m = re.search(r ' ( ^ \s * dependencies\s * \{ ) ( . *? ^ \s * \} ) ' , body, flags = re.DOTALL | re.MULTILINE )
303+ if m:
304+ start, content, end = m.group(1 ), m.group(2 ), m.group(0 )[- 1 ]
305+ insert_at = m.end(1 )
306+ return body[:insert_at] + f ' \n androidTestImplementation " { dep} " ' + body[insert_at:]
289307 else :
290- raise SystemExit (" defaultConfig block not found while adding instrumentation runner" )
308+ # No dependencies block; create one at end
309+ return body + f ' \n\n dependencies {{\n androidTestImplementation " { dep} " \n}}\n '
291310
292- libraries = [
293- " useLibrary 'android .test.base' " ,
294- " useLibrary 'android .test.mock' " ,
295- " useLibrary 'android .test.runner' " ,
311+ deps = [
312+ " androidx .test:runner:1.5.2 " ,
313+ " androidx .test:core:1.5.0 " ,
314+ " androidx .test.services:storage:1.4.2 " ,
296315]
316+ for d in deps:
317+ nt = ensure_dep(t, d)
318+ if nt != t:
319+ t = nt
320+ modified = True
297321
298- missing_libraries = [lib for lib in libraries if lib not in text]
299- if missing_libraries:
300- match = re.search(r " ^ ( \s * android\s * \{ ) " , text, flags = re.MULTILINE )
301- if not match:
302- raise SystemExit (" android block not found while adding instrumentation libraries" )
303- line = match.group(1 )
304- indent = re.match(r " ^ ( \s * ) " , line).group(1 )
305- insertion = " " .join(f " \n { indent} { lib} " for lib in missing_libraries)
306- text = text[: match.end()] + insertion + text[match.end():]
307- modified = True
308-
309- if modified:
310- if not text.endswith(" \n " ):
311- text += " \n "
312- path.write_text(text)
322+ if modified and t != orig:
323+ # Keep a trailing newline
324+ if not t.endswith(" \n " ):
325+ t += " \n "
326+ p.write_text(t)
327+ print (" Applied AndroidX test runner/deps patch to build.gradle" )
328+ else :
329+ print (" AndroidX test runner/deps patch: no changes needed" )
313330PYTHON
314- ba_log " Ensured instrumentation runner and libraries are declared"
331+ ba_log " Ensured AndroidX instrumentation runner and dependencies are declared"
315332else
316333 ba_log " Warning: Gradle build file not found at $APP_BUILD_GRADLE ; skipping instrumentation dependency configuration" >&2
317334fi
318335
319336TEST_SRC_DIR=" $GRADLE_PROJECT_DIR /app/src/androidTest/java/${PACKAGE_PATH} "
320337mkdir -p " $TEST_SRC_DIR "
321338TEST_CLASS=" $TEST_SRC_DIR /HelloCodenameOneInstrumentedTest.java"
322- cat > " $TEST_CLASS " << EOF
323- package $PACKAGE_NAME ;
324-
325- import android.content.Context;
326- import android.test.InstrumentationTestCase;
339+ cat > " $TEST_CLASS " << 'EOF '
340+ package @PACKAGE@;
327341
328342import android.app.Instrumentation;
329343import android.os.ParcelFileDescriptor;
330- import android.util.Base64;
331344
345+ import androidx.test.ext.junit.runners.AndroidJUnit4;
346+ import androidx.test.platform.app.InstrumentationRegistry;
347+ import androidx.test.services.storage.TestStorage;
348+ import androidx.test.core.app.ApplicationProvider;
349+
350+ import org.junit.Test;
351+ import org.junit.runner.RunWith;
352+
353+ import java.io.File;
332354import java.io.FileInputStream;
333- import java.io.IOException ;
355+ import java.io.FileOutputStream ;
334356import java.io.InputStream;
357+ import java.io.ByteArrayOutputStream;
335358
336- public class HelloCodenameOneInstrumentedTest extends InstrumentationTestCase {
359+ import static org.junit.Assert.assertEquals;
337360
338- public void testUseAppContext() {
339- Context appContext = getInstrumentation().getTargetContext();
340- assertEquals("$PACKAGE_NAME ", appContext.getPackageName());
341- }
361+ @RunWith(AndroidJUnit4.class)
362+ public class HelloCodenameOneInstrumentedTest {
342363
343- private static final int CHUNK = 200_000;
364+ @Test
365+ public void testUseAppContext_andSaveScreenshot() throws Exception {
366+ // --- Your existing assertion (kept) ---
367+ String expectedPkg = "@PACKAGE@";
368+ String actualPkg = ApplicationProvider.getApplicationContext().getPackageName();
369+ assertEquals(expectedPkg, actualPkg);
344370
345- public static void printPngToStdout(Instrumentation inst) {
346- try {
371+ // --- Capture a PNG straight from the emulator and save to TestStorage ---
372+ Instrumentation inst = InstrumentationRegistry.getInstrumentation();
347373 ParcelFileDescriptor pfd = inst.getUiAutomation().executeShellCommand("screencap -p");
348- byte[] png;
349- try (InputStream in = new FileInputStream(pfd.getFileDescriptor())) {
350- png = readAll(in);
351- }
352- String b64 = Base64.encodeToString(png, Base64.NO_WRAP);
353- System.out.println("<<CN1_SCREENSHOT_BEGIN>>");
354- for (int i = 0; i < b64.length(); i += CHUNK) {
355- int end = Math.min(i + CHUNK, b64.length());
356- System.out.println(b64.substring(i, end));
374+
375+ byte[] png = readAll(new FileInputStream(pfd.getFileDescriptor()));
376+
377+ File outDir = TestStorage.getInstance().getOutputDir();
378+ File out = new File(outDir, "emulator-screenshot.png");
379+ try (FileOutputStream fos = new FileOutputStream(out)) {
380+ fos.write(png);
357381 }
358- System.out.println("<<CN1_SCREENSHOT_END>>");
359- System.out.flush();
360- } catch (IOException err) {
361- err.printStackTrace();
362- throw new RuntimeException(err);
363- }
382+
383+ System.out.println("WROTE_TO_TEST_STORAGE:" + out.getAbsolutePath());
364384 }
365385
366- private static byte[] readAll(InputStream in) throws IOException {
386+ private static byte[] readAll(InputStream in) throws Exception {
367387 byte[] buf = new byte[64 * 1024];
368388 int n;
369- java.io. ByteArrayOutputStream out = new java.io. ByteArrayOutputStream();
389+ ByteArrayOutputStream out = new ByteArrayOutputStream();
370390 while ((n = in.read(buf)) != -1) out.write(buf, 0, n);
371391 return out.toByteArray();
372392 }
373393}
374394EOF
395+
396+ # Fill in the package placeholder
397+ sed -i " s|@PACKAGE@|$PACKAGE_NAME |g" " $TEST_CLASS "
375398ba_log " Created instrumentation test at $TEST_CLASS "
376399
377400DEFAULT_ANDROID_TEST=" $GRADLE_PROJECT_DIR /app/src/androidTest/java/com/example/myapplication2/ExampleInstrumentedTest.java"
0 commit comments