1 /*
   2  * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import java.io.IOException;
  25 import java.nio.file.Path;
  26 import jdk.jpackage.test.TKit;
  27 import jdk.jpackage.test.PackageTest;
  28 import jdk.jpackage.test.PackageType;
  29 import jdk.jpackage.test.Annotations.Test;
  30 import jdk.jpackage.test.Annotations.Parameters;
  31 import java.util.List;
  32 import java.util.function.Predicate;
  33 import java.util.stream.Stream;
  34 import java.util.stream.Collectors;
  35 import jdk.jpackage.test.Executor;
  36 
  37 /*
  38  * @test
  39  * @summary Custom l10n of msi installers in jpackage
  40  * @library ../helpers
  41  * @key jpackagePlatformPackage
  42  * @requires (jpackage.test.SQETest == null)
  43  * @build jdk.jpackage.test.*
  44  * @requires (os.family == "windows")
  45  * @modules jdk.incubator.jpackage/jdk.incubator.jpackage.internal
  46  * @compile WinL10nTest.java
  47  * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main
  48  *  --jpt-run=WinL10nTest
  49  */
  50 
  51 public class WinL10nTest {
  52 
  53     public WinL10nTest(WixFileInitializer wxlFileInitializers[],
  54             String expectedCulture, String expectedErrorMessage) {
  55         this.wxlFileInitializers = wxlFileInitializers;
  56         this.expectedCulture = expectedCulture;
  57         this.expectedErrorMessage = expectedErrorMessage;
  58     }
  59 
  60     @Parameters
  61     public static List<Object[]> data() {
  62         return List.of(new Object[][]{
  63             {null, "en-us", null},
  64             {new WixFileInitializer[] {
  65                 WixFileInitializer.create("a.wxl", "en-us")
  66             }, "en-us", null},
  67             {new WixFileInitializer[] {
  68                 WixFileInitializer.create("a.wxl", "fr")
  69             }, "fr;en-us", null},
  70             {new WixFileInitializer[] {
  71                 WixFileInitializer.create("a.wxl", "fr"),
  72                 WixFileInitializer.create("b.wxl", "fr")
  73             }, "fr;en-us", null},
  74             {new WixFileInitializer[] {
  75                 WixFileInitializer.create("a.wxl", "it"),
  76                 WixFileInitializer.create("b.wxl", "fr")
  77             }, "it;fr;en-us", null},
  78             {new WixFileInitializer[] {
  79                 WixFileInitializer.create("c.wxl", "it"),
  80                 WixFileInitializer.create("b.wxl", "fr")
  81             }, "fr;it;en-us", null},
  82             {new WixFileInitializer[] {
  83                 WixFileInitializer.create("a.wxl", "fr"),
  84                 WixFileInitializer.create("b.wxl", "it"),
  85                 WixFileInitializer.create("c.wxl", "fr"),
  86                 WixFileInitializer.create("d.wxl", "it")
  87             }, "fr;it;en-us", null},
  88             {new WixFileInitializer[] {
  89                 WixFileInitializer.create("c.wxl", "it"),
  90                 WixFileInitializer.createMalformed("b.wxl")
  91             }, null, null}
  92         });
  93     }
  94 
  95     private final static Stream<String> getLightCommandLine(
  96             Executor.Result result) {
  97         return result.getOutput().stream()
  98                 .filter(s -> s.contains("Running"))
  99                 .filter(s -> s.contains("light.exe"))
 100                 .filter(s -> !s.contains("/?"));
 101     }
 102 
 103     @Test
 104     public void test() throws IOException {
 105 
 106         final boolean allWxlFilesValid;
 107         if (wxlFileInitializers != null) {
 108             allWxlFilesValid = Stream.of(wxlFileInitializers).allMatch(
 109                     WixFileInitializer::isValid);
 110         } else {
 111             allWxlFilesValid = true;
 112         }
 113 
 114         PackageTest test = new PackageTest()
 115         .forTypes(PackageType.WINDOWS)
 116         .configureHelloApp()
 117         .addInitializer(cmd -> {
 118             // 1. Set fake run time to save time by skipping jlink step of jpackage.
 119             // 2. Instruct test to save jpackage output.
 120             cmd.setFakeRuntime().saveConsoleOutput(true);
 121         })
 122         .addBundleVerifier((cmd, result) -> {
 123             if (expectedCulture != null) {
 124                 TKit.assertTextStream("-cultures:" + expectedCulture).apply(
 125                         getLightCommandLine(result));
 126             }
 127 
 128             if (expectedErrorMessage != null) {
 129                 TKit.assertTextStream(expectedErrorMessage)
 130                         .apply(result.getOutput().stream());
 131             }
 132 
 133             if (wxlFileInitializers != null) {
 134                 if (allWxlFilesValid) {
 135                     for (var v : wxlFileInitializers) {
 136                         v.createCmdOutputVerifier(resourceDir).apply(
 137                                 getLightCommandLine(result));
 138                     }
 139                 } else {
 140                     Stream.of(wxlFileInitializers)
 141                             .filter(Predicate.not(WixFileInitializer::isValid))
 142                             .forEach(v -> v.createCmdOutputVerifier(
 143                                     resourceDir).apply(result.getOutput().stream()));
 144                     TKit.assertFalse(
 145                             getLightCommandLine(result).findAny().isPresent(),
 146                             "Check light.exe was not invoked");
 147                 }
 148             }
 149         });
 150 
 151         if (wxlFileInitializers != null) {
 152             test.addInitializer(cmd -> {
 153                 resourceDir = TKit.createTempDirectory("resources");
 154 
 155                 cmd.addArguments("--resource-dir", resourceDir);
 156 
 157                 for (var v : wxlFileInitializers) {
 158                     v.apply(resourceDir);
 159                 }
 160             });
 161         }
 162 
 163         if (expectedErrorMessage != null || !allWxlFilesValid) {
 164             test.setExpectedExitCode(1);
 165         }
 166 
 167         test.run();
 168     }
 169 
 170     final private WixFileInitializer wxlFileInitializers[];
 171     final private String expectedCulture;
 172     final private String expectedErrorMessage;
 173     private Path resourceDir;
 174 
 175     private static class WixFileInitializer {
 176         static WixFileInitializer create(String name, String culture) {
 177             return new WixFileInitializer(name, culture);
 178         }
 179 
 180         static WixFileInitializer createMalformed(String name) {
 181             return new WixFileInitializer(name, null) {
 182                 @Override
 183                 public void apply(Path root) throws IOException {
 184                     TKit.createTextFile(root.resolve(name), List.of(
 185                             "<?xml version=\"1.0\" encoding=\"utf-8\"?>",
 186                             "<WixLocalization>"));
 187                 }
 188 
 189                 @Override
 190                 public String toString() {
 191                     return String.format("name=%s; malformed xml", name);
 192                 }
 193 
 194                 @Override
 195                 boolean isValid() {
 196                     return false;
 197                 }
 198 
 199                 @Override
 200                 TKit.TextStreamVerifier createCmdOutputVerifier(Path root) {
 201                     return TKit.assertTextStream(String.format(
 202                             "Failed to parse %s file",
 203                             root.resolve("b.wxl").toAbsolutePath()));
 204                 }
 205             };
 206         }
 207 
 208         private WixFileInitializer(String name, String culture) {
 209             this.name = name;
 210             this.culture = culture;
 211         }
 212 
 213         void apply(Path root) throws IOException {
 214             TKit.createTextFile(root.resolve(name), List.of(
 215                     "<?xml version=\"1.0\" encoding=\"utf-8\"?>",
 216                     culture == null ? "<WixLocalization/>" : "<WixLocalization Culture=\""
 217                             + culture
 218                             + "\" xmlns=\"http://schemas.microsoft.com/wix/2006/localization\" Codepage=\"1252\"/>"));
 219         }
 220 
 221         TKit.TextStreamVerifier createCmdOutputVerifier(Path root) {
 222             return TKit.assertTextStream(
 223                     root.resolve(name).toAbsolutePath().toString());
 224         }
 225 
 226         boolean isValid() {
 227             return true;
 228         }
 229 
 230         @Override
 231         public String toString() {
 232             return String.format("name=%s; culture=%s", name, culture);
 233         }
 234 
 235         private final String name;
 236         private final String culture;
 237     }
 238 }