--- old/test/jdk/tools/jpackage/share/IconTest.java 2019-12-13 13:37:32.139640000 -0500 +++ new/test/jdk/tools/jpackage/share/IconTest.java 2019-12-13 13:37:31.066262800 -0500 @@ -22,72 +22,414 @@ */ import java.io.IOException; +import java.util.*; +import java.util.stream.Stream; +import java.util.stream.Collectors; +import java.util.function.Consumer; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; -import jdk.incubator.jpackage.internal.IOUtils; -import jdk.jpackage.test.TKit; -import jdk.jpackage.test.Functional; +import jdk.jpackage.test.*; +import jdk.jpackage.test.Functional.ThrowingConsumer; +import jdk.jpackage.test.Functional.ThrowingBiConsumer; import jdk.jpackage.test.Annotations.*; -import jdk.jpackage.test.JPackageCommand; /* * @test - * @summary jpackage create image with custom icon + * @summary jpackage create image and package with custom icons for the main and additional launcher * @library ../helpers * @build jdk.jpackage.test.* * @modules jdk.incubator.jpackage/jdk.incubator.jpackage.internal * @compile IconTest.java - * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=540 -Xmx512m jdk.jpackage.test.Main * --jpt-run=IconTest */ public class IconTest { - @Test - public static void testResourceDir() throws IOException { - TKit.withTempDirectory("resources", tempDir -> { - JPackageCommand cmd = JPackageCommand.helloAppImage() - .addArguments("--resource-dir", tempDir); - Files.copy(GOLDEN_ICON, tempDir.resolve(appIconFileName(cmd)), - StandardCopyOption.REPLACE_EXISTING); + enum IconType { + /** + * Icon not specified. + */ + DefaultIcon, + + /** + * Explicit no icon. + */ + NoIcon, + + /** + * Custom icon on command line. + */ + CustomIcon, + + /** + * Custom icon in resource dir. + */ + ResourceDirIcon, + + /** + * Custom icon on command line and in resource dir. + */ + CustomWithResourceDirIcon + } + + enum BundleType { AppImage, Package } + + public IconTest(BundleType bundleType, IconType mainLauncherIconType, + IconType additionalLauncherIconType, String[] extraJPackageArgs) { + this.appImage = (bundleType == BundleType.AppImage); + this.extraJPackageArgs = extraJPackageArgs; + config = Map.of( + Launcher.Main, mainLauncherIconType, + Launcher.Additional, additionalLauncherIconType); + } + + public IconTest(BundleType bundleType, IconType mainLauncherIconType, + IconType additionalLauncherIconType) { + this.appImage = (bundleType == BundleType.AppImage); + this.extraJPackageArgs = new String[0]; + config = Map.of( + Launcher.Main, mainLauncherIconType, + Launcher.Additional, additionalLauncherIconType); + } - testIt(cmd); - }); + public IconTest(BundleType bundleType, IconType mainLauncherIconType) { + this.appImage = (bundleType == BundleType.AppImage); + this.extraJPackageArgs = new String[0]; + config = Map.of(Launcher.Main, mainLauncherIconType); + } + + @Parameters + public static Collection data() { + List data = new ArrayList<>(); + + var withLinuxShortcut = Set.of(IconType.DefaultIcon, IconType.NoIcon); + + for (var bundleType : BundleType.values()) { + if (TKit.isWindows() && bundleType == BundleType.Package) { + // On Windows icons are embedded in launcher executables in + // application image. Nothing is changed when app image is + // packed in msi/exe package bundle, so skip testing of package + // bundle. + continue; + } + for (var mainLauncherIconType : IconType.values()) { + if (mainLauncherIconType == IconType.NoIcon) { + // `No icon` setting is not applicable for the main launcher. + continue; + } + + if (TKit.isOSX()) { + // Custom icons not supported for additional launchers on Mac. + data.add(new Object[]{bundleType, mainLauncherIconType}); + continue; + } + + for (var additionalLauncherIconType : IconType.values()) { + data.add(new Object[]{bundleType, mainLauncherIconType, + additionalLauncherIconType}); + + if (TKit.isLinux() && bundleType == BundleType.Package + && withLinuxShortcut.contains(mainLauncherIconType) + && withLinuxShortcut.contains( + additionalLauncherIconType)) { + data.add(new Object[]{bundleType, mainLauncherIconType, + additionalLauncherIconType, new String[]{ + "--linux-shortcut"}}); + } + } + } + } + return data; } @Test - @Parameter("true") - @Parameter("false") - public static void testParameter(boolean relativePath) throws IOException { - final Path iconPath; - if (relativePath) { - iconPath = TKit.createRelativePathCopy(GOLDEN_ICON); + public void test() throws IOException { + if (appImage) { + JPackageCommand cmd = initAppImageTest(); + var result = cmd.executeAndAssertImageCreated(); + ThrowingConsumer.toConsumer(createInstallVerifier()).accept(cmd); + ThrowingBiConsumer.toBiConsumer(createBundleVerifier()).accept(cmd, result); } else { - iconPath = GOLDEN_ICON; + PackageTest test = initPackageTest(); + test.addInstallVerifier(createInstallVerifier()); + test.addBundleVerifier(createBundleVerifier()); + + test.addBundleDesktopIntegrationVerifier(config.values().stream() + .anyMatch(this::isWithDesktopIntegration)); + + test.run(PackageTest.Action.CREATE_AND_UNPACK); + } + } + + boolean isWithDesktopIntegration(IconType iconType) { + if (appImage) { + return false; } + boolean withDesktopFile = !Set.of( + IconType.NoIcon, + IconType.DefaultIcon).contains(iconType); + withDesktopFile |= List.of(extraJPackageArgs).contains("--linux-shortcut"); + return withDesktopFile; + } - testIt(JPackageCommand.helloAppImage().addArguments("--icon", iconPath)); + private ThrowingBiConsumer createBundleVerifier() { + return (cmd, result) -> { + var verifier = createConsoleOutputVerifier(cmd.name(), config.get( + Launcher.Main), null); + if (verifier != null) { + verifier.apply(result.getOutput().stream()); + } + + if (config.containsKey(Launcher.Additional)) { + verifier = createConsoleOutputVerifier( + Launcher.Additional.launcherName, config.get( + Launcher.Additional), config.get(Launcher.Main)); + if (verifier != null) { + verifier.apply(result.getOutput().stream()); + } + } + }; } - private static String appIconFileName(JPackageCommand cmd) { - return IOUtils.replaceSuffix(cmd.appLauncherPath().getFileName(), - TKit.ICON_SUFFIX).toString(); + private TKit.TextStreamVerifier createConsoleOutputVerifier( + String launcherName, IconType iconType, IconType mainIconType) { + if (iconType == IconType.DefaultIcon && mainIconType != null) { + iconType = mainIconType; + } + return createConsoleOutputVerifier(launcherName, iconType); + } + + private static TKit.TextStreamVerifier createConsoleOutputVerifier( + String launcherName, IconType iconType) { + String lookupString = null; + switch (iconType) { + case DefaultIcon: + lookupString = String.format( + "Using default package resource %s [icon] (add %s%s to the resource-dir to customize)", + LauncherIconVerifier.getDefaultIcon().getFileName(), + launcherName, TKit.ICON_SUFFIX); + break; + + case ResourceDirIcon: + lookupString = String.format( + "Using custom package resource [icon] (loaded from %s%s)", + launcherName, TKit.ICON_SUFFIX); + break; + + case CustomIcon: + case CustomWithResourceDirIcon: + lookupString = "Using custom package resource [icon] (loaded from file"; + break; + + default: + return null; + } + + return TKit.assertTextStream(lookupString); + } + + private ThrowingConsumer createInstallVerifier() { + LauncherIconVerifier verifier = new LauncherIconVerifier(); + switch (config.get(Launcher.Main)) { + case NoIcon: + verifier.setExpectedIcon(null); + break; + + case DefaultIcon: + verifier.setExpectedDefaultIcon(); + break; + + case CustomIcon: + verifier.setExpectedIcon(Launcher.Main.cmdlineIcon); + break; + + case ResourceDirIcon: + verifier.setExpectedIcon(Launcher.Main.resourceDirIcon); + break; + + case CustomWithResourceDirIcon: + verifier.setExpectedIcon(Launcher.Main2.cmdlineIcon); + break; + } + + return cmd -> { + verifier.applyTo(cmd); + if (TKit.isLinux() && !cmd.isImagePackageType()) { + Path desktopFile = LinuxHelper.getDesktopFile(cmd); + if (isWithDesktopIntegration(config.get(Launcher.Main))) { + TKit.assertFileExists(desktopFile); + } else { + TKit.assertPathExists(desktopFile, false); + } + } + }; } - private static void testIt(JPackageCommand cmd) throws IOException { - cmd.executeAndAssertHelloAppImageCreated(); + private void initTest(JPackageCommand cmd, PackageTest test) { + config.entrySet().forEach(ThrowingConsumer.toConsumer(entry -> { + initTest(entry.getKey(), entry.getValue(), cmd, test); + })); + + ThrowingConsumer initializer = testCmd -> { + testCmd.saveConsoleOutput(true); + testCmd.setFakeRuntime(); + testCmd.addArguments(extraJPackageArgs); + }; - Path iconPath = cmd.appLayout().destktopIntegrationDirectory().resolve( - appIconFileName(cmd)); + if (test != null) { + test.addInitializer(initializer); + } else { + ThrowingConsumer.toConsumer(initializer).accept(cmd); + } + } + + private static void initTest(Launcher cfg, IconType iconType, + JPackageCommand cmd, PackageTest test) throws IOException { + Consumer addLauncher = v -> { + if (test != null) { + v.applyTo(test); + } else { + v.applyTo(cmd); + } + }; + + switch (iconType) { + case DefaultIcon: + if (cfg.launcherName != null) { + addLauncher.accept(new AdditionalLauncher(cfg.launcherName)); + } + break; + + case NoIcon: + if (cfg.launcherName != null) { + addLauncher.accept( + new AdditionalLauncher(cfg.launcherName).setNoIcon()); + } + break; + + case CustomIcon: + if (test != null) { + addCustomIcon(null, test, cfg.launcherName, cfg.cmdlineIcon); + } else { + addCustomIcon(cmd, null, cfg.launcherName, cfg.cmdlineIcon); + } + break; + + case ResourceDirIcon: + if (Launcher.PRIMARY.contains(cfg) && cfg.launcherName != null) { + addLauncher.accept(new AdditionalLauncher(cfg.launcherName)); + } + if (test != null) { + test.addInitializer(testCmd -> { + addResourceDirIcon(testCmd, cfg.launcherName, + cfg.resourceDirIcon); + }); + } else { + addResourceDirIcon(cmd, cfg.launcherName, cfg.resourceDirIcon); + } + break; + + case CustomWithResourceDirIcon: + switch (cfg) { + case Main: + initTest(Launcher.Main2, IconType.CustomIcon, cmd, test); + initTest(Launcher.Main2, IconType.ResourceDirIcon, cmd, test); + break; + + case Additional: + initTest(Launcher.Additional2, IconType.CustomIcon, cmd, test); + initTest(Launcher.Additional2, IconType.ResourceDirIcon, cmd, test); + break; + + default: + throw new IllegalArgumentException(); + } + break; + } + } + + private JPackageCommand initAppImageTest() { + JPackageCommand cmd = JPackageCommand.helloAppImage(); + initTest(cmd, null); + return cmd; + } + + private PackageTest initPackageTest() { + PackageTest test = new PackageTest().configureHelloApp(); + initTest(null, test); + return test; + } + + private static void addResourceDirIcon(JPackageCommand cmd, + String launcherName, Path iconPath) throws IOException { + Path resourceDir = cmd.getArgumentValue("--resource-dir", () -> null, + Path::of); + if (resourceDir == null) { + resourceDir = TKit.createTempDirectory("resources"); + cmd.addArguments("--resource-dir", resourceDir); + } + + String dstIconFileName = Optional.ofNullable(launcherName).orElseGet( + () -> cmd.name()) + TKit.ICON_SUFFIX; + + TKit.trace(String.format("Resource file: [%s] <- [%s]", + resourceDir.resolve(dstIconFileName), iconPath)); + Files.copy(iconPath, resourceDir.resolve(dstIconFileName), + StandardCopyOption.REPLACE_EXISTING); + } + + private static void addCustomIcon(JPackageCommand cmd, PackageTest test, + String launcherName, Path iconPath) throws IOException { + + if (launcherName != null) { + AdditionalLauncher al = new AdditionalLauncher(launcherName).setIcon( + iconPath); + if (test != null) { + al.applyTo(test); + } else { + al.applyTo(cmd); + } + } else if (test != null) { + test.addInitializer(testCmd -> { + testCmd.addArguments("--icon", iconPath); + }); + } else { + cmd.addArguments("--icon", iconPath); + } + } + + private enum Launcher { + Main(null, ICONS[0], ICONS[1]), + Main2(null, ICONS[1], ICONS[0]), + Additional("x", ICONS[2], ICONS[3]), + Additional2("x", ICONS[3], ICONS[2]); + + Launcher(String name, Path cmdlineIcon, Path resourceDirIcon) { + this.launcherName = name; + this.cmdlineIcon = cmdlineIcon; + this.resourceDirIcon = resourceDirIcon; + } + + private final String launcherName; + private final Path cmdlineIcon; + private final Path resourceDirIcon; + + private final static Set PRIMARY = Set.of(Main, Additional); + } - TKit.assertFileExists(iconPath); - TKit.assertTrue(-1 == Files.mismatch(GOLDEN_ICON, iconPath), - String.format( - "Check application icon file [%s] is a copy of source icon file [%s]", - iconPath, GOLDEN_ICON)); + private final boolean appImage; + private final Map config; + private final String[] extraJPackageArgs; + + private static Path iconPath(String name) { + return TKit.TEST_SRC_ROOT.resolve(Path.of("resources", name + + TKit.ICON_SUFFIX)); } - private final static Path GOLDEN_ICON = TKit.TEST_SRC_ROOT.resolve(Path.of( - "resources", "icon" + TKit.ICON_SUFFIX)); + private final static Path[] ICONS = Stream.of("icon", "icon2", "icon3", + "icon4") + .map(IconTest::iconPath) + .collect(Collectors.toList()).toArray(Path[]::new); }