diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/util/PListWriter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PListWriter.java
similarity index 90%
rename from src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/util/PListWriter.java
rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PListWriter.java
index 381faee3802e3..a5eb150a1d1ae 100644
--- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/util/PListWriter.java
+++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/PListWriter.java
@@ -90,7 +90,13 @@ public static void writeArray(XMLStreamWriter xml, XmlConsumer content)
public static void writePList(XMLStreamWriter xml, XmlConsumer content)
throws XMLStreamException, IOException {
- xml.writeDTD("plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"https://www.apple.com/DTDs/PropertyList-1.0.dtd\"");
+ try {
+ xml.writeDTD("");
+ } catch (UnsupportedOperationException ex) {
+ // Silently ignore.
+ // This would normally be thrown by com.sun.xml.internal.stream.writers.XMLDOMWriterImpl.writeDTD()
+ // or (presumably) any other DOM tree-backed XML stream writer implementation.
+ }
xml.writeStartElement("plist");
xml.writeAttribute("version", "1.0");
content.accept(xml);
diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java
index c78101c124504..549044862d875 100644
--- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java
+++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/XmlUtils.java
@@ -24,6 +24,8 @@
*/
package jdk.jpackage.internal.util;
+import static jdk.jpackage.internal.util.function.ExceptionBox.rethrowUnchecked;
+
import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Proxy;
@@ -43,6 +45,7 @@
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.stax.StAXResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
@@ -63,8 +66,7 @@ public static XmlConsumer toXmlConsumer(XmlConsumerNoArg xmlConsumer) {
return xml -> xmlConsumer.accept();
}
- public static void createXml(Path dstFile, XmlConsumer xmlConsumer) throws
- IOException {
+ public static void createXml(Path dstFile, XmlConsumer xmlConsumer) throws IOException {
XMLOutputFactory xmlFactory = XMLOutputFactory.newInstance();
Files.createDirectories(dstFile.getParent());
try (Writer w = Files.newBufferedWriter(dstFile)) {
@@ -78,9 +80,28 @@ public static void createXml(Path dstFile, XmlConsumer xmlConsumer) throws
xml.flush();
xml.close();
} catch (XMLStreamException ex) {
- throw new IOException(ex);
- } catch (IOException ex) {
- throw ex;
+ throw rethrowUnchecked(ex);
+ }
+ }
+
+ public static void createXml(Node root, XmlConsumer xmlConsumer) throws IOException {
+ createXml(new DOMResult(root), xmlConsumer);
+ }
+
+ public static DOMResult createXml(XmlConsumer xmlConsumer) throws IOException {
+ var dom = new DOMResult(initDocumentBuilder().newDocument());
+ createXml(dom, xmlConsumer);
+ return dom;
+ }
+
+ public static void createXml(DOMResult dom, XmlConsumer xmlConsumer) throws IOException {
+ try {
+ var xml = XMLOutputFactory.newInstance().createXMLStreamWriter(dom);
+ xmlConsumer.accept(xml);
+ xml.flush();
+ xml.close();
+ } catch (XMLStreamException ex) {
+ throw rethrowUnchecked(ex);
}
}
diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/MacHelperTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/MacHelperTest.java
new file mode 100644
index 0000000000000..5d14f021eafc9
--- /dev/null
+++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/MacHelperTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2025, 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 java.util.Map.entry;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.UncheckedIOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import jdk.jpackage.internal.util.PListReader;
+import jdk.jpackage.internal.util.XmlUtils;
+import org.junit.jupiter.api.Test;
+import org.w3c.dom.Node;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+public class MacHelperTest {
+
+ @Test
+ public void test_flatMapPList() {
+ var props = MacHelper.flatMapPList(new PListReader(createXml(
+ "AppName",
+ "Hello",
+ "AppVersion",
+ "1.0",
+ "UserData",
+ "",
+ " Foo",
+ " ",
+ " Str",
+ " ",
+ " Another Str",
+ " ",
+ " ",
+ " ",
+ " ",
+ "",
+ "Checksum",
+ "7841ff0076cdde93bdca02cfd332748c40620ce4",
+ "Plugins",
+ "",
+ " ",
+ " PluginName",
+ " Foo",
+ " Priority",
+ " 13",
+ " History",
+ " ",
+ " New File",
+ " Another New File",
+ " ",
+ " ",
+ " ",
+ " PluginName",
+ " Bar",
+ " Priority",
+ " 23",
+ " History",
+ " ",
+ " ",
+ " ",
+ ""
+ )));
+
+ assertEquals(Map.ofEntries(
+ entry("/AppName", "Hello"),
+ entry("/AppVersion", "1.0"),
+ entry("/UserData/Foo[0]", "Str"),
+ entry("/UserData/Foo[1][0]", "Another Str"),
+ entry("/UserData/Foo[1][1]", "true"),
+ entry("/UserData/Foo[1][2]", "false"),
+ entry("/Checksum", "7841ff0076cdde93bdca02cfd332748c40620ce4"),
+ entry("/Plugins[0]/PluginName", "Foo"),
+ entry("/Plugins[0]/Priority", "13"),
+ entry("/Plugins[0]/History[0]", "New File"),
+ entry("/Plugins[0]/History[1]", "Another New File"),
+ entry("/Plugins[1]/PluginName", "Bar"),
+ entry("/Plugins[1]/Priority", "23"),
+ entry("/Plugins[1]/History[]", ""),
+ entry("/Plugins[2]{}", "")
+ ), props);
+ }
+
+ private static String createPListXml(String ...xml) {
+ final List content = new ArrayList<>();
+ content.add("");
+ content.add("");
+ content.add("");
+ content.addAll(List.of(xml));
+ content.add("");
+ content.add("");
+ return String.join("", content.toArray(String[]::new));
+ }
+
+ private static Node createXml(String ...xml) {
+ try {
+ return XmlUtils.initDocumentBuilder().parse(new InputSource(new StringReader(createPListXml(xml))));
+ } catch (IOException ex) {
+ throw new UncheckedIOException(ex);
+ } catch (SAXException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+}
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 6aacc261fb64c..8984450f54be2 100644
--- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java
+++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java
@@ -313,7 +313,7 @@ public JPackageCommand setFakeRuntime() {
// an error by PackageTest.
createBulkFile.accept(fakeRuntimeDir.resolve(Path.of("bin", "bulk")));
- cmd.addArguments("--runtime-image", fakeRuntimeDir);
+ cmd.setArgumentValue("--runtime-image", fakeRuntimeDir);
});
return this;
@@ -363,6 +363,29 @@ public static JPackageCommand helloAppImage(JavaAppDesc javaAppDesc) {
return cmd;
}
+ public static Path createInputRuntimeImage() throws IOException {
+
+ final Path runtimeImageDir;
+
+ if (JPackageCommand.DEFAULT_RUNTIME_IMAGE != null) {
+ runtimeImageDir = JPackageCommand.DEFAULT_RUNTIME_IMAGE;
+ } else {
+ runtimeImageDir = TKit.createTempDirectory("runtime-image").resolve("data");
+
+ new Executor().setToolProvider(JavaTool.JLINK)
+ .dumpOutput()
+ .addArguments(
+ "--output", runtimeImageDir.toString(),
+ "--add-modules", "java.desktop",
+ "--strip-debug",
+ "--no-header-files",
+ "--no-man-pages")
+ .execute();
+ }
+
+ return runtimeImageDir;
+ }
+
public JPackageCommand setPackageType(PackageType type) {
verifyMutable();
type.applyTo(this);
diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java
index 37e395e1a3eca..1b18b0512ae39 100644
--- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java
+++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java
@@ -23,22 +23,41 @@
package jdk.jpackage.test;
import static java.util.stream.Collectors.toSet;
+import static jdk.jpackage.internal.util.PListWriter.writeArray;
+import static jdk.jpackage.internal.util.PListWriter.writeBoolean;
+import static jdk.jpackage.internal.util.PListWriter.writeBooleanOptional;
+import static jdk.jpackage.internal.util.PListWriter.writeDict;
+import static jdk.jpackage.internal.util.PListWriter.writeKey;
+import static jdk.jpackage.internal.util.PListWriter.writeString;
+import static jdk.jpackage.internal.util.PListWriter.writeStringArray;
+import static jdk.jpackage.internal.util.PListWriter.writeStringOptional;
+import static jdk.jpackage.internal.util.XmlUtils.toXmlConsumer;
+import static jdk.jpackage.internal.util.function.ThrowingRunnable.toRunnable;
import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.lang.constant.ClassDesc;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;
+import java.util.Properties;
import java.util.Set;
+import java.util.function.BiFunction;
+import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import javax.xml.stream.XMLStreamWriter;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import jdk.jpackage.internal.RetryExecutor;
@@ -160,6 +179,52 @@ public static PListReader readPList(Stream lines) {
.collect(Collectors.joining()).getBytes(StandardCharsets.UTF_8))).get();
}
+ public static Map flatMapPList(PListReader plistReader) {
+ return Collections.unmodifiableMap(expandPListDist(new HashMap<>(), "", plistReader.toMap(true)));
+ }
+
+ private static Map expandPListDist(Map accumulator, String root, Map plistDict) {
+ Objects.requireNonNull(accumulator);
+ Objects.requireNonNull(plistDict);
+ Objects.requireNonNull(root);
+ for (var e : plistDict.entrySet()) {
+ collectPListProperty(accumulator, root + "/" + e.getKey(), e.getValue());
+ }
+ return accumulator;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static void collectPListProperty(Map accumulator, String key, Object value) {
+ Objects.requireNonNull(accumulator);
+ Objects.requireNonNull(key);
+ Objects.requireNonNull(value);
+ switch (value) {
+ case PListReader.Raw raw -> {
+ accumulator.put(key, raw.value());
+ }
+ case List> array -> {
+ if (array.isEmpty()) {
+ accumulator.put(key + "[]", "");
+ } else {
+ for (int i = 0; i != array.size(); i++) {
+ collectPListProperty(accumulator, String.format("%s[%d]", key, i), array.get(i));
+ }
+ }
+ }
+ case Map, ?> map -> {
+ if (map.isEmpty()) {
+ accumulator.put(key + "{}", "");
+ } else {
+ expandPListDist(accumulator, key, (Map)map);
+ }
+ }
+ default -> {
+ throw new IllegalArgumentException(String.format(
+ "Unexpected value type [%s] of property [%s]", value.getClass(), key));
+ }
+ }
+ }
+
public static boolean signPredefinedAppImage(JPackageCommand cmd) {
Objects.requireNonNull(cmd);
if (!TKit.isOSX()) {
@@ -186,6 +251,83 @@ public static boolean appImageSigned(JPackageCommand cmd) {
return (cmd.hasArgument("--mac-signing-key-user-name") || cmd.hasArgument("--mac-app-image-sign-identity"));
}
+ public static void writeFaPListFragment(JPackageCommand cmd, XMLStreamWriter xml) {
+ toRunnable(() -> {
+ var allProps = Stream.of(cmd.getAllArgumentValues("--file-associations")).map(Path::of).map(propFile -> {
+ try (var propFileReader = Files.newBufferedReader(propFile)) {
+ var props = new Properties();
+ props.load(propFileReader);
+ return props;
+ } catch (IOException ex) {
+ throw new UncheckedIOException(ex);
+ }
+ }).toList();
+
+ if (!allProps.isEmpty()) {
+ var bundleId = getPackageId(cmd);
+
+ Function contentType = fa -> {
+ return String.format("%s.%s", bundleId, Objects.requireNonNull(fa.getProperty("extension")));
+ };
+
+ Function> icon = fa -> {
+ return Optional.ofNullable(fa.getProperty("icon")).map(Path::of).map(Path::getFileName).map(Path::toString);
+ };
+
+ BiFunction> asBoolean = (fa, key) -> {
+ return Optional.ofNullable(fa.getProperty(key)).map(Boolean::parseBoolean);
+ };
+
+ BiFunction> asList = (fa, key) -> {
+ return Optional.ofNullable(fa.getProperty(key)).map(str -> {
+ return List.of(str.split("[ ,]+"));
+ }).orElseGet(List::of);
+ };
+
+ writeKey(xml, "CFBundleDocumentTypes");
+ writeArray(xml, toXmlConsumer(() -> {
+ for (var fa : allProps) {
+ writeDict(xml, toXmlConsumer(() -> {
+ writeStringArray(xml, "LSItemContentTypes", List.of(contentType.apply(fa)));
+ writeStringOptional(xml, "CFBundleTypeName", Optional.ofNullable(fa.getProperty("description")));
+ writeString(xml, "LSHandlerRank", Optional.ofNullable(fa.getProperty("mac.LSHandlerRank")).orElse("Owner"));
+ writeString(xml, "CFBundleTypeRole", Optional.ofNullable(fa.getProperty("mac.CFBundleTypeRole")).orElse("Editor"));
+ writeStringOptional(xml, "NSPersistentStoreTypeKey", Optional.ofNullable(fa.getProperty("mac.NSPersistentStoreTypeKey")));
+ writeStringOptional(xml, "NSDocumentClass", Optional.ofNullable(fa.getProperty("mac.NSDocumentClass")));
+ writeBoolean(xml, "LSIsAppleDefaultForType", true);
+ writeBooleanOptional(xml, "LSTypeIsPackage", asBoolean.apply(fa, "mac.LSTypeIsPackage"));
+ writeBooleanOptional(xml, "LSSupportsOpeningDocumentsInPlace", asBoolean.apply(fa, "mac.LSSupportsOpeningDocumentsInPlace"));
+ writeBooleanOptional(xml, "UISupportsDocumentBrowser", asBoolean.apply(fa, "mac.UISupportsDocumentBrowser"));
+ writeStringOptional(xml, "CFBundleTypeIconFile", icon.apply(fa));
+ }));
+ }
+ }));
+
+ writeKey(xml, "UTExportedTypeDeclarations");
+ writeArray(xml, toXmlConsumer(() -> {
+ for (var fa : allProps) {
+ writeDict(xml, toXmlConsumer(() -> {
+ writeString(xml, "UTTypeIdentifier", contentType.apply(fa));
+ writeStringOptional(xml, "UTTypeDescription", Optional.ofNullable(fa.getProperty("description")));
+ if (fa.containsKey("mac.UTTypeConformsTo")) {
+ writeStringArray(xml, "UTTypeConformsTo", asList.apply(fa, "mac.UTTypeConformsTo"));
+ } else {
+ writeStringArray(xml, "UTTypeConformsTo", List.of("public.data"));
+ }
+ writeStringOptional(xml, "UTTypeIconFile", icon.apply(fa));
+ writeKey(xml, "UTTypeTagSpecification");
+ writeDict(xml, toXmlConsumer(() -> {
+ writeStringArray(xml, "public.filename-extension", List.of(fa.getProperty("extension")));
+ writeStringArray(xml, "public.mime-type", List.of(fa.getProperty("mime-type")));
+ writeStringArray(xml, "NSExportableTypes", asList.apply(fa, "mac.NSExportableTypes"));
+ }));
+ }));
+ }
+ }));
+ }
+ }).run();
+ }
+
static PackageHandlers createDmgPackageHandlers() {
return new PackageHandlers(MacHelper::installDmg, MacHelper::uninstallDmg, MacHelper::unpackDmg);
}
@@ -375,7 +517,12 @@ private static String getPackageName(JPackageCommand cmd) {
private static String getPackageId(JPackageCommand cmd) {
return cmd.getArgumentValue("--mac-package-identifier", () -> {
return cmd.getArgumentValue("--main-class", cmd::name, className -> {
- return JavaAppDesc.parse(className).packageName();
+ var packageName = ClassDesc.of(className).packageName();
+ if (packageName.isEmpty()) {
+ return className;
+ } else {
+ return packageName;
+ }
});
});
}
diff --git a/test/jdk/tools/jpackage/macosx/CustomInfoPListTest.java b/test/jdk/tools/jpackage/macosx/CustomInfoPListTest.java
new file mode 100644
index 0000000000000..f8e606d77e8a0
--- /dev/null
+++ b/test/jdk/tools/jpackage/macosx/CustomInfoPListTest.java
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2025, 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.
+ */
+
+import static java.util.Map.entry;
+import static jdk.jpackage.internal.util.PListWriter.writeDict;
+import static jdk.jpackage.internal.util.PListWriter.writePList;
+import static jdk.jpackage.internal.util.PListWriter.writeString;
+import static jdk.jpackage.internal.util.XmlUtils.createXml;
+import static jdk.jpackage.internal.util.XmlUtils.toXmlConsumer;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import jdk.jpackage.internal.util.PListReader;
+import jdk.jpackage.internal.util.function.ThrowingBiConsumer;
+import jdk.jpackage.internal.util.function.ThrowingConsumer;
+import jdk.jpackage.test.Annotations.ParameterSupplier;
+import jdk.jpackage.test.Annotations.Test;
+import jdk.jpackage.test.JPackageCommand;
+import jdk.jpackage.test.JPackageStringBundle;
+import jdk.jpackage.test.MacHelper;
+import jdk.jpackage.test.PackageTest;
+import jdk.jpackage.test.PackageType;
+import jdk.jpackage.test.RunnablePackageTest.Action;
+import jdk.jpackage.test.TKit;
+
+/**
+ * Test --resource-dir with custom "Info.plist" for the top-level bundle
+ * and "Runtime-Info.plist" for the embedded runtime bundle
+ */
+
+/*
+ * @test
+ * @summary jpackage with --type image --resource-dir "Info.plist" and "Runtime-Info.plist"
+ * @library /test/jdk/tools/jpackage/helpers
+ * @key jpackagePlatformPackage
+ * @build jdk.jpackage.test.*
+ * @build CustomInfoPListTest
+ * @requires (os.family == "mac")
+ * @requires (jpackage.test.SQETest == null)
+ * @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main
+ * --jpt-run=CustomInfoPListTest
+ */
+public class CustomInfoPListTest {
+
+ @Test
+ @ParameterSupplier("customPLists")
+ public void testAppImage(TestConfig cfg) throws Throwable {
+ var cmd = cfg.init(JPackageCommand.helloAppImage());
+ var verifier = cfg.createPListFilesVerifier(cmd.executePrerequisiteActions());
+ cmd.executeAndAssertHelloAppImageCreated();
+ verifier.accept(cmd);
+ }
+
+ @Test
+ @ParameterSupplier("customPLists")
+ public void testNativePackage(TestConfig cfg) {
+ List> verifier = new ArrayList<>();
+ new PackageTest().configureHelloApp().addInitializer(cmd -> {
+ cfg.init(cmd.setFakeRuntime());
+ }).addRunOnceInitializer(() -> {
+ verifier.add(cfg.createPListFilesVerifier(JPackageCommand.helloAppImage().executePrerequisiteActions()));
+ }).addInstallVerifier(cmd -> {
+ verifier.get(0).accept(cmd);
+ }).run(Action.CREATE_AND_UNPACK);
+ }
+
+ @Test
+ public void testRuntime() {
+ final Path runtimeImage[] = new Path[1];
+
+ var cfg = new TestConfig(Set.of(CustomPListType.RUNTIME));
+
+ new PackageTest().addRunOnceInitializer(() -> {
+ runtimeImage[0] = JPackageCommand.createInputRuntimeImage();
+ }).addInitializer(cmd -> {
+ cmd.ignoreDefaultRuntime(true)
+ .removeArgumentWithValue("--input")
+ .setArgumentValue("--runtime-image", runtimeImage[0]);
+ cfg.init(cmd);
+ }).addInstallVerifier(cmd -> {
+ cfg.createPListFilesVerifier(cmd).accept(cmd);
+ }).run(Action.CREATE_AND_UNPACK);
+ }
+
+ public static Collection