jdk-24/test/jdk/tools/jpackage/windows/WinL10nTest.java
2024-11-20 16:54:51 +00:00

326 lines
13 KiB
Java

/*
* Copyright (c) 2020, 2024, 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 java.io.IOException;
import java.nio.file.Path;
import jdk.jpackage.test.TKit;
import jdk.jpackage.test.PackageTest;
import jdk.jpackage.test.PackageType;
import jdk.jpackage.test.Annotations.Test;
import jdk.jpackage.test.Annotations.Parameters;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import jdk.jpackage.test.Executor;
import static jdk.jpackage.test.WindowsHelper.WixType.WIX3;
import static jdk.jpackage.test.WindowsHelper.getWixTypeFromVerboseJPackageOutput;
/*
* @test
* @summary Custom l10n of msi installers in jpackage
* @library /test/jdk/tools/jpackage/helpers
* @key jpackagePlatformPackage
* @requires (jpackage.test.SQETest == null)
* @build jdk.jpackage.test.*
* @requires (os.family == "windows")
* @compile WinL10nTest.java
* @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main
* --jpt-run=WinL10nTest
*/
public class WinL10nTest {
public WinL10nTest(WixFileInitializer wxlFileInitializers[],
String[] expectedCultures, String expectedErrorMessage,
String userLanguage, String userCountry,
boolean enableWixUIExtension) {
this.wxlFileInitializers = wxlFileInitializers;
this.expectedCultures = expectedCultures;
this.expectedErrorMessage = expectedErrorMessage;
this.userLanguage = userLanguage;
this.userCountry = userCountry;
this.enableWixUIExtension = enableWixUIExtension;
}
@Parameters
public static List<Object[]> data() {
return List.of(new Object[][]{
{null, new String[] {"en-us"}, null, null, null, false},
{null, new String[] {"en-us"}, null, "en", "US", false},
{null, new String[] {"en-us"}, null, "en", "US", true},
{null, new String[] {"de-de"}, null, "de", "DE", false},
{null, new String[] {"de-de"}, null, "de", "DE", true},
{null, new String[] {"ja-jp"}, null, "ja", "JP", false},
{null, new String[] {"ja-jp"}, null, "ja", "JP", true},
{null, new String[] {"zh-cn"}, null, "zh", "CN", false},
{null, new String[] {"zh-cn"}, null, "zh", "CN", true},
{new WixFileInitializer[] {
WixFileInitializer.create("a.wxl", "en-us")
}, new String[] {"en-us"}, null, null, null, false},
{new WixFileInitializer[] {
WixFileInitializer.create("a.wxl", "fr")
}, new String[] {"fr", "en-us"}, null, null, null, false},
{new WixFileInitializer[] {
WixFileInitializer.create("a.wxl", "fr"),
WixFileInitializer.create("b.wxl", "fr")
}, new String[] {"fr", "en-us"}, null, null, null, false},
{new WixFileInitializer[] {
WixFileInitializer.create("a.wxl", "it"),
WixFileInitializer.create("b.wxl", "fr")
}, new String[] {"it", "fr", "en-us"}, null, null, null, false},
{new WixFileInitializer[] {
WixFileInitializer.create("c.wxl", "it"),
WixFileInitializer.create("b.wxl", "fr")
}, new String[] {"fr", "it", "en-us"}, null, null, null, false},
{new WixFileInitializer[] {
WixFileInitializer.create("a.wxl", "fr"),
WixFileInitializer.create("b.wxl", "it"),
WixFileInitializer.create("c.wxl", "fr"),
WixFileInitializer.create("d.wxl", "it")
}, new String[] {"fr", "it", "en-us"}, null, null, null, false},
{new WixFileInitializer[] {
WixFileInitializer.create("c.wxl", "it"),
WixFileInitializer.createMalformed("b.wxl")
}, null, null, null, null, false},
{new WixFileInitializer[] {
WixFileInitializer.create("MsiInstallerStrings_de.wxl", "de")
}, new String[] {"en-us"}, null, null, null, false}
});
}
private static Stream<String> getWixCommandLine(Executor.Result result) {
return result.getOutput().stream().filter(createToolCommandLinePredicate("light").or(
createToolCommandLinePredicate("wix")));
}
private static boolean isWix3(Executor.Result result) {
return getWixTypeFromVerboseJPackageOutput(result) == WIX3;
}
private final static Predicate<String> createToolCommandLinePredicate(String wixToolName) {
var toolFileName = wixToolName + ".exe";
return (s) -> {
s = s.trim();
return s.startsWith(toolFileName) || ((s.contains(String.format("\\%s ", toolFileName)) && s.
contains(" -out ")));
};
}
private static List<TKit.TextStreamVerifier> createDefaultL10nFilesLocVerifiers(Path wixSrcDir) {
return Arrays.stream(DEFAULT_L10N_FILES).map(loc ->
TKit.assertTextStream("-loc " + wixSrcDir.resolve(
String.format("MsiInstallerStrings_%s.wxl", loc))))
.toList();
}
@Test
public void test() throws IOException {
final Path tempRoot = TKit.createTempDirectory("tmp");
final boolean allWxlFilesValid;
if (wxlFileInitializers != null) {
allWxlFilesValid = Stream.of(wxlFileInitializers).allMatch(
WixFileInitializer::isValid);
} else {
allWxlFilesValid = true;
}
PackageTest test = new PackageTest()
.forTypes(PackageType.WINDOWS)
.configureHelloApp()
.addInitializer(cmd -> {
// 1. Set fake run time to save time by skipping jlink step of jpackage.
// 2. Instruct test to save jpackage output.
cmd.setFakeRuntime().saveConsoleOutput(true);
boolean withJavaOptions = false;
// Set JVM default locale that is used to select primary l10n file.
if (userLanguage != null) {
withJavaOptions = true;
cmd.addArguments("-J-Duser.language=" + userLanguage);
}
if (userCountry != null) {
withJavaOptions = true;
cmd.addArguments("-J-Duser.country=" + userCountry);
}
if (withJavaOptions) {
// Use jpackage as a command to allow "-J" options come through
cmd.useToolProvider(false);
}
// Cultures handling is affected by the WiX extensions used.
// By default only WixUtilExtension is used, this flag
// additionally enables WixUIExtension.
if (enableWixUIExtension) {
cmd.addArgument("--win-dir-chooser");
}
// Preserve config dir to check the set of copied l10n files.
Path tempDir = tempRoot.resolve(cmd.packageType().name());
cmd.addArguments("--temp", tempDir);
})
.addBundleVerifier((cmd, result) -> {
final List<String> wixCmdline = getWixCommandLine(result).toList();
final var isWix3 = isWix3(result);
if (expectedCultures != null) {
String expected;
if (isWix3) {
expected = "-cultures:" + String.join(";", expectedCultures);
} else {
expected = Stream.of(expectedCultures).map(culture -> {
return String.join(" ", "-culture", culture);
}).collect(Collectors.joining(" "));
}
TKit.assertTextStream(expected).apply(wixCmdline.stream());
}
if (expectedErrorMessage != null) {
TKit.assertTextStream(expectedErrorMessage)
.apply(result.getOutput().stream());
}
if (wxlFileInitializers != null) {
var wixSrcDir = Path.of(cmd.getArgumentValue("--temp")).resolve(
"config").normalize().toAbsolutePath();
if (allWxlFilesValid) {
for (var v : wxlFileInitializers) {
if (!v.name.startsWith("MsiInstallerStrings_")) {
v.createCmdOutputVerifier(wixSrcDir).apply(wixCmdline.stream());
}
}
for (var v : createDefaultL10nFilesLocVerifiers(wixSrcDir)) {
v.apply(wixCmdline.stream());
}
} else {
Stream.of(wxlFileInitializers)
.filter(Predicate.not(WixFileInitializer::isValid))
.forEach(v -> v.createCmdOutputVerifier(
wixSrcDir).apply(result.getOutput().stream()));
TKit.assertTrue(wixCmdline.stream().findAny().isEmpty(),
String.format("Check %s.exe was not invoked",
isWix3 ? "light" : "wix"));
}
}
});
if (wxlFileInitializers != null) {
test.addInitializer(cmd -> {
resourceDir = TKit.createTempDirectory("resources");
cmd.addArguments("--resource-dir", resourceDir);
for (var v : wxlFileInitializers) {
v.apply(resourceDir);
}
});
}
if (expectedErrorMessage != null || !allWxlFilesValid) {
test.setExpectedExitCode(1);
}
test.run();
}
final private WixFileInitializer[] wxlFileInitializers;
final private String[] expectedCultures;
final private String expectedErrorMessage;
final private String userLanguage;
final private String userCountry;
final private boolean enableWixUIExtension;
private Path resourceDir;
private static class WixFileInitializer {
static WixFileInitializer create(String name, String culture) {
return new WixFileInitializer(name, culture);
}
static WixFileInitializer createMalformed(String name) {
return new WixFileInitializer(name, null) {
@Override
public void apply(Path root) throws IOException {
TKit.createTextFile(root.resolve(name), List.of(
"<?xml version=\"1.0\" encoding=\"utf-8\"?>",
"<WixLocalization>"));
}
@Override
public String toString() {
return String.format("name=%s; malformed xml", name);
}
@Override
boolean isValid() {
return false;
}
@Override
TKit.TextStreamVerifier createCmdOutputVerifier(Path wixSrcDir) {
return TKit.assertTextStream(String.format(
"Failed to parse %s file", wixSrcDir.resolve("b.wxl")));
}
};
}
private WixFileInitializer(String name, String culture) {
this.name = name;
this.culture = culture;
}
void apply(Path root) throws IOException {
TKit.createTextFile(root.resolve(name), List.of(
"<?xml version=\"1.0\" encoding=\"utf-8\"?>",
culture == null ? "<WixLocalization/>" : "<WixLocalization Culture=\""
+ culture
+ "\" xmlns=\"http://schemas.microsoft.com/wix/2006/localization\" Codepage=\"1252\"/>"));
}
TKit.TextStreamVerifier createCmdOutputVerifier(Path wixSrcDir) {
return TKit.assertTextStream("-loc " + wixSrcDir.resolve(name));
}
boolean isValid() {
return true;
}
@Override
public String toString() {
return String.format("name=%s; culture=%s", name, culture);
}
private final String name;
private final String culture;
}
private static final String[] DEFAULT_L10N_FILES = { "de", "en", "ja", "zh_CN" };
}