mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-29 00:02:34 +00:00
8383168: jpackage: enhance capabilities of the test lib for testing jpackage console output
Reviewed-by: almatvee
This commit is contained in:
parent
38a6f6b150
commit
5ddb0fd108
@ -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<String, Object[], String> {
|
||||
MESSAGE_FORMAT {
|
||||
@Override
|
||||
|
||||
@ -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<TestSpec> test_toPattern() {
|
||||
|
||||
var testCases = new ArrayList<TestSpec>();
|
||||
|
||||
testCases.addAll(List.of(
|
||||
TestSpec.create("", Pattern.compile(Pattern.quote(""))),
|
||||
TestSpec.create("", "foo")
|
||||
));
|
||||
|
||||
for (List<Object> args : List.of(List.<Object>of())) {
|
||||
Stream.of(
|
||||
"Stop."
|
||||
).map(formatter -> {
|
||||
return new TestSpec(formatter, args, Optional.of(Pattern.compile(Pattern.quote(formatter))));
|
||||
}).forEach(testCases::add);
|
||||
}
|
||||
|
||||
for (List<Object> args : List.of(List.<Object>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<Object> args, Optional<Pattern> expectedPattern) {
|
||||
TestSpec {
|
||||
Objects.requireNonNull(format);
|
||||
Objects.requireNonNull(args);
|
||||
Objects.requireNonNull(expectedPattern);
|
||||
}
|
||||
|
||||
Function<Object, Pattern> 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<Object, Pattern> DEFAULT_FORMAT_ARG_MAPPER = _ -> {
|
||||
return DEFAULT_FORMAT_ARG_PATTERN;
|
||||
};
|
||||
|
||||
private static final Function<Object, Pattern> UNREACHABLE_FORMAT_ARG_MAPPER = _ -> {
|
||||
throw new AssertionError();
|
||||
};
|
||||
}
|
||||
@ -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<CannedFormattedString> 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<TestSpec> test_toPattern() {
|
||||
|
||||
var testCases = new ArrayList<TestSpec>();
|
||||
|
||||
testCases.addAll(List.of(
|
||||
TestSpec.create("", Pattern.compile("")),
|
||||
TestSpec.create("", Pattern.compile(""), "foo")
|
||||
));
|
||||
|
||||
for (List<Object> args : List.of(List.<Object>of(), List.<Object>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<Object> args, Pattern expectedPattern) {
|
||||
TestSpec {
|
||||
Objects.requireNonNull(formatter);
|
||||
Objects.requireNonNull(args);
|
||||
Objects.requireNonNull(expectedPattern);
|
||||
}
|
||||
|
||||
Function<Object, Pattern> 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<Object, Pattern> DEFAULT_FORMAT_ARG_MAPPER = _ -> {
|
||||
|
||||
@ -30,22 +30,22 @@ import java.util.function.UnaryOperator;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public record CannedFormattedString(BiFunction<String, Object[], String> formatter, String key, List<Object> args) implements CannedArgument {
|
||||
public record CannedFormattedString(BiFunction<String, Object[], String> formatter, String format, List<Object> args) implements CannedArgument {
|
||||
|
||||
public CannedFormattedString mapArgs(UnaryOperator<Object> 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<String, Object[], String> 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<String, Object[], String> formatt
|
||||
}
|
||||
}
|
||||
|
||||
public static CannedFormattedString createFromMessageFormat(String messageFormatStr, Object... args) {
|
||||
return new CannedFormattedString(MESSAGE_FORMAT_FORMATTER, messageFormatStr, List.of(args));
|
||||
}
|
||||
|
||||
private record AddPrefixFormatter(BiFunction<String, Object[], String> formatter) implements BiFunction<String, Object[], String> {
|
||||
|
||||
AddPrefixFormatter {
|
||||
@ -97,4 +101,8 @@ public record CannedFormattedString(BiFunction<String, Object[], String> formatt
|
||||
return formatter.apply(format, new Object[] {str});
|
||||
}
|
||||
}
|
||||
|
||||
private static final BiFunction<String, Object[], String> MESSAGE_FORMAT_FORMATTER = (String format, Object[] args) -> {
|
||||
return CannedMessageFormat.create(format, args).value();
|
||||
};
|
||||
}
|
||||
|
||||
@ -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> messageFormat() {
|
||||
return messageFormat;
|
||||
}
|
||||
|
||||
public Pattern toPattern(Function<Object, Pattern> 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<Integer, RuntimeException> 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<Integer, RuntimeException> 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<Object, Pattern> 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> messageFormat;
|
||||
|
||||
private static final Function<Object, Pattern> MATCH_ANY = new Function<>() {
|
||||
|
||||
@Override
|
||||
public Pattern apply(Object v) {
|
||||
return PATTERN;
|
||||
}
|
||||
|
||||
private static final Pattern PATTERN = Pattern.compile(".*");
|
||||
};
|
||||
}
|
||||
@ -63,7 +63,25 @@ public final class Executor extends CommandArguments<Executor> {
|
||||
}
|
||||
|
||||
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<Executor> {
|
||||
|
||||
private ToolProvider toolProvider;
|
||||
private Path executable;
|
||||
private final CommandOutputControl commandOutputControl = new CommandOutputControl();
|
||||
private final CommandOutputControl commandOutputControl;
|
||||
private Path directory;
|
||||
private Set<String> removeEnvVars = new HashSet<>();
|
||||
private Map<String, String> setEnvVars = new HashMap<>();
|
||||
private String winTmpDir = null;
|
||||
private final Set<String> removeEnvVars;
|
||||
private final Map<String, String> setEnvVars;
|
||||
private String winTmpDir;
|
||||
}
|
||||
|
||||
@ -80,6 +80,7 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
|
||||
@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<JPackageCommand> {
|
||||
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<JPackageCommand> {
|
||||
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<JPackageCommand> {
|
||||
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<JPackageCommand> {
|
||||
}
|
||||
|
||||
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<JPackageCommand> {
|
||||
|
||||
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<JPackageCommand> {
|
||||
}
|
||||
|
||||
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<JPackageCommand> {
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -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<Object, Pattern> 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<Object, Pattern> 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> 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<String, Object[], String> formatter;
|
||||
|
||||
private static final Function<Object, Pattern> MATCH_ANY = new Function<>() {
|
||||
|
||||
@Override
|
||||
public Pattern apply(Object v) {
|
||||
return PATTERN;
|
||||
}
|
||||
|
||||
private static final Pattern PATTERN = Pattern.compile(".*");
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user