diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JavaAppDescTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JavaAppDescTest.java new file mode 100644 index 00000000000..a2cde44f009 --- /dev/null +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JavaAppDescTest.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.test; + +import java.nio.file.Path; +import java.util.List; +import java.util.function.UnaryOperator; +import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.Annotations.Parameters; + +public class JavaAppDescTest { + + public JavaAppDescTest(JavaAppDesc expectedAppDesc, JavaAppDesc actualAppDesc) { + this.expectedAppDesc = expectedAppDesc; + this.actualAppDesc = actualAppDesc; + } + + @Test + public void test() { + TKit.assertEquals(expectedAppDesc.toString(), actualAppDesc.toString(), null); + TKit.assertTrue(expectedAppDesc.equals(actualAppDesc), null); + } + + @Test + @Parameter({"Foo", "Foo.class"}) + @Parameter({"com.bar.A", "com/bar/A.class"}) + @Parameter({"module/com.bar.A", "com/bar/A.class"}) + public static void testClassFilePath(String... args) { + var appDesc = args[0]; + var expectedClassFilePath = Path.of(args[1]); + TKit.assertEquals(expectedClassFilePath.toString(), JavaAppDesc.parse( + appDesc).classFilePath().toString(), null); + } + + @Parameters + public static List input() { + return List.of(new Object[][] { + createTestCase("", "hello.jar:Hello"), + createTestCase("foo.jar*", "foo.jar*hello.jar:Hello"), + createTestCase("Bye", "hello.jar:Bye"), + createTestCase("bye.jar:", "bye.jar:Hello"), + createTestCase("duke.jar:com.other/com.other.foo.bar.Buz!@3.7", appDesc -> { + return appDesc + .setBundleFileName("duke.jar") + .setModuleName("com.other") + .setClassName("com.other.foo.bar.Buz") + .setWithMainClass(true) + .setModuleVersion("3.7"); + }), + }); + } + + private static JavaAppDesc[] createTestCase(String inputAppDesc, String expectedAppDescStr) { + return createTestCase(inputAppDesc, appDesc -> { + return stripDefaultSrcJavaPath(JavaAppDesc.parse(expectedAppDescStr)); + }); + } + + private static JavaAppDesc stripDefaultSrcJavaPath(JavaAppDesc appDesc) { + var defaultAppDesc = HelloApp.createDefaltAppDesc(); + if (appDesc.srcJavaPath().equals(defaultAppDesc.srcJavaPath())) { + appDesc.setSrcJavaPath(null); + } + return appDesc; + } + + private static JavaAppDesc[] createTestCase(String appDesc, UnaryOperator config) { + var actualAppDesc = stripDefaultSrcJavaPath(JavaAppDesc.parse(appDesc)); + + var expectedAppDesc = config.apply(stripDefaultSrcJavaPath(HelloApp.createDefaltAppDesc())); + + return new JavaAppDesc[] {expectedAppDesc, actualAppDesc}; + } + + private final JavaAppDesc expectedAppDesc; + private final JavaAppDesc actualAppDesc; +} diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.java new file mode 100644 index 00000000000..3f55c3c50ae --- /dev/null +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TKitTest.java @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.test; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; +import jdk.jpackage.test.Annotations.Parameters; +import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.Functional.ThrowingRunnable; +import static jdk.jpackage.test.Functional.ThrowingRunnable.toRunnable; +import static jdk.jpackage.test.Functional.ThrowingSupplier.toSupplier; + +public class TKitTest { + + @Parameters + public static Collection assertTestsData() { + List data = new ArrayList<>(); + + var assertFunc = MethodCallConfig.build("assertTrue", boolean.class, String.class); + data.addAll(List.of(assertFunc.args(true).pass().expectLog("assertTrue()").createForMessage("Catbird"))); + data.addAll(List.of(assertFunc.args(false).fail().expectLog("Failed").createForMessage("Catbird"))); + + assertFunc = MethodCallConfig.build("assertFalse", boolean.class, String.class); + data.addAll(List.of(assertFunc.args(false).pass().expectLog("assertFalse()").createForMessage("Stork"))); + data.addAll(List.of(assertFunc.args(true).fail().expectLog("Failed").createForMessage("Stork"))); + + assertFunc = MethodCallConfig.build("assertEquals", String.class, String.class, String.class); + data.addAll(List.of(assertFunc.args("a", "a").pass().expectLog("assertEquals(a)").createForMessage("Crow"))); + data.addAll(List.of(assertFunc.args("a", "b").fail().expectLog("Expected [a]. Actual [b]").createForMessage("Crow"))); + + assertFunc = MethodCallConfig.build("assertEquals", long.class, long.class, String.class); + data.addAll(List.of(assertFunc.args(7, 7).pass().expectLog("assertEquals(7)").createForMessage("Owl"))); + data.addAll(List.of(assertFunc.args(7, 10).fail().expectLog("Expected [7]. Actual [10]").createForMessage("Owl"))); + + assertFunc = MethodCallConfig.build("assertNotEquals", String.class, String.class, String.class); + data.addAll(List.of(assertFunc.args("a", "b").pass().expectLog("assertNotEquals(a, b)").createForMessage("Tit"))); + data.addAll(List.of(assertFunc.args("a", "a").fail().expectLog("Unexpected [a] value").createForMessage("Tit"))); + + assertFunc = MethodCallConfig.build("assertNotEquals", long.class, long.class, String.class); + data.addAll(List.of(assertFunc.args(7, 10).pass().expectLog("assertNotEquals(7, 10)").createForMessage("Duck"))); + data.addAll(List.of(assertFunc.args(7, 7).fail().expectLog("Unexpected [7] value").createForMessage("Duck"))); + + assertFunc = MethodCallConfig.build("assertNull", Object.class, String.class); + data.addAll(List.of(assertFunc.args((Object) null).pass().expectLog("assertNull()").createForMessage("Ibis"))); + data.addAll(List.of(assertFunc.args("v").fail().expectLog("Unexpected not null value [v]").createForMessage("Ibis"))); + + assertFunc = MethodCallConfig.build("assertNotNull", Object.class, String.class); + data.addAll(List.of(assertFunc.args("v").pass().expectLog("assertNotNull(v)").createForMessage("Pigeon"))); + data.addAll(List.of(assertFunc.args((Object) null).fail().expectLog("Unexpected null value").createForMessage("Pigeon"))); + + assertFunc = MethodCallConfig.build("assertStringListEquals", List.class, List.class, String.class); + data.addAll(List.of(assertFunc.args(List.of(), List.of()).pass().expectLog( + "assertStringListEquals()").createForMessage("Gull"))); + + data.addAll(List.of(assertFunc.args(List.of("a", "b"), List.of("a", "b")).pass().expectLog( + "assertStringListEquals()", + "assertStringListEquals(1, a)", + "assertStringListEquals(2, b)").createForMessage("Pelican"))); + + assertFunc.fail().withAutoExpectLogPrefix(false); + for (var msg : new String[] { "Raven", null }) { + data.addAll(List.of(assertFunc.args(List.of("a"), List.of("a", "b"), msg).expectLog( + concatMessages("TRACE: assertStringListEquals()", msg), + "TRACE: assertStringListEquals(1, a)", + concatMessages("ERROR: Actual list is longer than expected by 1 elements", msg) + ).create())); + + data.addAll(List.of(assertFunc.args(List.of("n", "m"), List.of("n"), msg).expectLog( + concatMessages("TRACE: assertStringListEquals()", msg), + "TRACE: assertStringListEquals(1, n)", + concatMessages("ERROR: Actual list is shorter than expected by 1 elements", msg) + ).create())); + + data.addAll(List.of(assertFunc.args(List.of("a", "b"), List.of("n", "m"), msg).expectLog( + concatMessages("TRACE: assertStringListEquals()", msg), + concatMessages("ERROR: (1) Expected [a]. Actual [n]", msg) + ).create())); + } + + return data.stream().map(v -> { + return new Object[]{v}; + }).toList(); + } + + public record MethodCallConfig(Method method, Object[] args, boolean expectFail, String[] expectLog) { + @Override + public String toString() { + return String.format("%s%s%s", method.getName(), Arrays.toString(args), expectFail ? "!" : ""); + } + + static Builder build(String name, Class ... parameterTypes) { + return new Builder(name, parameterTypes); + } + + private static class Builder { + Builder(Method method) { + Objects.requireNonNull(method); + this.method = method; + } + + Builder(String name, Class ... parameterTypes) { + method = toSupplier(() -> TKit.class.getMethod(name, parameterTypes)).get(); + } + + MethodCallConfig create() { + String[] effectiveExpectLog; + if (!withAutoExpectLogPrefix) { + effectiveExpectLog = expectLog; + } else { + var prefix = expectFail ? "ERROR: " : "TRACE: "; + effectiveExpectLog = Stream.of(expectLog).map(line -> { + return prefix + line; + }).toArray(String[]::new); + } + return new MethodCallConfig(method, args, expectFail, effectiveExpectLog); + } + + MethodCallConfig[] createForMessage(String msg) { + return Arrays.asList(msg, null).stream().map(curMsg -> { + var builder = new Builder(method); + builder.expectFail = expectFail; + builder.withAutoExpectLogPrefix = withAutoExpectLogPrefix; + builder.args = Stream.concat(Stream.of(args), Stream.of(curMsg)).toArray(); + builder.expectLog = Arrays.copyOf(expectLog, expectLog.length); + builder.expectLog[0] = concatMessages(builder.expectLog[0], curMsg); + return builder.create(); + }).toArray(MethodCallConfig[]::new); + } + + Builder fail() { + expectFail = true; + return this; + } + + Builder pass() { + expectFail = false; + return this; + } + + Builder args(Object ... v) { + args = v; + return this; + } + + Builder expectLog(String expectLogFirstStr, String ... extra) { + expectLog = Stream.concat(Stream.of(expectLogFirstStr), Stream.of(extra)).toArray(String[]::new); + return this; + } + + Builder withAutoExpectLogPrefix(boolean v) { + withAutoExpectLogPrefix = v; + return this; + } + + private final Method method; + private Object[] args = new Object[0]; + private boolean expectFail; + private String[] expectLog; + private boolean withAutoExpectLogPrefix = true; + } + } + + public TKitTest(MethodCallConfig methodCall) { + this.methodCall = methodCall; + } + + @Test + public void test() { + runAssertWithExpectedLogOutput(() -> { + methodCall.method.invoke(null, methodCall.args); + }, methodCall.expectFail, methodCall.expectLog); + } + + private static void runAssertWithExpectedLogOutput(ThrowingRunnable action, + boolean expectFail, String... expectLogStrings) { + runWithExpectedLogOutput(() -> { + TKit.assertAssert(!expectFail, toRunnable(action)); + }, expectLogStrings); + } + + private static void runWithExpectedLogOutput(ThrowingRunnable action, + String... expectLogStrings) { + final var buf = new ByteArrayOutputStream(); + try (PrintStream ps = new PrintStream(buf, true, StandardCharsets.UTF_8)) { + TKit.withExtraLogStream(action, ps); + } finally { + toRunnable(() -> { + var output = new BufferedReader(new InputStreamReader( + new ByteArrayInputStream(buf.toByteArray()), + StandardCharsets.UTF_8)).lines().map(line -> { + // Skip timestamp + return line.substring(LOG_MSG_TIMESTAMP_LENGTH); + }).toList(); + if (output.size() == 1 && expectLogStrings.length == 1) { + TKit.assertEquals(expectLogStrings[0], output.get(0), null); + } else { + TKit.assertStringListEquals(List.of(expectLogStrings), output, null); + } + }).run(); + } + } + + private static String concatMessages(String msg, String msg2) { + if (msg2 != null && !msg2.isBlank()) { + return msg + ": " + msg2; + } + return msg; + } + + private final MethodCallConfig methodCall; + + private static final int LOG_MSG_TIMESTAMP_LENGTH = "[HH:mm:ss.SSS] ".length(); +} diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TestSuite.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TestSuite.java new file mode 100644 index 00000000000..f9dda851414 --- /dev/null +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/TestSuite.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.test; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +/* + * @test + * @summary Unit tests for jpackage test library + * @library /test/jdk/tools/jpackage/helpers + * @library /test/jdk/tools/jpackage/helpers-test + * @build jdk.jpackage.test.* + * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.TestSuite + */ + +public final class TestSuite { + public static void main(String args[]) throws Throwable { + final var pkgName = TestSuite.class.getPackageName(); + final var javaSuffix = ".java"; + final var testSrcNameSuffix = "Test" + javaSuffix; + + final var unitTestDir = TKit.TEST_SRC_ROOT.resolve(Path.of("helpers-test", pkgName.split("\\."))); + + final List runTestArgs = new ArrayList<>(); + runTestArgs.addAll(List.of(args)); + + try (var javaSources = Files.list(unitTestDir)) { + runTestArgs.addAll(javaSources.filter(path -> { + return path.getFileName().toString().endsWith(testSrcNameSuffix); + }).map(path -> { + var filename = path.getFileName().toString(); + return String.join(".", pkgName, filename.substring(0, filename.length() - javaSuffix.length())); + }).map(testClassName -> { + return "--jpt-run=" + testClassName; + }).toList()); + } + + Main.main(runTestArgs.toArray(String[]::new)); + } +} diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java index 1e51f8452b3..4afd96cdf88 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java @@ -37,6 +37,7 @@ import java.util.List; import java.util.Objects; import java.util.Set; +import java.util.function.Supplier; import java.util.regex.Pattern; import java.util.spi.ToolProvider; import java.util.stream.Collectors; @@ -250,18 +251,49 @@ public List executeAndGetOutput() { return saveOutput().execute().getOutput(); } + private static class BadResultException extends RuntimeException { + BadResultException(Result v) { + value = v; + } + + Result getValue() { + return value; + } + + private final Result value; + } + /* * Repeates command "max" times and waits for "wait" seconds between each * execution until command returns expected error code. */ public Result executeAndRepeatUntilExitCode(int expectedCode, int max, int wait) { - Result result; + try { + return tryRunMultipleTimes(() -> { + Result result = executeWithoutExitCodeCheck(); + if (result.getExitCode() != expectedCode) { + throw new BadResultException(result); + } + return result; + }, max, wait).assertExitCodeIs(expectedCode); + } catch (BadResultException ex) { + return ex.getValue().assertExitCodeIs(expectedCode); + } + } + + /* + * Repeates a "task" "max" times and waits for "wait" seconds between each + * execution until the "task" returns without throwing an exception. + */ + public static T tryRunMultipleTimes(Supplier task, int max, int wait) { + RuntimeException lastException = null; int count = 0; do { - result = executeWithoutExitCodeCheck(); - if (result.getExitCode() == expectedCode) { - return result; + try { + return task.get(); + } catch (RuntimeException ex) { + lastException = ex; } try { @@ -273,7 +305,14 @@ public Result executeAndRepeatUntilExitCode(int expectedCode, int max, int wait) count++; } while (count < max); - return result.assertExitCodeIs(expectedCode); + throw lastException; + } + + public static void tryRunMultipleTimes(Runnable task, int max, int wait) { + tryRunMultipleTimes(() -> { + task.run(); + return null; + }, max, wait); } public List executeWithoutExitCodeCheckAndGetOutput() { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Functional.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Functional.java index 87718c1394c..a57caa92cb2 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Functional.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Functional.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -151,12 +151,16 @@ public ExceptionBox(Throwable throwable) { @SuppressWarnings("unchecked") public static RuntimeException rethrowUnchecked(Throwable throwable) throws ExceptionBox { - if (throwable instanceof RuntimeException) { - throw (RuntimeException)throwable; + if (throwable instanceof RuntimeException err) { + throw err; } - if (throwable instanceof InvocationTargetException) { - throw new ExceptionBox(throwable.getCause()); + if (throwable instanceof Error err) { + throw err; + } + + if (throwable instanceof InvocationTargetException err) { + throw rethrowUnchecked(err.getCause()); } throw new ExceptionBox(throwable); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java index 7d5472fd5be..ffe59971107 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java @@ -22,7 +22,6 @@ */ package jdk.jpackage.test; -import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -57,15 +56,10 @@ public final class HelloApp { private JarBuilder prepareSources(Path srcDir) throws IOException { final String srcClassName = appDesc.srcClassName(); - - final String qualifiedClassName = appDesc.className(); - - final String className = qualifiedClassName.substring( - qualifiedClassName.lastIndexOf('.') + 1); + final String className = appDesc.shortClassName(); final String packageName = appDesc.packageName(); - final Path srcFile = srcDir.resolve(Path.of(String.join( - File.separator, qualifiedClassName.split("\\.")) + ".java")); + final Path srcFile = srcDir.resolve(appDesc.classNameAsPath(".java")); Files.createDirectories(srcFile.getParent()); JarBuilder jarBuilder = createJarBuilder().addSourceFile(srcFile); @@ -348,7 +342,7 @@ private static AppOutputVerifier getVerifier(JPackageCommand cmd, } - public final static class AppOutputVerifier { + public static final class AppOutputVerifier { AppOutputVerifier(Path helloAppLauncher) { this.launcherPath = helloAppLauncher; this.outputFilePath = TKit.workDir().resolve(OUTPUT_FILENAME); @@ -479,13 +473,13 @@ public static AppOutputVerifier assertApp(Path helloAppLauncher) { return new AppOutputVerifier(helloAppLauncher); } - final static String OUTPUT_FILENAME = "appOutput.txt"; + static final String OUTPUT_FILENAME = "appOutput.txt"; private final JavaAppDesc appDesc; private static final Path HELLO_JAVA = TKit.TEST_SRC_ROOT.resolve( "apps/Hello.java"); - private final static String CLASS_NAME = HELLO_JAVA.getFileName().toString().split( + private static final String CLASS_NAME = HELLO_JAVA.getFileName().toString().split( "\\.", 2)[0]; } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaAppDesc.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaAppDesc.java index 6a798012ca7..c0807deef3b 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaAppDesc.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaAppDesc.java @@ -22,8 +22,9 @@ */ package jdk.jpackage.test; -import java.io.File; import java.nio.file.Path; +import java.util.Objects; +import java.util.stream.Stream; public final class JavaAppDesc { @@ -73,9 +74,18 @@ public String className() { return qualifiedClassName; } + public String shortClassName() { + return qualifiedClassName.substring(qualifiedClassName.lastIndexOf('.') + 1); + } + + Path classNameAsPath(String extension) { + final String[] pathComponents = qualifiedClassName.split("\\."); + pathComponents[pathComponents.length - 1] = shortClassName() + extension; + return Stream.of(pathComponents).map(Path::of).reduce(Path::resolve).get(); + } + public Path classFilePath() { - return Path.of(qualifiedClassName.replace(".", File.separator) - + ".class"); + return classNameAsPath(".class"); } public String moduleName() { @@ -124,6 +134,48 @@ public boolean isWithMainClass() { return withMainClass; } + @Override + public int hashCode() { + int hash = 5; + hash = 79 * hash + Objects.hashCode(this.srcJavaPath); + hash = 79 * hash + Objects.hashCode(this.qualifiedClassName); + hash = 79 * hash + Objects.hashCode(this.moduleName); + hash = 79 * hash + Objects.hashCode(this.bundleFileName); + hash = 79 * hash + Objects.hashCode(this.moduleVersion); + hash = 79 * hash + (this.withMainClass ? 1 : 0); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final JavaAppDesc other = (JavaAppDesc) obj; + if (this.withMainClass != other.withMainClass) { + return false; + } + if (!Objects.equals(this.qualifiedClassName, other.qualifiedClassName)) { + return false; + } + if (!Objects.equals(this.moduleName, other.moduleName)) { + return false; + } + if (!Objects.equals(this.bundleFileName, other.bundleFileName)) { + return false; + } + if (!Objects.equals(this.moduleVersion, other.moduleVersion)) { + return false; + } + return Objects.equals(this.srcJavaPath, other.srcJavaPath); + } + @Override public String toString() { StringBuilder sb = new StringBuilder(); @@ -216,7 +268,9 @@ public static JavaAppDesc parse(final String javaAppDesc) { components[0].length() - 1); desc.setWithMainClass(true); } - desc.setClassName(components[0]); + if (!components[0].isEmpty()) { + desc.setClassName(components[0]); + } if (components.length == 2) { desc.setModuleVersion(components[1]); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java index c5bf16d1291..b9f1fc6806e 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java @@ -94,7 +94,9 @@ void verifyLauncherIcon(JPackageCommand cmd, String launcherName, Files.copy(getDefaultAppLauncher(expectedIcon == null && !expectedDefault), iconContainer); if (expectedIcon != null) { - setIcon(expectedIcon, iconContainer); + Executor.tryRunMultipleTimes(() -> { + setIcon(expectedIcon, iconContainer); + }, 3, 5); } Path extractedExpectedIcon = extractIconFromExecutable( diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java index 0884b41dc55..76639d30128 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/PackageTest.java @@ -24,7 +24,6 @@ import java.awt.Desktop; import java.awt.GraphicsEnvironment; -import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -709,7 +708,7 @@ private static Map createDefaultPackageHandlers() private Set namedInitializers; private Map packageHandlers; - private final static File BUNDLE_OUTPUT_DIR; + private static final Path BUNDLE_OUTPUT_DIR; static { final String propertyName = "output"; @@ -717,9 +716,9 @@ private static Map createDefaultPackageHandlers() if (val == null) { BUNDLE_OUTPUT_DIR = null; } else { - BUNDLE_OUTPUT_DIR = new File(val).getAbsoluteFile(); + BUNDLE_OUTPUT_DIR = Path.of(val).toAbsolutePath(); - if (!BUNDLE_OUTPUT_DIR.isDirectory()) { + if (!Files.isDirectory(BUNDLE_OUTPUT_DIR)) { throw new IllegalArgumentException(String.format("Invalid value of %s sytem property: [%s]. Should be existing directory", TKit.getConfigPropertyName(propertyName), BUNDLE_OUTPUT_DIR)); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java index 2298ada5612..d2c328fc4a7 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java @@ -22,7 +22,6 @@ */ package jdk.jpackage.test; -import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; @@ -103,14 +102,21 @@ static void withExtraLogStream(ThrowingRunnable action) { ThrowingRunnable.toRunnable(action).run(); } else { try (PrintStream logStream = openLogStream()) { - extraLogStream = logStream; - ThrowingRunnable.toRunnable(action).run(); - } finally { - extraLogStream = null; + withExtraLogStream(action, logStream); } } } + static void withExtraLogStream(ThrowingRunnable action, PrintStream logStream) { + var oldExtraLogStream = extraLogStream; + try { + extraLogStream = logStream; + ThrowingRunnable.toRunnable(action).run(); + } finally { + extraLogStream = oldExtraLogStream; + } + } + static void runTests(List tests) { if (currentTest != null) { throw new IllegalStateException( @@ -183,11 +189,7 @@ public static boolean isLinux() { } public static boolean isLinuxAPT() { - if (!isLinux()) { - return false; - } - File aptFile = new File("/usr/bin/apt-get"); - return aptFile.exists(); + return isLinux() && Files.exists(Path.of("/usr/bin/apt-get")); } private static String addTimestamp(String msg) { @@ -264,6 +266,22 @@ public static void error(String v) { throw new AssertionError(v); } + static void assertAssert(boolean expectedSuccess, Runnable runnable) { + try { + runnable.run(); + } catch (AssertionError err) { + if (expectedSuccess) { + assertUnexpected("Assertion failed"); + } else { + return; + } + } + + if (!expectedSuccess) { + assertUnexpected("Assertion passed"); + } + } + private final static String TEMP_FILE_PREFIX = null; private static Path createUniqueFileName(String defaultName) { @@ -569,7 +587,7 @@ public static void assertEquals(long expected, long actual, String msg) { msg)); } - traceAssert(String.format("assertEquals(%d): %s", expected, msg)); + traceAssert(concatMessages(String.format("assertEquals(%d)", expected), msg)); } public static void assertNotEquals(long expected, long actual, String msg) { @@ -579,8 +597,8 @@ public static void assertNotEquals(long expected, long actual, String msg) { msg)); } - traceAssert(String.format("assertNotEquals(%d, %d): %s", expected, - actual, msg)); + traceAssert(concatMessages(String.format("assertNotEquals(%d, %d)", expected, + actual), msg)); } public static void assertEquals(String expected, String actual, String msg) { @@ -592,7 +610,7 @@ public static void assertEquals(String expected, String actual, String msg) { msg)); } - traceAssert(String.format("assertEquals(%s): %s", expected, msg)); + traceAssert(concatMessages(String.format("assertEquals(%s)", expected), msg)); } public static void assertNotEquals(String expected, String actual, String msg) { @@ -600,8 +618,8 @@ public static void assertNotEquals(String expected, String actual, String msg) { if ((actual != null && !actual.equals(expected)) || (expected != null && !expected.equals(actual))) { - traceAssert(String.format("assertNotEquals(%s, %s): %s", expected, - actual, msg)); + traceAssert(concatMessages(String.format("assertNotEquals(%s, %s)", expected, + actual), msg)); return; } @@ -615,7 +633,7 @@ public static void assertNull(Object value, String msg) { value), msg)); } - traceAssert(String.format("assertNull(): %s", msg)); + traceAssert(concatMessages("assertNull()", msg)); } public static void assertNotNull(Object value, String msg) { @@ -624,7 +642,7 @@ public static void assertNotNull(Object value, String msg) { error(concatMessages("Unexpected null value", msg)); } - traceAssert(String.format("assertNotNull(%s): %s", value, msg)); + traceAssert(concatMessages(String.format("assertNotNull(%s)", value), msg)); } public static void assertTrue(boolean actual, String msg) { @@ -644,7 +662,7 @@ public static void assertTrue(boolean actual, String msg, Runnable onFail) { error(concatMessages("Failed", msg)); } - traceAssert(String.format("assertTrue(): %s", msg)); + traceAssert(concatMessages("assertTrue()", msg)); } public static void assertFalse(boolean actual, String msg, Runnable onFail) { @@ -656,7 +674,7 @@ public static void assertFalse(boolean actual, String msg, Runnable onFail) { error(concatMessages("Failed", msg)); } - traceAssert(String.format("assertFalse(): %s", msg)); + traceAssert(concatMessages("assertFalse()", msg)); } public static void assertPathExists(Path path, boolean exists) { @@ -727,7 +745,7 @@ public static void assertStringListEquals(List expected, List actual, String msg) { currentTest.notifyAssert(); - traceAssert(String.format("assertStringListEquals(): %s", msg)); + traceAssert(concatMessages("assertStringListEquals()", msg)); String idxFieldFormat = Functional.identity(() -> { int listSize = expected.size(); @@ -757,7 +775,7 @@ public static void assertStringListEquals(List expected, expectedStr)); }); - if (expected.size() < actual.size()) { + if (actual.size() > expected.size()) { // Actual string list is longer than expected error(concatMessages(String.format( "Actual list is longer than expected by %d elements", @@ -767,7 +785,7 @@ public static void assertStringListEquals(List expected, if (actual.size() < expected.size()) { // Actual string list is shorter than expected error(concatMessages(String.format( - "Actual list is longer than expected by %d elements", + "Actual list is shorter than expected by %d elements", expected.size() - actual.size()), msg)); } } diff --git a/test/jdk/tools/jpackage/share/AddLauncherTest.java b/test/jdk/tools/jpackage/share/AddLauncherTest.java index 1fd930117fc..29008896dd0 100644 --- a/test/jdk/tools/jpackage/share/AddLauncherTest.java +++ b/test/jdk/tools/jpackage/share/AddLauncherTest.java @@ -22,7 +22,6 @@ */ import java.nio.file.Path; -import java.io.File; import java.util.Map; import java.lang.invoke.MethodHandles; import jdk.jpackage.test.PackageTest; @@ -227,11 +226,11 @@ public void testMainLauncherIsModular(boolean mainLauncherIsModular) { TKit.assertEquals(ExpectedCN, mainClass, String.format("Check value of app.mainclass=[%s]" + "in NonModularAppLauncher cfg file is as expected", ExpectedCN)); - TKit.assertTrue(classpath.startsWith("$APPDIR" + File.separator - + nonModularAppDesc.jarFileName()), + TKit.assertTrue(classpath.startsWith(Path.of("$APPDIR", + nonModularAppDesc.jarFileName()).toString()), "Check app.classpath value in ModularAppLauncher cfg file"); } - private final static Path GOLDEN_ICON = TKit.TEST_SRC_ROOT.resolve(Path.of( + private static final Path GOLDEN_ICON = TKit.TEST_SRC_ROOT.resolve(Path.of( "resources", "icon" + TKit.ICON_SUFFIX)); }