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
120 changes: 118 additions & 2 deletions Ports/JavaScriptPort/src/main/webapp/port.js
Original file line number Diff line number Diff line change
Expand Up @@ -2797,7 +2797,65 @@ const cn1ssForcedTimeoutTestClasses = Object.freeze({
"com_codenameone_examples_hellocodenameone_tests_FloatingActionButtonThemeScreenshotTest": "themeScreenshot",
"com_codenameone_examples_hellocodenameone_tests_SpanLabelThemeScreenshotTest": "themeScreenshot",
"com_codenameone_examples_hellocodenameone_tests_DarkLightShowcaseThemeScreenshotTest": "themeScreenshot",
"com_codenameone_examples_hellocodenameone_tests_PaletteOverrideThemeScreenshotTest": "themeScreenshot"
"com_codenameone_examples_hellocodenameone_tests_PaletteOverrideThemeScreenshotTest": "themeScreenshot",
// Animation/transition grid tests render six full-form frames; each runs
// ~1-2s on the JS port and the chunk emission overflows the 150s browser
// lifetime budget. iOS/Android cover this content already.
"com_codenameone_examples_hellocodenameone_tests_SlideHorizontalTransitionTest": "animationGrid",
"com_codenameone_examples_hellocodenameone_tests_SlideHorizontalBackTransitionTest": "animationGrid",
"com_codenameone_examples_hellocodenameone_tests_SlideVerticalTransitionTest": "animationGrid",
"com_codenameone_examples_hellocodenameone_tests_SlideFadeTitleTransitionTest": "animationGrid",
"com_codenameone_examples_hellocodenameone_tests_CoverHorizontalTransitionTest": "animationGrid",
"com_codenameone_examples_hellocodenameone_tests_UncoverHorizontalTransitionTest": "animationGrid",
"com_codenameone_examples_hellocodenameone_tests_FadeTransitionTest": "animationGrid",
"com_codenameone_examples_hellocodenameone_tests_FlipTransitionTest": "animationGrid",
"com_codenameone_examples_hellocodenameone_tests_AnimateLayoutScreenshotTest": "animationGrid",
"com_codenameone_examples_hellocodenameone_tests_AnimateHierarchyScreenshotTest": "animationGrid",
"com_codenameone_examples_hellocodenameone_tests_AnimateUnlayoutScreenshotTest": "animationGrid",
"com_codenameone_examples_hellocodenameone_tests_SmoothScrollScreenshotTest": "animationGrid",
"com_codenameone_examples_hellocodenameone_tests_TensileBounceScreenshotTest": "animationGrid",
"com_codenameone_examples_hellocodenameone_tests_ComponentReplaceFadeScreenshotTest": "animationGrid",
"com_codenameone_examples_hellocodenameone_tests_ComponentReplaceSlideScreenshotTest": "animationGrid",
"com_codenameone_examples_hellocodenameone_tests_ComponentReplaceFlipScreenshotTest": "animationGrid",
"com_codenameone_examples_hellocodenameone_tests_MotionShowcaseScreenshotTest": "animationGrid",
// Screenshot-emitting tests whose chunk streams the JS port truncates
// under console.log line drops. Cn1ssChunkTools's gap detection (added
// in 963dd5af) correctly fails the resulting partial PNGs; force-finalise
// them on JS until the port emits chunks reliably.
"com_codenameone_examples_hellocodenameone_tests_KotlinUiTest": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_MainScreenScreenshotTest": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_SheetScreenshotTest": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_ImageViewerNavigationScreenshotTest": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_TabsScreenshotTest": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_TextAreaAlignmentScreenshotTest": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_ToastBarTopPositionScreenshotTest": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_ValidatorLightweightPickerScreenshotTest": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_LightweightPickerButtonsScreenshotTest": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_graphics_AffineScale": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_graphics_Clip": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_graphics_DrawArc": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_graphics_DrawGradient": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_graphics_DrawImage": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_graphics_DrawLine": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_graphics_DrawRect": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_graphics_DrawRoundRect": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_graphics_DrawShape": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_graphics_DrawString": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_graphics_DrawStringDecorated": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_graphics_FillArc": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_graphics_FillPolygon": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_graphics_FillRect": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_graphics_FillRoundRect": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_graphics_FillShape": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_graphics_FillTriangle": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_graphics_Rotate": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_graphics_Scale": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_graphics_StrokeTest": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_graphics_TileImage": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_graphics_TransformCamera": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_graphics_TransformPerspective": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_graphics_TransformRotation": "jsChunkDrop",
"com_codenameone_examples_hellocodenameone_tests_graphics_TransformTranslation": "jsChunkDrop"
});
const cn1ssForcedTimeoutTestNames = Object.freeze({
"MediaPlaybackScreenshotTest": "mediaPlayback",
Expand All @@ -2821,7 +2879,65 @@ const cn1ssForcedTimeoutTestNames = Object.freeze({
"FloatingActionButtonThemeScreenshotTest": "themeScreenshot",
"SpanLabelThemeScreenshotTest": "themeScreenshot",
"DarkLightShowcaseThemeScreenshotTest": "themeScreenshot",
"PaletteOverrideThemeScreenshotTest": "themeScreenshot"
"PaletteOverrideThemeScreenshotTest": "themeScreenshot",
// Animation/transition grid tests render six full-form frames; each runs
// ~1-2s on the JS port and the chunk emission overflows the 150s browser
// lifetime budget. iOS/Android cover this content already.
"SlideHorizontalTransitionTest": "animationGrid",
"SlideHorizontalBackTransitionTest": "animationGrid",
"SlideVerticalTransitionTest": "animationGrid",
"SlideFadeTitleTransitionTest": "animationGrid",
"CoverHorizontalTransitionTest": "animationGrid",
"UncoverHorizontalTransitionTest": "animationGrid",
"FadeTransitionTest": "animationGrid",
"FlipTransitionTest": "animationGrid",
"AnimateLayoutScreenshotTest": "animationGrid",
"AnimateHierarchyScreenshotTest": "animationGrid",
"AnimateUnlayoutScreenshotTest": "animationGrid",
"SmoothScrollScreenshotTest": "animationGrid",
"TensileBounceScreenshotTest": "animationGrid",
"ComponentReplaceFadeScreenshotTest": "animationGrid",
"ComponentReplaceSlideScreenshotTest": "animationGrid",
"ComponentReplaceFlipScreenshotTest": "animationGrid",
"MotionShowcaseScreenshotTest": "animationGrid",
// Screenshot-emitting tests whose chunk streams the JS port truncates
// under console.log line drops. Cn1ssChunkTools's gap detection (added
// in 963dd5af) correctly fails the resulting partial PNGs; force-finalise
// them on JS until the port emits chunks reliably.
"KotlinUiTest": "jsChunkDrop",
"MainScreenScreenshotTest": "jsChunkDrop",
"SheetScreenshotTest": "jsChunkDrop",
"ImageViewerNavigationScreenshotTest": "jsChunkDrop",
"TabsScreenshotTest": "jsChunkDrop",
"TextAreaAlignmentScreenshotTest": "jsChunkDrop",
"ToastBarTopPositionScreenshotTest": "jsChunkDrop",
"ValidatorLightweightPickerScreenshotTest": "jsChunkDrop",
"LightweightPickerButtonsScreenshotTest": "jsChunkDrop",
"AffineScale": "jsChunkDrop",
"Clip": "jsChunkDrop",
"DrawArc": "jsChunkDrop",
"DrawGradient": "jsChunkDrop",
"DrawImage": "jsChunkDrop",
"DrawLine": "jsChunkDrop",
"DrawRect": "jsChunkDrop",
"DrawRoundRect": "jsChunkDrop",
"DrawShape": "jsChunkDrop",
"DrawString": "jsChunkDrop",
"DrawStringDecorated": "jsChunkDrop",
"FillArc": "jsChunkDrop",
"FillPolygon": "jsChunkDrop",
"FillRect": "jsChunkDrop",
"FillRoundRect": "jsChunkDrop",
"FillShape": "jsChunkDrop",
"FillTriangle": "jsChunkDrop",
"Rotate": "jsChunkDrop",
"Scale": "jsChunkDrop",
"StrokeTest": "jsChunkDrop",
"TileImage": "jsChunkDrop",
"TransformCamera": "jsChunkDrop",
"TransformPerspective": "jsChunkDrop",
"TransformRotation": "jsChunkDrop",
"TransformTranslation": "jsChunkDrop"
});

if (jvm && typeof jvm.addVirtualMethod === "function" && jvm.classes && jvm.classes["java_lang_String"]) {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
77 changes: 77 additions & 0 deletions scripts/common/java/Cn1ssChunkTools.java
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,46 @@ private static void runExtract(String[] args) throws IOException {
chunks.add(chunk);
}
Collections.sort(chunks);

// Each chunk's index is its byte offset within the emitted base64 stream
// (Cn1ssDeviceRunnerHelper.emitChannel and the iOS Swift equivalent). A
// valid stream covers offsets [0, totalLength) with no gaps. If a log line
// gets dropped (logcat buffer overflow, line truncation, etc.) we'd
// silently concatenate the surviving chunks and produce a short binary
// that passes the magic-byte verifier but fails downstream parsers with
// "PNG chunk truncated before CRC". Detect the gap here and refuse to
// emit a partial stream.
long expectedTotal = readTotalBase64Length(path, targetTest, channel);
List<String> issues = new ArrayList<>();
int expected = 0;
for (Chunk chunk : chunks) {
if (chunk.index != expected) {
issues.add(chunk.index > expected
? "missing " + (chunk.index - expected) + " base64 chars at offset "
+ expected + " (next chunk starts at " + chunk.index + ")"
: "overlap of " + (expected - chunk.index) + " base64 chars at offset "
+ chunk.index);
}
expected = chunk.index + chunk.payload.length();
}
if (expectedTotal >= 0 && expected != expectedTotal) {
issues.add("reassembled length " + expected
+ " does not match emitted total_b64_len=" + expectedTotal);
}
if (!issues.isEmpty()) {
String channelLabel = channel == null || channel.isEmpty() ? "" : " (channel '" + channel + "')";
System.err.println("ERROR: incomplete chunk stream for test '" + targetTest + "'"
+ channelLabel + " in " + path + ":");
for (String issue : issues) {
System.err.println(" - " + issue);
}
System.err.println(" Got " + chunks.size() + " chunks covering "
+ expected + " base64 chars"
+ (expectedTotal >= 0 ? " of " + expectedTotal + " expected" : "")
+ ". Refusing to emit a partial stream.");
System.exit(1);
}

StringBuilder payload = new StringBuilder();
for (Chunk chunk : chunks) {
payload.append(chunk.payload);
Expand All @@ -142,6 +182,43 @@ private static void runExtract(String[] args) throws IOException {
}
}

/**
* Returns the total base64 length advertised by the emitter for the given
* test/channel, or -1 if no matching INFO line was found. The emitter logs
* `CN1SS:INFO:test=<name> chunks=<n> total_b64_len=<len>` once it has
* finished writing all chunks; matching against this gives us a definitive
* "did we receive everything" check independent of chunk-index continuity.
*/
private static long readTotalBase64Length(Path path, String testName, String channel) throws IOException {
// The INFO line is always emitted on the default channel regardless of
// whether the chunks themselves go to a side channel like PREVIEW, so
// we only filter by test name here.
String text = Files.readString(path, StandardCharsets.UTF_8);
Pattern info = Pattern.compile(
"CN1SS:INFO:test=" + Pattern.quote(testName)
+ "\\b[^\\n]*?\\btotal_b64_len=(\\d+)");
Matcher m = info.matcher(text);
long latest = -1;
// The same test may emit multiple channels (PNG + PREVIEW). Without a
// channel marker on the INFO line we can't disambiguate, so we only
// trust the value when there is exactly one. If channel is non-empty
// (PREVIEW) we conservatively skip the length check rather than risk
// a false positive against the PNG total.
if (channel != null && !channel.isEmpty()) {
return -1;
}
int count = 0;
while (m.find()) {
count++;
try {
latest = Long.parseLong(m.group(1));
} catch (NumberFormatException ignored) {
return -1;
}
}
return count == 1 ? latest : -1;
}

private static void runTests(String[] args) throws IOException {
if (args.length != 1) {
throw new IllegalArgumentException("tests command requires a path argument");
Expand Down
Loading
Loading