From 5ddb0fd10858106f508d2f2c9b6f64d9ea094de5 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Mon, 27 Apr 2026 14:34:33 +0000 Subject: [PATCH] 8383168: jpackage: enhance capabilities of the test lib for testing jpackage console output Reviewed-by: almatvee --- .../test/CannedFormattedStringTest.java | 22 +++ .../test/CannedMessageFormatTest.java | 171 ++++++++++++++++++ .../test/JPackageStringBundleTest.java | 55 ------ .../jpackage/test/CannedFormattedString.java | 24 ++- .../jpackage/test/CannedMessageFormat.java | 166 +++++++++++++++++ .../helpers/jdk/jpackage/test/Executor.java | 28 ++- .../jdk/jpackage/test/JPackageCommand.java | 57 +++--- .../jpackage/test/JPackageStringBundle.java | 100 +--------- 8 files changed, 441 insertions(+), 182 deletions(-) create mode 100644 test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/CannedMessageFormatTest.java create mode 100644 test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CannedMessageFormat.java diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/CannedFormattedStringTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/CannedFormattedStringTest.java index 2e4ad9ab754..2a93590d5cc 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/CannedFormattedStringTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/CannedFormattedStringTest.java @@ -25,6 +25,7 @@ package jdk.jpackage.test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertThrowsExactly; import java.text.MessageFormat; import java.util.List; @@ -83,6 +84,27 @@ class CannedFormattedStringTest { assertEquals("Hello Java! Bye Java", b.getValue()); } + @Test + void test_createFromMessageFormat() { + var a = CannedFormattedString.createFromMessageFormat("Hello {0}!", "Duke"); + var b = CannedFormattedString.createFromMessageFormat("Hello {0}!", "Duke"); + var c = CannedFormattedString.createFromMessageFormat("Bye {0}!", "Duke"); + + assertEquals(a, b); + assertEquals(a.getValue(), b.getValue()); + assertNotEquals(a, c); + + assertEquals("Hello Duke!", a.getValue()); + assertEquals("Bye Duke!", c.getValue()); + + assertEquals("Repeated message: Hello Duke! Hello Duke!", a.addPrefix("Repeated message: {0} {0}").getValue()); + + assertEquals("No formatting", CannedFormattedString.createFromMessageFormat("No formatting").getValue()); + + assertThrowsExactly(IllegalArgumentException.class, + CannedFormattedString.createFromMessageFormat("No formatting", "foo")::getValue); + } + enum Formatter implements BiFunction { MESSAGE_FORMAT { @Override diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/CannedMessageFormatTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/CannedMessageFormatTest.java new file mode 100644 index 00000000000..58ede0453d2 --- /dev/null +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/CannedMessageFormatTest.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2026, 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 static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrowsExactly; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; +import java.util.regex.Pattern; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +class CannedMessageFormatTest { + + @Test + void test_ctor() { + var cmf = CannedMessageFormat.create("Foo {1}{1} Bar {0}", 327, Boolean.TRUE); + assertTrue(cmf.messageFormat().isPresent()); + assertEquals("Foo truetrue Bar 327", cmf.value()); + } + + @Test + void test_ctor_no_args() { + var cmf = CannedMessageFormat.create("Foo"); + assertEquals(Optional.empty(), cmf.messageFormat()); + assertEquals("Foo", cmf.value()); + } + + @Test + void test_ctor_wrong_number_of_args() { + var ex = assertThrowsExactly(IllegalArgumentException.class, () -> { + CannedMessageFormat.create("Foo", 7, "", 89); + }); + assertEquals("Expected 0 arguments for [Foo] string, but given 3", ex.getMessage()); + + ex = assertThrowsExactly(IllegalArgumentException.class, () -> { + CannedMessageFormat.create("Foo {0}", 7, "", 89); + }); + assertEquals("Expected 1 arguments for [Foo {0}] string, but given 3", ex.getMessage()); + + ex = assertThrowsExactly(IllegalArgumentException.class, () -> { + CannedMessageFormat.create("Foo {0}"); + }); + assertEquals("Expected 1 arguments for [Foo {0}] string, but given 0", ex.getMessage()); + } + + @Test + void test_ctor_invalid_parameters() { + assertThrowsExactly(NullPointerException.class, () -> { + CannedMessageFormat.create(null); + }); + + assertThrowsExactly(NullPointerException.class, () -> { + CannedMessageFormat.create("Foo {0}", (String)null); + }); + } + + @ParameterizedTest + @MethodSource + void test_toPattern(TestSpec test) { + test.expectedPattern().ifPresentOrElse(expectedPattern -> { + var pattern = CannedMessageFormat.create(test.format(), test.args().toArray()).toPattern(test.formatArgMapper()); + assertEquals(expectedPattern.toString(), pattern.toString()); + }, () -> { + assertThrowsExactly(IllegalArgumentException.class, () -> { + CannedMessageFormat.create(test.format(), test.args().toArray()); + }); + }); + } + + @Test + void testEscapes() { + assertEquals("Foo 327327 Bar {1}", CannedMessageFormat.create("Foo {0}{0} Bar '{1}'", 327).value()); + + assertEquals("Foo '{0}{0}'", CannedMessageFormat.create("Foo '{0}{0}'").value()); + } + + private static Collection test_toPattern() { + + var testCases = new ArrayList(); + + testCases.addAll(List.of( + TestSpec.create("", Pattern.compile(Pattern.quote(""))), + TestSpec.create("", "foo") + )); + + for (List args : List.of(List.of())) { + Stream.of( + "Stop." + ).map(formatter -> { + return new TestSpec(formatter, args, Optional.of(Pattern.compile(Pattern.quote(formatter)))); + }).forEach(testCases::add); + } + + for (List args : List.of(List.of("foo"))) { + Stream.of( + "Stop." + ).map(formatter -> { + return new TestSpec(formatter, args, Optional.empty()); + }).forEach(testCases::add); + } + + testCases.add(TestSpec.create("Hello {1} {0}{1}!", Pattern.compile("\\QHello \\E.*\\Q \\E.*.*\\Q!\\E"), "foo", "bar")); + testCases.add(TestSpec.create("Hello {1} {0}{0} {0}{0}{0} {0}", Pattern.compile("\\QHello \\E.*\\Q \\E.*\\Q \\E.*\\Q \\E.*"), "foo", "bar")); + testCases.add(TestSpec.create("{0}{0}", Pattern.compile(".*"), "foo")); + + return testCases; + } + + record TestSpec(String format, List args, Optional expectedPattern) { + TestSpec { + Objects.requireNonNull(format); + Objects.requireNonNull(args); + Objects.requireNonNull(expectedPattern); + } + + Function formatArgMapper() { + if (Pattern.compile(Pattern.quote(format)).toString().equals(expectedPattern.orElseThrow().toString())) { + return UNREACHABLE_FORMAT_ARG_MAPPER; + } else { + return DEFAULT_FORMAT_ARG_MAPPER; + } + } + + static TestSpec create(String format, Pattern expectedPattern, Object... args) { + return new TestSpec(format, List.of(args), Optional.of(expectedPattern)); + } + + static TestSpec create(String format, Object... args) { + return new TestSpec(format, List.of(args), Optional.empty()); + } + } + + private static final Pattern DEFAULT_FORMAT_ARG_PATTERN = Pattern.compile(".*"); + + private static final Function DEFAULT_FORMAT_ARG_MAPPER = _ -> { + return DEFAULT_FORMAT_ARG_PATTERN; + }; + + private static final Function UNREACHABLE_FORMAT_ARG_MAPPER = _ -> { + throw new AssertionError(); + }; +} diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JPackageStringBundleTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JPackageStringBundleTest.java index 0512d03b76a..9667bbabcb9 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JPackageStringBundleTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JPackageStringBundleTest.java @@ -28,14 +28,10 @@ import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertThrowsExactly; import static org.junit.jupiter.api.Assertions.assertTrue; -import java.text.MessageFormat; -import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Objects; import java.util.function.Function; import java.util.regex.Pattern; -import java.util.stream.Stream; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -106,13 +102,6 @@ class JPackageStringBundleTest { }); } - @ParameterizedTest - @MethodSource - void test_toPattern(TestSpec test) { - var pattern = JPackageStringBundle.toPattern(new MessageFormat(test.formatter()), test.formatArgMapper(), test.args().toArray()); - assertEquals(test.expectedPattern().toString(), pattern.toString()); - } - private static Collection test_cannedFormattedString_wrong_argument_count() { return List.of( JPackageStringBundle.MAIN.cannedFormattedString("error.version-string-empty", "foo"), @@ -121,50 +110,6 @@ class JPackageStringBundleTest { ); } - private static Collection test_toPattern() { - - var testCases = new ArrayList(); - - testCases.addAll(List.of( - TestSpec.create("", Pattern.compile("")), - TestSpec.create("", Pattern.compile(""), "foo") - )); - - for (List args : List.of(List.of(), List.of("foo"))) { - Stream.of( - "Stop." - ).map(formatter -> { - return new TestSpec(formatter, args, Pattern.compile(Pattern.quote(formatter))); - }).forEach(testCases::add); - } - - testCases.add(TestSpec.create("Hello {1} {0}{1}!", Pattern.compile("\\QHello \\E.*\\Q \\E.*.*\\Q!\\E"), "foo", "bar")); - testCases.add(TestSpec.create("Hello {1} {0}{0} {0}{0}{0} {0}", Pattern.compile("\\QHello \\E.*\\Q \\E.*\\Q \\E.*\\Q \\E.*"), "foo", "bar")); - testCases.add(TestSpec.create("{0}{0}", Pattern.compile(".*"), "foo")); - - return testCases; - } - - record TestSpec(String formatter, List args, Pattern expectedPattern) { - TestSpec { - Objects.requireNonNull(formatter); - Objects.requireNonNull(args); - Objects.requireNonNull(expectedPattern); - } - - Function formatArgMapper() { - if (Pattern.compile(Pattern.quote(formatter)).toString().equals(expectedPattern.toString())) { - return UNREACHABLE_FORMAT_ARG_MAPPER; - } else { - return DEFAULT_FORMAT_ARG_MAPPER; - } - } - - static TestSpec create(String formatter, Pattern expectedPattern, Object... args) { - return new TestSpec(formatter, List.of(args), expectedPattern); - } - } - private static final Pattern DEFAULT_FORMAT_ARG_PATTERN = Pattern.compile(".*"); private static final Function DEFAULT_FORMAT_ARG_MAPPER = _ -> { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CannedFormattedString.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CannedFormattedString.java index cc31c416d44..3ad92e47005 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CannedFormattedString.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CannedFormattedString.java @@ -30,22 +30,22 @@ import java.util.function.UnaryOperator; import java.util.regex.Pattern; import java.util.stream.Stream; -public record CannedFormattedString(BiFunction formatter, String key, List args) implements CannedArgument { +public record CannedFormattedString(BiFunction formatter, String format, List args) implements CannedArgument { public CannedFormattedString mapArgs(UnaryOperator mapper) { - return new CannedFormattedString(formatter, key, args.stream().map(mapper).toList()); + return new CannedFormattedString(formatter, format, args.stream().map(mapper).toList()); } public CannedFormattedString { Objects.requireNonNull(formatter); - Objects.requireNonNull(key); + Objects.requireNonNull(format); Objects.requireNonNull(args); args.forEach(Objects::requireNonNull); } @Override public String getValue() { - return formatter.apply(key, args.stream().map(arg -> { + return formatter.apply(format, args.stream().map(arg -> { if (arg instanceof CannedArgument cannedArg) { return cannedArg.getValue(); } else { @@ -54,17 +54,17 @@ public record CannedFormattedString(BiFunction formatt }).toArray()); } - public CannedFormattedString addPrefix(String prefixKey) { + public CannedFormattedString addPrefix(String prefixFormat) { return new CannedFormattedString( - new AddPrefixFormatter(formatter), prefixKey, Stream.concat(Stream.of(key), args.stream()).toList()); + new AddPrefixFormatter(formatter), prefixFormat, Stream.concat(Stream.of(format), args.stream()).toList()); } @Override public String toString() { if (args.isEmpty()) { - return String.format("%s", key); + return String.format("%s", format); } else { - return String.format("%s+%s", key, args); + return String.format("%s+%s", format, args); } } @@ -85,6 +85,10 @@ public record CannedFormattedString(BiFunction formatt } } + public static CannedFormattedString createFromMessageFormat(String messageFormatStr, Object... args) { + return new CannedFormattedString(MESSAGE_FORMAT_FORMATTER, messageFormatStr, List.of(args)); + } + private record AddPrefixFormatter(BiFunction formatter) implements BiFunction { AddPrefixFormatter { @@ -97,4 +101,8 @@ public record CannedFormattedString(BiFunction formatt return formatter.apply(format, new Object[] {str}); } } + + private static final BiFunction MESSAGE_FORMAT_FORMATTER = (String format, Object[] args) -> { + return CannedMessageFormat.create(format, args).value(); + }; } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CannedMessageFormat.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CannedMessageFormat.java new file mode 100644 index 00000000000..8192785434b --- /dev/null +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/CannedMessageFormat.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2026, 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.text.MessageFormat; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; +import java.util.regex.Pattern; + +public final class CannedMessageFormat { + + private CannedMessageFormat(MessageFormat messageFormat, Object[] args) { + this.messageFormat = Optional.of(messageFormat); + this.args = Arrays.copyOf(args, args.length); + } + + private CannedMessageFormat(String value) { + this.messageFormat = Optional.empty(); + this.args = new Object[] {value}; + } + + public String value() { + return messageFormat.map(mf -> { + return mf.format(args); + }).orElseGet(() -> { + return (String)args[0]; + }); + } + + public Optional messageFormat() { + return messageFormat; + } + + public Pattern toPattern(Function formatArgMapper) { + return messageFormat.map(mf -> { + return toPattern(mf, formatArgMapper, args); + }).orElseGet(() -> { + return Pattern.compile(Pattern.quote(value())); + }); + } + + public Pattern toPattern() { + return toPattern(MATCH_ANY); + } + + /** + * Creates {@code CannedMessageFormat} instance from the given format string and + * format arguments. + * + * @param formatString format string suitable for use as the first argument of + * {@link MessageFormat#format(String, Object...)} call + * @param args an array of objects to be formatted and substituted + * @return the {@code CannedMessageFormat} instance + */ + public static CannedMessageFormat create(String formatString, Object... args) { + return create( + defaultInvalidFormatArgumentCountExceptionSupplier(formatString, args.length), + formatString, + args); + } + + static CannedMessageFormat create( + Function invalidFormatArgumentCountExceptionSupplier, + String formatString, + Object... args) { + + Objects.requireNonNull(invalidFormatArgumentCountExceptionSupplier); + Objects.requireNonNull(formatString); + List.of(args).forEach(Objects::requireNonNull); + + var mf = new MessageFormat(formatString); + var formatCount = mf.getFormatsByArgumentIndex().length; + if (formatCount != args.length) { + throw Objects.requireNonNull(invalidFormatArgumentCountExceptionSupplier.apply(formatCount)); + } + + if (formatCount == 0) { + return new CannedMessageFormat(formatString); + } else { + return new CannedMessageFormat(mf, args); + } + } + + static Function defaultInvalidFormatArgumentCountExceptionSupplier(String formatString, int argc) { + Objects.requireNonNull(formatString); + return formatCount -> { + return new IllegalArgumentException(String.format( + "Expected %d arguments for [%s] string, but given %d", formatCount, formatString, argc)); + }; + } + + private static Pattern toPattern(MessageFormat mf, Function formatArgMapper, Object ... args) { + Objects.requireNonNull(mf); + Objects.requireNonNull(formatArgMapper); + + var patternSb = new StringBuilder(); + var runSb = new StringBuilder(); + + var it = mf.formatToCharacterIterator(args); + while (it.getIndex() < it.getEndIndex()) { + var runBegin = it.getRunStart(); + var runEnd = it.getRunLimit(); + if (runEnd < runBegin) { + throw new IllegalStateException(); + } + + var attrs = it.getAttributes(); + if (attrs.isEmpty()) { + // Regular text run. + runSb.setLength(0); + it.setIndex(runBegin); + for (int counter = runEnd - runBegin; counter != 0; --counter) { + runSb.append(it.current()); + it.next(); + } + patternSb.append(Pattern.quote(runSb.toString())); + } else { + // Format run. + int argi = (Integer)attrs.get(MessageFormat.Field.ARGUMENT); + var arg = args[argi]; + var pattern = Objects.requireNonNull(formatArgMapper.apply(arg)); + patternSb.append(pattern.toString()); + it.setIndex(runEnd); + } + } + + return Pattern.compile(patternSb.toString()); + } + + private final Object[] args; + private final Optional messageFormat; + + private static final Function MATCH_ANY = new Function<>() { + + @Override + public Pattern apply(Object v) { + return PATTERN; + } + + private static final Pattern PATTERN = Pattern.compile(".*"); + }; +} 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 1ae678cd944..66eab196937 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java @@ -63,7 +63,25 @@ public final class Executor extends CommandArguments { } public Executor() { - commandOutputControl.dumpStdout(TKit.state().out()).dumpStderr(TKit.state().err()); + commandOutputControl = new CommandOutputControl() + .dumpStdout(TKit.state().out()) + .dumpStderr(TKit.state().err()); + removeEnvVars = new HashSet<>(); + setEnvVars = new HashMap<>(); + } + + public Executor(Executor other) { + toolProvider = other.toolProvider; + executable = other.executable; + commandOutputControl = other.commandOutputControl.copy(); + directory = other.directory; + removeEnvVars = new HashSet<>(other.removeEnvVars); + setEnvVars = new HashMap<>(other.setEnvVars); + winTmpDir = other.winTmpDir; + } + + public Executor copy() { + return new Executor(this); } public Executor setExecutable(String v) { @@ -537,9 +555,9 @@ public final class Executor extends CommandArguments { private ToolProvider toolProvider; private Path executable; - private final CommandOutputControl commandOutputControl = new CommandOutputControl(); + private final CommandOutputControl commandOutputControl; private Path directory; - private Set removeEnvVars = new HashSet<>(); - private Map setEnvVars = new HashMap<>(); - private String winTmpDir = null; + private final Set removeEnvVars; + private final Map setEnvVars; + private String winTmpDir; } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index 861b717bea0..42a5096d2c0 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -80,6 +80,7 @@ public class JPackageCommand extends CommandArguments { @SuppressWarnings("this-escape") public JPackageCommand() { toolProviderSource = new ToolProviderSource(); + executorPrototype = new Executor().dumpOutput(true); prerequisiteActions = new Actions(); verifyActions = new Actions(); excludeStandardAsserts(StandardAssert.MAIN_LAUNCHER_DESCRIPTION); @@ -89,10 +90,7 @@ public class JPackageCommand extends CommandArguments { private JPackageCommand(JPackageCommand cmd, boolean immutable) { args.addAll(cmd.args); toolProviderSource = cmd.toolProviderSource.copy(); - saveConsoleOutput = cmd.saveConsoleOutput; - discardStdout = cmd.discardStdout; - discardStderr = cmd.discardStderr; - suppressOutput = cmd.suppressOutput; + executorPrototype = cmd.executorPrototype.copy(); ignoreDefaultRuntime = cmd.ignoreDefaultRuntime; ignoreDefaultVerbose = cmd.ignoreDefaultVerbose; removeOldOutputBundle = cmd.removeOldOutputBundle; @@ -346,6 +344,14 @@ public class JPackageCommand extends CommandArguments { return this; } + public String fullVersion() { + if (isImagePackageType() || !PackageType.LINUX.contains(packageType())) { + return version(); + } else { + return version() + LinuxHelper.getReleaseSuffix(this); + } + } + public String name() { return nameFromAppImage().or(this::nameFromBasicArgs).or(this::nameFromRuntimeImage).orElseThrow(); } @@ -936,27 +942,39 @@ public class JPackageCommand extends CommandArguments { return this; } + public JPackageCommand removeEnvVars(String ... envVarName) { + verifyMutable(); + List.of(envVarName).forEach(executorPrototype::removeEnvVar); + return this; + } + + public JPackageCommand setEnvVar(String envVarName, String envVarValue) { + verifyMutable(); + executorPrototype.setEnvVar(envVarName, envVarValue); + return this; + } + public JPackageCommand saveConsoleOutput(boolean v) { verifyMutable(); - saveConsoleOutput = v; + executorPrototype.saveOutput(v); return this; } public JPackageCommand discardStdout(boolean v) { verifyMutable(); - discardStdout = v; + executorPrototype.discardStdout(v); return this; } public JPackageCommand discardStderr(boolean v) { verifyMutable(); - discardStderr = v; + executorPrototype.discardStderr(v); return this; } public JPackageCommand dumpOutput(boolean v) { verifyMutable(); - suppressOutput = !v; + executorPrototype.dumpOutput(v); return this; } @@ -1053,7 +1071,7 @@ public class JPackageCommand extends CommandArguments { } public String getValue(CannedFormattedString str) { - return new CannedFormattedString(str.formatter(), str.key(), str.args().stream().map(arg -> { + return new CannedFormattedString(str.formatter(), str.format(), str.args().stream().map(arg -> { if (arg instanceof CannedArgument cannedArg) { return cannedArg.value(this); } else { @@ -1085,7 +1103,7 @@ public class JPackageCommand extends CommandArguments { var messageSpecs = messageGroup.getEnumConstants(); - var expectMessageFormats = expectedMessages.stream().map(CannedFormattedString::key).toList(); + var expectMessageFormats = expectedMessages.stream().map(CannedFormattedString::format).toList(); var groupMessageFormats = Stream.of(messageSpecs) .map(CannedFormattedString.Spec::format) @@ -1129,18 +1147,16 @@ public class JPackageCommand extends CommandArguments { } Executor createExecutor() { - Executor exec = new Executor() - .saveOutput(saveConsoleOutput).dumpOutput(!suppressOutput) - .discardStdout(discardStdout).discardStderr(discardStderr) + Executor exec = executorPrototype.copy() .setDirectory(executeInDirectory) .addArguments(args); toolProviderSource.toolProvider().ifPresentOrElse(exec::setToolProvider, () -> { - exec.setExecutable(JavaTool.JPACKAGE); - if (TKit.isWindows()) { - exec.setWindowsTmpDir(System.getProperty("java.io.tmpdir")); - } - }); + exec.setExecutable(JavaTool.JPACKAGE); + if (TKit.isWindows()) { + exec.setWindowsTmpDir(System.getProperty("java.io.tmpdir")); + } + }); return exec; } @@ -2051,10 +2067,7 @@ public class JPackageCommand extends CommandArguments { } private final ToolProviderSource toolProviderSource; - private boolean saveConsoleOutput; - private boolean discardStdout; - private boolean discardStderr; - private boolean suppressOutput; + private final Executor executorPrototype; private boolean ignoreDefaultRuntime; private boolean ignoreDefaultVerbose; private boolean removeOldOutputBundle; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageStringBundle.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageStringBundle.java index 688b16a8e09..761597ac796 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageStringBundle.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageStringBundle.java @@ -27,10 +27,7 @@ import static jdk.jpackage.internal.util.function.ExceptionBox.toUnchecked; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.text.MessageFormat; import java.util.List; -import java.util.Objects; -import java.util.Optional; import java.util.function.BiFunction; import java.util.function.Function; import java.util.regex.Pattern; @@ -50,7 +47,7 @@ public enum JPackageStringBundle { throw toUnchecked(ex); } formatter = (String key, Object[] args) -> { - return new FormattedMessage(key, args).value(); + return createFormattedMessage(key, args).value(); }; } @@ -70,102 +67,21 @@ public enum JPackageStringBundle { } public Pattern cannedFormattedStringAsPattern(String key, Function formatArgMapper, Object ... args) { - var fm = new FormattedMessage(key, args); - return fm.messageFormat().map(mf -> { - return toPattern(mf, formatArgMapper, args); - }).orElseGet(() -> { - return Pattern.compile(Pattern.quote(fm.value())); - }); + return createFormattedMessage(key, args).toPattern(formatArgMapper); } public Pattern cannedFormattedStringAsPattern(String key, Object ... args) { - return cannedFormattedStringAsPattern(key, MATCH_ANY, args); + return createFormattedMessage(key, args).toPattern(); } - static Pattern toPattern(MessageFormat mf, Function formatArgMapper, Object ... args) { - Objects.requireNonNull(mf); - Objects.requireNonNull(formatArgMapper); - - var patternSb = new StringBuilder(); - var runSb = new StringBuilder(); - - var it = mf.formatToCharacterIterator(args); - while (it.getIndex() < it.getEndIndex()) { - var runBegin = it.getRunStart(); - var runEnd = it.getRunLimit(); - if (runEnd < runBegin) { - throw new IllegalStateException(); - } - - var attrs = it.getAttributes(); - if (attrs.isEmpty()) { - // Regular text run. - runSb.setLength(0); - it.setIndex(runBegin); - for (int counter = runEnd - runBegin; counter != 0; --counter) { - runSb.append(it.current()); - it.next(); - } - patternSb.append(Pattern.quote(runSb.toString())); - } else { - // Format run. - int argi = (Integer)attrs.get(MessageFormat.Field.ARGUMENT); - var arg = args[argi]; - var pattern = Objects.requireNonNull(formatArgMapper.apply(arg)); - patternSb.append(pattern.toString()); - it.setIndex(runEnd); - } - } - - return Pattern.compile(patternSb.toString()); - } - - private final class FormattedMessage { - - FormattedMessage(String key, Object[] args) { - List.of(args).forEach(Objects::requireNonNull); - - var formatter = getString(key); - - var mf = new MessageFormat(formatter); - var formatCount = mf.getFormatsByArgumentIndex().length; - if (formatCount != args.length) { - throw new IllegalArgumentException(String.format( - "Expected %d arguments for [%s] string, but given %d", formatCount, key, args.length)); - } - - if (formatCount == 0) { - this.mf = null; - value = formatter; - } else { - this.mf = mf; - value = mf.format(args); - } - } - - String value() { - return value; - } - - Optional messageFormat() { - return Optional.ofNullable(mf); - } - - private final String value; - private final MessageFormat mf; + private CannedMessageFormat createFormattedMessage(String key, Object ... args) { + return CannedMessageFormat.create( + CannedMessageFormat.defaultInvalidFormatArgumentCountExceptionSupplier(key, args.length), + getString(key), + args); } private final Class i18nClass; private final Method i18nClass_getString; private final BiFunction formatter; - - private static final Function MATCH_ANY = new Function<>() { - - @Override - public Pattern apply(Object v) { - return PATTERN; - } - - private static final Pattern PATTERN = Pattern.compile(".*"); - }; }