Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -59,6 +60,56 @@ public boolean test(String value) {
return value.length() == 1;
}
}));

List<String> distinctSorted = Stream.of("delta", "beta", "alpha", "beta", "gamma", "alpha")
.distinct()
.sorted()
.skip(1)
.limit(2)
.collect(Collectors.<String>toList());
assertEqual(Arrays.asList(new String[]{"beta", "delta"}), distinctSorted, "distinct/sorted/skip/limit pipeline failed");

Object[] arrayResult = Stream.of("x", "y", "z").skip(2).toArray();
assertEqual(1, arrayResult.length, "Unexpected toArray length after skip");
assertEqual("z", arrayResult[0], "Unexpected toArray value after skip");

long emptyCount = Stream.<String>empty().count();
assertEqual(0L, emptyCount, "Stream.empty() should produce a stream with zero elements");

long zeroLimitedCount = Stream.of(Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3)).limit(0).count();
assertEqual(0L, zeroLimitedCount, "limit(0) should produce zero elements");

long skippedPastEnd = Stream.of(Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3)).skip(99).count();
assertEqual(0L, skippedPastEnd, "Skipping past the end should produce an empty stream");

StringBuffer forEachOrder = new StringBuffer();
Stream.of(Integer.valueOf(3), Integer.valueOf(1), Integer.valueOf(2)).sorted().forEach(new Consumer<Integer>() {
public void accept(Integer value) {
forEachOrder.append(value.intValue());
}
});
assertEqual("123", forEachOrder.toString(), "forEach should preserve sorted encounter order");

assertTrue(!Stream.<String>empty().anyMatch(new Predicate<String>() {
public boolean test(String value) {
return true;
}
}), "anyMatch on empty stream should be false");

assertTrue(Stream.<String>empty().allMatch(new Predicate<String>() {
public boolean test(String value) {
return false;
}
}), "allMatch on empty stream should be true");

assertTrue(Stream.<String>empty().noneMatch(new Predicate<String>() {
public boolean test(String value) {
return true;
}
}), "noneMatch on empty stream should be true");

long distinctWithNullCount = Stream.of("x", "x", null, null, "y").distinct().count();
assertEqual(3L, distinctWithNullCount, "distinct should keep one null and unique non-null values");
} catch (Throwable t) {
fail("Stream API test failed: " + t);
return false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package com.codename1.tools.translator;

import org.junit.jupiter.api.Test;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import static org.junit.jupiter.api.Assertions.*;

class StreamApiIntegrationTest {

@Test
void streamEdgeCasesMatchBetweenJavaSEAndParparVM() throws Exception {
Parser.cleanup();

Path sourceDir = Files.createTempDirectory("stream-integration-sources");
Path classesDir = Files.createTempDirectory("stream-integration-classes");
Path javaApiDir = Files.createTempDirectory("java-api-classes");

Path source = sourceDir.resolve("StreamEdgeApp.java");
Files.write(source, loadAppSource().getBytes(StandardCharsets.UTF_8));

CompilerHelper.CompilerConfig config = selectCompiler();
if (config == null) {
fail("No compatible compiler available for stream integration test");
}

assertTrue(CompilerHelper.isJavaApiCompatible(config),
"JDK " + config.jdkVersion + " must target matching bytecode level for JavaAPI");

CompilerHelper.compileJavaAPI(javaApiDir, config);

List<String> compileArgs = new ArrayList<>();
compileArgs.add("-source");
compileArgs.add(config.targetVersion);
compileArgs.add("-target");
compileArgs.add(config.targetVersion);
if (CompilerHelper.useClasspath(config)) {
compileArgs.add("-classpath");
compileArgs.add(javaApiDir.toString());
} else {
compileArgs.add("-bootclasspath");
compileArgs.add(javaApiDir.toString());
compileArgs.add("-Xlint:-options");
}
compileArgs.add("-d");
compileArgs.add(classesDir.toString());
compileArgs.add(source.toString());

int compileResult = CompilerHelper.compile(config.jdkHome, compileArgs);
assertEquals(0, compileResult, "StreamEdgeApp should compile");

String javaOutput = runJavaMain(config, classesDir, javaApiDir);
String javaResult = extractResultLine(javaOutput);
assertTrue(javaResult.startsWith("RESULT="), "JavaSE should produce a RESULT line. Output: " + javaOutput);

CompilerHelper.copyDirectory(javaApiDir, classesDir);

Path outputDir = Files.createTempDirectory("stream-integration-output");
CleanTargetIntegrationTest.runTranslator(classesDir, outputDir, "StreamEdgeApp");

Path distDir = outputDir.resolve("dist");
Path cmakeLists = distDir.resolve("CMakeLists.txt");
assertTrue(Files.exists(cmakeLists), "Translator should emit a CMake project");

CleanTargetIntegrationTest.replaceLibraryWithExecutableTarget(cmakeLists, "StreamEdgeApp-src");

Path buildDir = distDir.resolve("build");
Files.createDirectories(buildDir);

CleanTargetIntegrationTest.runCommand(Arrays.asList(
"cmake",
"-S", distDir.toString(),
"-B", buildDir.toString(),
"-DCMAKE_C_COMPILER=clang",
"-DCMAKE_OBJC_COMPILER=clang"
), distDir);

CleanTargetIntegrationTest.runCommand(Arrays.asList("cmake", "--build", buildDir.toString()), distDir);

Path executable = buildDir.resolve("StreamEdgeApp");
String parparOutput = CleanTargetIntegrationTest.runCommand(Arrays.asList(executable.toString()), buildDir);
String parparResult = extractResultLine(parparOutput);
assertTrue(parparResult.startsWith("RESULT="), "ParparVM execution should produce a RESULT line. Output: " + parparOutput);

assertEquals(javaResult, parparResult,
"JavaSE and ParparVM should emit identical result lines for stream edge cases");
}

private String loadAppSource() throws Exception {
java.io.InputStream in = StreamApiIntegrationTest.class.getResourceAsStream("/com/codename1/tools/translator/StreamEdgeApp.java");
assertNotNull(in, "StreamEdgeApp.java test resource should exist");
try (BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
return reader.lines().collect(Collectors.joining("\n")) + "\n";
}
}

private String runJavaMain(CompilerHelper.CompilerConfig config, Path classesDir, Path javaApiDir) throws Exception {
String javaExe = config.jdkHome.resolve("bin").resolve("java").toString();
if (System.getProperty("os.name").toLowerCase().contains("win")) {
javaExe += ".exe";
}

ProcessBuilder pb = new ProcessBuilder(
javaExe,
"-cp",
classesDir + System.getProperty("path.separator") + javaApiDir,
"StreamEdgeApp"
);
pb.redirectErrorStream(true);

Process process = pb.start();
String output;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) {
output = reader.lines().collect(Collectors.joining("\n"));
}

int exitCode = process.waitFor();
assertEquals(0, exitCode, "JVM run should exit cleanly. Output: " + output);
return output;
}

private String extractResultLine(String output) {
for (String line : output.split("\\R")) {
if (line.startsWith("RESULT=")) {
return line.trim();
}
}
return "";
}

private CompilerHelper.CompilerConfig selectCompiler() {
String[] preferredTargets = {"11", "17", "21", "25", "1.8"};
for (String target : preferredTargets) {
List<CompilerHelper.CompilerConfig> configs = CompilerHelper.getAvailableCompilers(target);
for (CompilerHelper.CompilerConfig config : configs) {
if (CompilerHelper.isJavaApiCompatible(config)) {
return config;
}
}
}
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import java.util.stream.Stream;

public class StreamEdgeApp {
private static int calculate() {
Object[] transformed = Stream.of(4, 2, 9, 2, 7, 4)
.distinct()
.sorted()
.skip(1)
.limit(3)
.toArray();
int transformedSum = ((Integer) transformed[0]).intValue()
+ ((Integer) transformed[1]).intValue()
+ ((Integer) transformed[2]).intValue();

int reduce = Stream.of(1, 2, 3, 4).reduce(10, (a, b) -> a + b);

final int[] forEachCode = new int[] { 0 };
Stream.of(3, 1, 2).sorted().forEach(i -> forEachCode[0] = forEachCode[0] * 10 + i);

Object[] arr = Stream.of(5, 6).skip(1).toArray();
long emptyCount = Stream.<Integer>empty().count();

int matchScore = 0;
if (!Stream.<Integer>empty().anyMatch(v -> true)) {
matchScore += 1;
}
if (Stream.<Integer>empty().allMatch(v -> false)) {
matchScore += 10;
}
if (Stream.<Integer>empty().noneMatch(v -> true)) {
matchScore += 100;
}

long clampCount = Stream.of(1, 2, 3).skip(5).limit(2).count();
long distinctCount = Stream.of(1, 1, 2, 3, 3).distinct().count();

int checksum = 0;
checksum += transformedSum * 2;
checksum += reduce;
checksum += forEachCode[0];
checksum += ((Integer) arr[0]).intValue() * 7;
checksum += (int) emptyCount * 11;
checksum += matchScore;
checksum += (int) clampCount;
checksum += (int) distinctCount * 13;
return checksum;
}

public static void main(String[] args) {
System.out.println("RESULT=" + calculate());
}
}
Loading