diff --git a/vm/pom.xml b/vm/pom.xml index 1a77b37ae0..0f1e299e37 100644 --- a/vm/pom.xml +++ b/vm/pom.xml @@ -16,8 +16,8 @@ - 1.5 - 1.5 + 1.8 + 1.8 UTF-8 5.0.3 5.10.2 diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/BytecodeInstructionIntegrationTest.java b/vm/tests/src/test/java/com/codename1/tools/translator/BytecodeInstructionIntegrationTest.java index 1b2f6b8932..7ffd4c2abc 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/BytecodeInstructionIntegrationTest.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/BytecodeInstructionIntegrationTest.java @@ -10,6 +10,8 @@ import com.codename1.tools.translator.bytecodes.MultiArray; import com.codename1.tools.translator.bytecodes.VarOp; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; @@ -39,8 +41,12 @@ class BytecodeInstructionIntegrationTest { - @Test - void translatesOptimizedBytecodeToLLVMExecutable() throws Exception { + @ParameterizedTest + @ValueSource(strings = {"1.5", "1.8"}) + void translatesOptimizedBytecodeToLLVMExecutable(String targetVersion) throws Exception { + if ("1.5".equals(targetVersion) && !isSourceVersionSupported("1.5")) { + return; // Skip on newer JDKs that dropped 1.5 support + } Parser.cleanup(); Path sourceDir = Files.createTempDirectory("bytecode-integration-sources"); @@ -61,9 +67,9 @@ void translatesOptimizedBytecodeToLLVMExecutable() throws Exception { // Compile App using JavaAPI as bootclasspath List compileArgs = new ArrayList<>(); compileArgs.add("-source"); - compileArgs.add("1.5"); + compileArgs.add(targetVersion); compileArgs.add("-target"); - compileArgs.add("1.5"); + compileArgs.add(targetVersion); compileArgs.add("-bootclasspath"); compileArgs.add(javaApiDir.toString()); compileArgs.add("-d"); @@ -183,8 +189,12 @@ private String invokeLdcLocalVarsAppSource() { "}\n"; } - @Test - void translatesInvokeAndLdcBytecodeToLLVMExecutable() throws Exception { + @ParameterizedTest + @ValueSource(strings = {"1.5", "1.8"}) + void translatesInvokeAndLdcBytecodeToLLVMExecutable(String targetVersion) throws Exception { + if ("1.5".equals(targetVersion) && !isSourceVersionSupported("1.5")) { + return; // Skip on newer JDKs that dropped 1.5 support + } Parser.cleanup(); Path sourceDir = Files.createTempDirectory("invoke-ldc-sources"); @@ -204,9 +214,9 @@ void translatesInvokeAndLdcBytecodeToLLVMExecutable() throws Exception { List compileArgs = new ArrayList<>(); compileArgs.add("-source"); - compileArgs.add("1.5"); + compileArgs.add(targetVersion); compileArgs.add("-target"); - compileArgs.add("1.5"); + compileArgs.add(targetVersion); compileArgs.add("-bootclasspath"); compileArgs.add(javaApiDir.toString()); compileArgs.add("-d"); @@ -974,15 +984,19 @@ private String nativeReportSource() { "}\n"; } - @Test - void handleDefaultOutputWritesOutput() throws Exception { + @ParameterizedTest + @ValueSource(strings = {"1.5", "1.8"}) + void handleDefaultOutputWritesOutput(String targetVersion) throws Exception { + if ("1.5".equals(targetVersion) && !isSourceVersionSupported("1.5")) { + return; // Skip on newer JDKs that dropped 1.5 support + } Parser.cleanup(); resetByteCodeClass(); Path sourceDir = Files.createTempDirectory("default-output-source"); Path outputDir = Files.createTempDirectory("default-output-dest"); Files.write(sourceDir.resolve("resource.txt"), "data".getBytes(StandardCharsets.UTF_8)); - compileDummyMainClass(sourceDir, "com.example", "MyAppDefault"); + compileDummyMainClass(sourceDir, "com.example", "MyAppDefault", targetVersion); String[] args = new String[] { "csharp", @@ -1061,15 +1075,19 @@ void copyDirRecursivelyCopies() throws Exception { assertTrue(Files.exists(copiedRoot.resolve("subdir/file2.txt"))); } - @Test - void handleIosOutputGeneratesProjectStructure() throws Exception { + @ParameterizedTest + @ValueSource(strings = {"1.5", "1.8"}) + void handleIosOutputGeneratesProjectStructure(String targetVersion) throws Exception { + if ("1.5".equals(targetVersion) && !isSourceVersionSupported("1.5")) { + return; // Skip on newer JDKs that dropped 1.5 support + } Parser.cleanup(); resetByteCodeClass(); Path sourceDir = Files.createTempDirectory("ios-output-source"); Path outputDir = Files.createTempDirectory("ios-output-dest"); Files.write(sourceDir.resolve("resource.txt"), "data".getBytes(StandardCharsets.UTF_8)); - compileDummyMainClass(sourceDir, "com.example", "MyAppIOS"); + compileDummyMainClass(sourceDir, "com.example", "MyAppIOS", targetVersion); // Add a bundle to test copyDir invocation in execute loop Path bundleDir = sourceDir.resolve("test.bundle"); @@ -1121,7 +1139,7 @@ private void resetByteCodeClass() throws Exception { ((Set) writableFieldsField.get(null)).clear(); } - private void compileDummyMainClass(Path sourceDir, String packageName, String className) throws Exception { + private void compileDummyMainClass(Path sourceDir, String packageName, String className, String targetVersion) throws Exception { Path packageDir = sourceDir; for (String part : packageName.split("\\.")) { packageDir = packageDir.resolve(part); @@ -1136,8 +1154,8 @@ private void compileDummyMainClass(Path sourceDir, String packageName, String cl JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); int result = compiler.run(null, null, null, - "-source", "1.5", - "-target", "1.5", + "-source", targetVersion, + "-target", targetVersion, "-d", sourceDir.toString(), javaFile.toString()); assertEquals(0, result, "Compilation failed"); @@ -1243,4 +1261,20 @@ void testArithmeticExpressionCoverage() { // Let's rely on integration tests for complex dependency checks in ArithmeticExpression, // or mock if possible. But here we can check basic behavior. } + + private boolean isSourceVersionSupported(String version) { + String javaVersion = System.getProperty("java.specification.version"); + if (javaVersion.startsWith("1.")) { + return true; + } + try { + int major = Integer.parseInt(javaVersion); + if ("1.5".equals(version)) { + if (major >= 9) return false; + } + } catch (NumberFormatException e) { + return true; + } + return true; + } } diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java b/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java index 0c643a62ab..026e60dd03 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java @@ -1,6 +1,8 @@ package com.codename1.tools.translator; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import javax.tools.JavaCompiler; import javax.tools.ToolProvider; @@ -23,8 +25,12 @@ class CleanTargetIntegrationTest { - @Test - void generatesRunnableHelloWorldUsingCleanTarget() throws Exception { + @ParameterizedTest + @ValueSource(strings = {"1.5", "1.8"}) + void generatesRunnableHelloWorldUsingCleanTarget(String targetVersion) throws Exception { + if ("1.5".equals(targetVersion) && !isSourceVersionSupported("1.5")) { + return; // Skip on newer JDKs that dropped 1.5 support + } Parser.cleanup(); Path sourceDir = Files.createTempDirectory("clean-target-sources"); @@ -47,6 +53,8 @@ void generatesRunnableHelloWorldUsingCleanTarget() throws Exception { null, null, null, + "-source", targetVersion, + "-target", targetVersion, "-d", classesDir.toString(), javaFile.toString(), sourceDir.resolve("java/lang/Object.java").toString(), @@ -452,4 +460,20 @@ static String nativeHelloSource() { " printf(\"Hello, Clean Target!\\n\");\n" + "}\n"; } + + private boolean isSourceVersionSupported(String version) { + String javaVersion = System.getProperty("java.specification.version"); + if (javaVersion.startsWith("1.")) { + return true; + } + try { + int major = Integer.parseInt(javaVersion); + if ("1.5".equals(version)) { + if (major >= 9) return false; + } + } catch (NumberFormatException e) { + return true; + } + return true; + } } diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/ParserTest.java b/vm/tests/src/test/java/com/codename1/tools/translator/ParserTest.java index c3f118576a..ee8e13cb04 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/ParserTest.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/ParserTest.java @@ -3,6 +3,8 @@ import com.codename1.tools.translator.bytecodes.Instruction; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; @@ -24,9 +26,10 @@ void cleanParser() { Parser.cleanup(); } - @Test - void parsesBasicClassWithFieldsAndMethodBodies() throws Exception { - Path classFile = createSampleClass(); + @ParameterizedTest + @ValueSource(ints = {Opcodes.V1_5, Opcodes.V1_8}) + void parsesBasicClassWithFieldsAndMethodBodies(int opcodeVersion) throws Exception { + Path classFile = createSampleClass(opcodeVersion); Parser.parse(classFile.toFile()); @@ -54,9 +57,10 @@ void parsesBasicClassWithFieldsAndMethodBodies() throws Exception { assertEquals(Opcodes.IRETURN, opcodes.get(opcodes.size() - 1)); } - @Test - void parsesInterfacesAsAbstractContracts() throws Exception { - Path classFile = createTaskInterface(); + @ParameterizedTest + @ValueSource(ints = {Opcodes.V1_5, Opcodes.V1_8}) + void parsesInterfacesAsAbstractContracts(int opcodeVersion) throws Exception { + Path classFile = createTaskInterface(opcodeVersion); Parser.parse(classFile.toFile()); @@ -69,9 +73,10 @@ void parsesInterfacesAsAbstractContracts() throws Exception { assertTrue(method.canBeVirtual()); } - @Test - void parsesEnumMetadataAndBaseType() throws Exception { - Path classFile = createPriorityEnum(); + @ParameterizedTest + @ValueSource(ints = {Opcodes.V1_5, Opcodes.V1_8}) + void parsesEnumMetadataAndBaseType(int opcodeVersion) throws Exception { + Path classFile = createPriorityEnum(opcodeVersion); Parser.parse(classFile.toFile()); @@ -81,9 +86,10 @@ void parsesEnumMetadataAndBaseType() throws Exception { assertTrue(readPrivateBoolean(cls, "isEnum")); } - @Test - void parsesAnnotationsWithCorrectFlags() throws Exception { - Path classFile = createAnnotation(); + @ParameterizedTest + @ValueSource(ints = {Opcodes.V1_5, Opcodes.V1_8}) + void parsesAnnotationsWithCorrectFlags(int opcodeVersion) throws Exception { + Path classFile = createAnnotation(opcodeVersion); Parser.parse(classFile.toFile()); @@ -123,9 +129,9 @@ private boolean readPrivateBoolean(Object target, String fieldName) throws Excep return field.getBoolean(target); } - private Path createSampleClass() throws Exception { + private Path createSampleClass(int opcodeVersion) throws Exception { return writeClass("com/example/Sample", cw -> { - cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER, "com/example/Sample", null, "java/lang/Object", null); + cw.visit(opcodeVersion, Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER, "com/example/Sample", null, "java/lang/Object", null); cw.visitField(Opcodes.ACC_PRIVATE, "counter", "I", null, null).visitEnd(); cw.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL, "GREETING", "Ljava/lang/String;", null, "hi").visitEnd(); cw.visitField(Opcodes.ACC_PUBLIC, "names", "Ljava/util/List;", "Ljava/util/List;", null).visitEnd(); @@ -151,10 +157,10 @@ private Path createSampleClass() throws Exception { }); } - private Path createTaskInterface() throws Exception { + private Path createTaskInterface(int opcodeVersion) throws Exception { return writeClass("com/example/Task", cw -> { cw.visit( - Opcodes.V1_5, + opcodeVersion, Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT | Opcodes.ACC_INTERFACE, "com/example/Task", null, @@ -166,10 +172,10 @@ private Path createTaskInterface() throws Exception { }); } - private Path createPriorityEnum() throws Exception { + private Path createPriorityEnum(int opcodeVersion) throws Exception { return writeClass("com/example/Priority", cw -> { cw.visit( - Opcodes.V1_5, + opcodeVersion, Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_SUPER | Opcodes.ACC_ENUM, "com/example/Priority", null, @@ -252,10 +258,10 @@ private Path createPriorityEnum() throws Exception { }); } - private Path createAnnotation() throws Exception { + private Path createAnnotation(int opcodeVersion) throws Exception { return writeClass("com/example/TestAnnotation", cw -> { cw.visit( - Opcodes.V1_5, + opcodeVersion, Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT | Opcodes.ACC_INTERFACE | Opcodes.ACC_ANNOTATION, "com/example/TestAnnotation", null,