8288838: jpackage: file association additional arguments

Reviewed-by: asemenyuk, almatvee
This commit is contained in:
Alex Kasko 2022-07-07 16:45:35 +00:00 committed by Alexey Semenyuk
parent 95e3190d96
commit a694e9e34d
5 changed files with 185 additions and 27 deletions

View File

@ -529,7 +529,7 @@ class WixAppImageFragmentBuilder extends WixFragmentBuilder {
xml.writeStartElement("Verb");
xml.writeAttribute("Id", "open");
xml.writeAttribute("Command", "Open");
xml.writeAttribute("Argument", "\"%1\"");
xml.writeAttribute("Argument", "\"%1\" %*");
xml.writeAttribute("TargetFile", Id.File.of(fa.launcherPath));
xml.writeEndElement(); // <Verb>

View File

@ -22,9 +22,16 @@
*/
package jdk.jpackage.test;
import java.awt.Desktop;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import jdk.jpackage.internal.IOUtils;
@ -97,8 +104,147 @@ final public class FileAssociations {
});
}
Iterable<TestRun> getTestRuns() {
return Optional.ofNullable(testRuns).orElseGet(() -> {
var builder = createTestRuns()
.setCurrentInvocationType(InvocationType.DesktopOpenAssociatedFile)
.addTestRunForFilenames("test_desktop_open_file");
if (TKit.isWindows()) {
builder.setCurrentInvocationType(InvocationType.WinCommandLine)
.addTestRunForFilenames("test_cmd_line")
.setCurrentInvocationType(InvocationType.WinDesktopOpenShortcut)
.addTestRunForFilenames("test_desktop_open_shortcut");
}
return builder.testRuns;
});
}
public static TestRunsBuilder createTestRuns() {
return new TestRunsBuilder();
}
static class TestRun {
Iterable<String> getFileNames() {
return testFileNames;
}
List<String> openFiles(List<Path> testFiles) throws IOException {
// current supported invocation types work only on single files
Path testFile = testFiles.get(0);
// To test unicode arguments on Windows manually:
// 1. add the following argument ("Hello" in Bulgarian) to the
// additionalArgs list: "\u0417\u0434\u0440\u0430\u0432\u0435\u0439\u0442\u0435"
// 2. in Control Panel -> Region -> Administrative -> Language for non-Unicode programs
// change the system locale to "Bulgarian (Bulgaria)"
// 3. reboot Windows and re-run the test
switch (invocationType) {
case DesktopOpenAssociatedFile: {
TKit.trace(String.format("Use desktop to open [%s] file", testFile));
Desktop.getDesktop().open(testFile.toFile());
return List.of(testFile.toString());
}
case WinCommandLine: {
List<String> additionalArgs = List.of("foo", "bar baz", "boo");
TKit.trace(String.format("Use command line to open [%s] file", testFile));
ArrayList<String> cmdLine = new ArrayList<>(List.of("cmd", "/c", testFile.toString()));
cmdLine.addAll(additionalArgs);
Executor.of(cmdLine.toArray(new String[0])).execute();
ArrayList<String> expectedArgs = new ArrayList<>(List.of(testFile.toString()));
expectedArgs.addAll(additionalArgs);
return expectedArgs;
}
case WinDesktopOpenShortcut: {
Path testDir = testFile.getParent();
List<String> additionalArgs = List.of("foo", "bar baz", "boo");
// create a shortcut and open it with desktop
final Path createShortcutVbs = testDir.resolve("createShortcut.vbs");
final Path shortcutLnk = testDir.resolve("shortcut.lnk");
StringBuilder shortcutArgs = new StringBuilder();
for (int i = 0; i < additionalArgs.size(); i++) {
String arg = additionalArgs.get(i);
if (arg.contains(" ")) {
shortcutArgs.append(String.format("\"\"%s\"\"", arg));
} else {
shortcutArgs.append(arg);
}
if (i < additionalArgs.size() - 1) {
shortcutArgs.append(" ");
}
}
TKit.createTextFile(createShortcutVbs, List.of(
"Dim sc, shell",
"Set shell = WScript.CreateObject (\"WScript.Shell\")",
String.format("Set sc = shell.CreateShortcut (\"%s\")", shortcutLnk),
String.format("sc.TargetPath = \"\"\"%s\"\"\"", testFile),
String.format("sc.Arguments = \"%s\"", shortcutArgs.toString()),
String.format("sc.WorkingDirectory = \"\"\"%s\"\"\"", testDir),
"sc.Save()"
));
Executor.of("cscript", "/nologo", createShortcutVbs.toString()).execute();
TKit.assertFileExists(shortcutLnk);
TKit.trace(String.format("Use desktop to open [%s] file", shortcutLnk));
Desktop.getDesktop().open(shortcutLnk.toFile());
ArrayList<String> expectedArgs = new ArrayList<>(List.of(testFile.toString()));
expectedArgs.addAll(additionalArgs);
return expectedArgs;
}
default:
throw new IllegalStateException(String.format(
"Invalid invocationType: [%s]", invocationType));
}
}
private TestRun(Collection<String> testFileNames,
InvocationType invocationType) {
Objects.requireNonNull(invocationType);
if (testFileNames.size() == 0) {
throw new IllegalArgumentException("Empty test file names list");
}
if (invocationType == InvocationType.DesktopOpenAssociatedFile && testFileNames.size() != 1) {
throw new IllegalArgumentException("Only one file can be configured for opening with the desktop");
}
this.testFileNames = testFileNames;
this.invocationType = invocationType;
}
private final Collection<String> testFileNames;
private final InvocationType invocationType;
}
public static class TestRunsBuilder {
public TestRunsBuilder setCurrentInvocationType(InvocationType v) {
curInvocationType = v;
return this;
}
public TestRunsBuilder addTestRunForFilenames(String ... filenames) {
testRuns.add(new TestRun(List.of(filenames), curInvocationType));
return this;
}
public void applyTo(FileAssociations fa) {
fa.testRuns = testRuns;
}
private InvocationType curInvocationType = InvocationType.DesktopOpenAssociatedFile;
private List<TestRun> testRuns = new ArrayList<>();
}
public static enum InvocationType {
DesktopOpenAssociatedFile,
WinCommandLine,
WinDesktopOpenShortcut
}
private Path file;
final private String suffixName;
private String description;
private Path icon;
private Collection<TestRun> testRuns;
}

View File

@ -41,6 +41,7 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import jdk.jpackage.internal.IOUtils;
import jdk.jpackage.test.Functional.ThrowingConsumer;
import jdk.jpackage.test.PackageTest.PackageHandlers;
@ -471,13 +472,24 @@ public final class LinuxHelper {
"Failed to locate system .desktop files folder"));
}
private static void withTestFileAssociationsFile(FileAssociations fa,
ThrowingConsumer<Path> consumer) {
boolean iterated[] = new boolean[] { false };
PackageTest.withFileAssociationsTestRuns(fa, (testRun, testFiles) -> {
if (!iterated[0]) {
iterated[0] = true;
consumer.accept(testFiles.get(0));
}
});
}
static void addFileAssociationsVerifier(PackageTest test, FileAssociations fa) {
test.addInstallVerifier(cmd -> {
if (cmd.isPackageUnpacked("Not running file associations checks")) {
return;
}
PackageTest.withTestFileAssociationsFile(fa, testFile -> {
withTestFileAssociationsFile(fa, testFile -> {
String mimeType = queryFileMimeType(testFile);
TKit.assertEquals(fa.getMime(), mimeType, String.format(
@ -501,7 +513,7 @@ public final class LinuxHelper {
});
test.addUninstallVerifier(cmd -> {
PackageTest.withTestFileAssociationsFile(fa, testFile -> {
withTestFileAssociationsFile(fa, testFile -> {
String mimeType = queryFileMimeType(testFile);
TKit.assertNotEquals(fa.getMime(), mimeType, String.format(

View File

@ -46,6 +46,7 @@ import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import jdk.jpackage.internal.ApplicationLayout;
import jdk.jpackage.test.Functional.ThrowingBiConsumer;
import static jdk.jpackage.test.Functional.ThrowingBiConsumer.toBiConsumer;
@ -227,19 +228,26 @@ public final class PackageTest extends RunnablePackageTest {
return this;
}
static void withTestFileAssociationsFile(FileAssociations fa,
ThrowingConsumer<Path> consumer) {
final Path testFileDefaultName = Path.of("test" + fa.getSuffix());
TKit.withTempFile(testFileDefaultName, testFile -> {
if (TKit.isLinux()) {
LinuxHelper.initFileAssociationsTestFile(testFile);
}
consumer.accept(testFile);
});
static void withFileAssociationsTestRuns(FileAssociations fa,
ThrowingBiConsumer<FileAssociations.TestRun, List<Path>> consumer) {
for (var testRun : fa.getTestRuns()) {
TKit.withTempDirectory("fa-test-files", tempDir -> {
List<Path> testFiles = StreamSupport.stream(testRun.getFileNames().spliterator(), false).map(fname -> {
return tempDir.resolve(fname + fa.getSuffix()).toAbsolutePath().normalize();
}).toList();
testFiles.forEach(toConsumer(Files::createFile));
if (TKit.isLinux()) {
testFiles.forEach(LinuxHelper::initFileAssociationsTestFile);
}
consumer.accept(testRun, testFiles);
});
}
}
PackageTest addHelloAppFileAssociationsVerifier(FileAssociations fa,
String... faLauncherDefaultArgs) {
PackageTest addHelloAppFileAssociationsVerifier(FileAssociations fa) {
// Setup test app to have valid jpackage command line before
// running check of type of environment.
@ -261,22 +269,14 @@ public final class PackageTest extends RunnablePackageTest {
return;
}
withTestFileAssociationsFile(fa, testFile -> {
testFile = testFile.toAbsolutePath().normalize();
final Path appOutput = testFile.getParent()
withFileAssociationsTestRuns(fa, (testRun, testFiles) -> {
final Path appOutput = testFiles.get(0).getParent()
.resolve(HelloApp.OUTPUT_FILENAME);
Files.deleteIfExists(appOutput);
TKit.trace(String.format("Use desktop to open [%s] file",
testFile));
Desktop.getDesktop().open(testFile.toFile());
List<String> expectedArgs = testRun.openFiles(testFiles);
TKit.waitForFileCreated(appOutput, 7);
List<String> expectedArgs = new ArrayList<>(List.of(
faLauncherDefaultArgs));
expectedArgs.add(testFile.toString());
// Wait a little bit after file has been created to
// make sure there are no pending writes into it.
Thread.sleep(3000);

View File

@ -63,7 +63,7 @@ import jdk.jpackage.test.Annotations.Parameter;
* @build jdk.jpackage.test.*
* @modules jdk.jpackage/jdk.jpackage.internal
* @compile FileAssociationsTest.java
* @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main
* @run main/othervm/timeout=540 -Xmx512m jdk.jpackage.test.Main
* --jpt-run=FileAssociationsTest
*/
@ -76,7 +76,7 @@ import jdk.jpackage.test.Annotations.Parameter;
* @build jdk.jpackage.test.*
* @modules jdk.jpackage/jdk.jpackage.internal
* @compile FileAssociationsTest.java
* @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main
* @run main/othervm/timeout=540 -Xmx512m jdk.jpackage.test.Main
* --jpt-run=FileAssociationsTest.test
*/