From b2da0d341b740eb5fbb784075adb3433427c3cff Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 25 Mar 2025 01:45:03 +0000 Subject: [PATCH] 8352289: [macos] Review skipped tests in tools/jpackage/macosx/SigningPackage* Reviewed-by: almatvee --- .../jdk/jpackage/test/JPackageCommand.java | 6 +- .../helpers/jdk/jpackage/test/MacHelper.java | 9 ++ .../jpackage/macosx/SigningAppImageTest.java | 8 +- .../macosx/SigningAppImageTwoStepsTest.java | 12 +- .../jpackage/macosx/SigningOptionsTest.java | 151 ------------------ ...SigningPackageFromTwoStepAppImageTest.java | 12 +- .../jpackage/macosx/SigningPackageTest.java | 8 +- .../macosx/SigningPackageTwoStepTest.java | 13 +- .../jpackage/macosx/base/SigningCheck.java | 97 ----------- test/jdk/tools/jpackage/share/ErrorTest.java | 55 ++++++- 10 files changed, 73 insertions(+), 298 deletions(-) delete mode 100644 test/jdk/tools/jpackage/macosx/SigningOptionsTest.java delete mode 100644 test/jdk/tools/jpackage/macosx/base/SigningCheck.java 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 1a6fd9ac6ca..d72e84bfab1 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -747,10 +747,10 @@ public class JPackageCommand extends CommandArguments { public JPackageCommand validateOutput(CannedFormattedString... str) { // Will look up the given errors in the order they are specified. - return validateOutput(Stream.of(str) - .map(this::getValue) + Stream.of(str).map(this::getValue) .map(TKit::assertTextStream) - .reduce(TKit.TextStreamVerifier::andThen).get()); + .reduce(TKit.TextStreamVerifier::andThen).ifPresent(this::validateOutput); + return this; } public boolean isWithToolProvider() { 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 8d245fb4d96..23d0ec80f1d 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java @@ -397,6 +397,10 @@ public final class MacHelper { private final org.w3c.dom.Document doc; } + public static boolean isXcodeDevToolsInstalled() { + return Inner.XCODE_DEV_TOOLS_INSTALLED; + } + private static DocumentBuilder createDocumentBuilder() throws ParserConfigurationException { DocumentBuilderFactory dbf = DocumentBuilderFactory.newDefaultInstance(); @@ -432,6 +436,11 @@ public final class MacHelper { } } + private static final class Inner { + private static final boolean XCODE_DEV_TOOLS_INSTALLED = + Executor.of("/usr/bin/xcrun", "--help").executeWithoutExitCodeCheck().getExitCode() == 0; + } + static final Set CRITICAL_RUNTIME_FILES = Set.of(Path.of( "Contents/Home/lib/server/libjvm.dylib")); diff --git a/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java b/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java index e27f6c8729b..e93e659408f 100644 --- a/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java @@ -46,16 +46,14 @@ import jdk.jpackage.test.AdditionalLauncher; * @test * @summary jpackage with --type app-image --mac-sign * @library /test/jdk/tools/jpackage/helpers - * @library /test/lib * @library base * @build SigningBase - * @build SigningCheck - * @build jtreg.SkippedException * @build jdk.jpackage.test.* * @build SigningAppImageTest - * @requires (os.family == "mac") + * @requires (jpackage.test.MacSignTests == "run") * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SigningAppImageTest + * --jpt-before-run=SigningBase.verifySignTestEnvReady */ public class SigningAppImageTest { @@ -72,8 +70,6 @@ public class SigningAppImageTest { public void test(boolean doSign, boolean signingKey, SigningBase.CertIndex certEnum) throws Exception { final var certIndex = certEnum.value(); - SigningCheck.checkCertificates(certIndex); - JPackageCommand cmd = JPackageCommand.helloAppImage(); if (doSign) { cmd.addArguments("--mac-sign", diff --git a/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java b/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java index b8763d82e36..94199b31434 100644 --- a/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java @@ -47,16 +47,14 @@ import jdk.jpackage.test.AdditionalLauncher; * @test * @summary jpackage with --type app-image --app-image "appImage" --mac-sign * @library /test/jdk/tools/jpackage/helpers - * @library /test/lib * @library base * @build SigningBase - * @build SigningCheck - * @build jtreg.SkippedException * @build jdk.jpackage.test.* * @build SigningAppImageTwoStepsTest - * @requires (os.family == "mac") + * @requires (jpackage.test.MacSignTests == "run") * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SigningAppImageTwoStepsTest + * --jpt-before-run=SigningBase.verifySignTestEnvReady */ public class SigningAppImageTwoStepsTest { @@ -68,11 +66,7 @@ public class SigningAppImageTwoStepsTest { @Parameter({"true", "false"}) // Unsigned @Parameter({"false", "true"}) - public void test(String... testArgs) throws Exception { - boolean signAppImage = Boolean.parseBoolean(testArgs[0]); - boolean signingKey = Boolean.parseBoolean(testArgs[1]); - - SigningCheck.checkCertificates(SigningBase.DEFAULT_INDEX); + public void test(boolean signAppImage, boolean signingKey) throws Exception { Path appimageOutput = TKit.createTempDirectory("appimage"); diff --git a/test/jdk/tools/jpackage/macosx/SigningOptionsTest.java b/test/jdk/tools/jpackage/macosx/SigningOptionsTest.java deleted file mode 100644 index 88595c566df..00000000000 --- a/test/jdk/tools/jpackage/macosx/SigningOptionsTest.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (c) 2023, 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 java.util.Collection; -import java.util.List; -import jdk.jpackage.test.Annotations.Parameters; -import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.JPackageCommand; -import jdk.jpackage.test.TKit; - -/* - * @test - * @summary Test jpackage signing options errors - * @library /test/jdk/tools/jpackage/helpers - * @library /test/lib - * @library base - * @build SigningBase - * @build SigningCheck - * @build jtreg.SkippedException - * @build SigningOptionsTest - * @requires (os.family == "mac") - * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main - * --jpt-run=SigningOptionsTest - * --jpt-before-run=jdk.jpackage.test.JPackageCommand.useExecutableByDefault - */ - -/* - * @test - * @summary Test jpackage signing options errors - * @library /test/jdk/tools/jpackage/helpers - * @library /test/lib - * @library base - * @build SigningBase - * @build SigningCheck - * @build jtreg.SkippedException - * @build SigningOptionsTest - * @requires (os.family == "mac") - * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main - * --jpt-run=SigningOptionsTest - * --jpt-before-run=jdk.jpackage.test.JPackageCommand.useToolProviderByDefault - */ - -public final class SigningOptionsTest { - - private final String expectedError; - private final JPackageCommand cmd; - - private static final String TEST_DUKE = TKit.TEST_SRC_ROOT.resolve( - "apps/dukeplug.png").toString(); - - @Parameters - public static Collection input() { - return List.of(new Object[][]{ - // --mac-signing-key-user-name and --mac-app-image-sign-identity - {"Hello", - new String[]{"--mac-sign", - "--mac-signing-key-user-name", "test-key", - "--mac-app-image-sign-identity", "test-identity"}, - null, - "Mutually exclusive options", - Boolean.FALSE}, - // --mac-signing-key-user-name and --mac-installer-sign-identity - {"Hello", - new String[]{"--mac-sign", - "--mac-signing-key-user-name", "test-key", - "--mac-installer-sign-identity", "test-identity"}, - null, - "Mutually exclusive options", - Boolean.FALSE}, - // --mac-installer-sign-identity and --type app-image - {"Hello", - new String[]{"--mac-sign", - "--mac-installer-sign-identity", "test-identity"}, - null, - "Option [--mac-installer-sign-identity] is not valid with type", - Boolean.FALSE}, - // --mac-installer-sign-identity and --type dmg - {"Hello", - new String[]{"--type", "dmg", - "--mac-sign", - "--mac-installer-sign-identity", "test-identity"}, - new String[]{"--type"}, - "Option [--mac-installer-sign-identity] is not valid with type", - Boolean.FALSE}, - // --app-content and --type app-image - // JDK-8340802: "codesign" may or may not fail if additional - // content is specified based on macOS version. For example on - // macOS 15 aarch64 "codesign" will not fail with additional content. - // Since we only need to check that warning is displayed when - // "codesign" fails and "--app-content" is provided, lets fail - // "codesign" for some better reason like identity which does not - // exists. - {"Hello", - new String[]{"--app-content", TEST_DUKE, - "--mac-sign", - "--mac-app-image-sign-identity", "test-identity"}, - null, - "\"codesign\" failed and additional application content" + - " was supplied via the \"--app-content\" parameter.", - Boolean.TRUE}, - }); - } - - public SigningOptionsTest(String javaAppDesc, String[] jpackageArgs, - String[] removeArgs, String expectedError, - Boolean checkRequirements) { - this.expectedError = expectedError; - - if (checkRequirements) { - SigningCheck.isXcodeDevToolsInstalled(); - } - - cmd = JPackageCommand.helloAppImage(javaAppDesc) - .saveConsoleOutput(true).dumpOutput(true); - if (jpackageArgs != null) { - cmd.addArguments(jpackageArgs); - } if (removeArgs != null) { - for (String arg : removeArgs) { - cmd.removeArgumentWithValue(arg); - } - } - } - - @Test - public void test() { - List output = cmd.execute(1).getOutput(); - TKit.assertNotNull(output, "output is null"); - TKit.assertTextStream(expectedError).apply(output.stream()); - } - -} diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java index f6408d21eba..a612c36ca62 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java @@ -51,17 +51,15 @@ import jdk.jpackage.test.Annotations.Parameter; * @test * @summary jpackage with --type pkg,dmg --app-image * @library /test/jdk/tools/jpackage/helpers - * @library /test/lib * @library base * @key jpackagePlatformPackage * @build SigningBase - * @build SigningCheck - * @build jtreg.SkippedException * @build jdk.jpackage.test.* * @build SigningPackageFromTwoStepAppImageTest - * @requires (os.family == "mac") + * @requires (jpackage.test.MacSignTests == "run") * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SigningPackageFromTwoStepAppImageTest + * --jpt-before-run=SigningBase.verifySignTestEnvReady */ public class SigningPackageFromTwoStepAppImageTest { @@ -103,11 +101,7 @@ public class SigningPackageFromTwoStepAppImageTest { @Parameter({"true", "false"}) // Unsigned @Parameter({"false", "true"}) - public void test(String... testArgs) throws Exception { - boolean signAppImage = Boolean.parseBoolean(testArgs[0]); - boolean signingKey = Boolean.parseBoolean(testArgs[1]); - - SigningCheck.checkCertificates(SigningBase.DEFAULT_INDEX); + public void test(boolean signAppImage, boolean signingKey) throws Exception { Path appimageOutput = TKit.createTempDirectory("appimage"); diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageTest.java index c56f01e192e..e41b0d60397 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageTest.java @@ -49,17 +49,15 @@ import jdk.jpackage.test.Annotations.Parameter; * @test * @summary jpackage with --type pkg,dmg --mac-sign * @library /test/jdk/tools/jpackage/helpers - * @library /test/lib * @library base * @key jpackagePlatformPackage * @build SigningBase - * @build SigningCheck - * @build jtreg.SkippedException * @build jdk.jpackage.test.* * @build SigningPackageTest - * @requires (os.family == "mac") + * @requires (jpackage.test.MacSignTests == "run") * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SigningPackageTest + * --jpt-before-run=SigningBase.verifySignTestEnvReady */ public class SigningPackageTest { @@ -129,8 +127,6 @@ public class SigningPackageTest { public static void test(boolean signingKey, boolean signAppImage, boolean signPKG, SigningBase.CertIndex certEnum) throws Exception { final var certIndex = certEnum.value(); - SigningCheck.checkCertificates(certIndex); - new PackageTest() .configureHelloApp() .forTypes(PackageType.MAC) diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java index 84af48f6efb..ccb78fee9f8 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java @@ -52,17 +52,15 @@ import jdk.jpackage.test.Annotations.Parameter; * @test * @summary jpackage with --type pkg,dmg --app-image * @library /test/jdk/tools/jpackage/helpers - * @library /test/lib * @library base * @key jpackagePlatformPackage * @build SigningBase - * @build SigningCheck - * @build jtreg.SkippedException * @build jdk.jpackage.test.* * @build SigningPackageTwoStepTest - * @requires (os.family == "mac") + * @requires (jpackage.test.MacSignTests == "run") * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SigningPackageTwoStepTest + * --jpt-before-run=SigningBase.verifySignTestEnvReady */ public class SigningPackageTwoStepTest { @@ -107,12 +105,7 @@ public class SigningPackageTwoStepTest { @Parameter({"true", "false"}) // Unsigned @Parameter({"false", "true"}) - public static void test(String... testArgs) throws Exception { - boolean signAppImage = Boolean.parseBoolean(testArgs[0]); - boolean signingKey = Boolean.parseBoolean(testArgs[1]); - - SigningCheck.checkCertificates(SigningBase.DEFAULT_INDEX); - + public static void test(boolean signAppImage, boolean signingKey) throws Exception { Path appimageOutput = TKit.createTempDirectory("appimage"); JPackageCommand appImageCmd = JPackageCommand.helloAppImage() diff --git a/test/jdk/tools/jpackage/macosx/base/SigningCheck.java b/test/jdk/tools/jpackage/macosx/base/SigningCheck.java deleted file mode 100644 index 3db101f3806..00000000000 --- a/test/jdk/tools/jpackage/macosx/base/SigningCheck.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2019, 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 java.util.List; - -import jdk.jpackage.test.TKit; -import jdk.jpackage.test.Executor; - -import jdk.jpackage.internal.MacCertificate; - -public class SigningCheck { - - public static void checkCertificates(int certIndex) { - if (!SigningBase.isDevNameDefault()) { - // Do not validate user supplied certificates. - // User supplied certs whose trust is set to "Use System Defaults" - // will not be listed as trusted by dump-trust-settings, so we - // cannot verify them completely. - return; - } - - // Index can be -1 for unsigned tests, but we still skipping test - // if machine is not configured for signing testing, so default it to - // SigningBase.DEFAULT_INDEX - if (certIndex <= -1) { - certIndex = SigningBase.DEFAULT_INDEX; - } - - String key = MacCertificate.findCertificateKey(null, - SigningBase.getAppCert(certIndex), - SigningBase.getKeyChain()); - validateCertificate(key); - validateCertificateTrust(SigningBase.getAppCert(certIndex)); - - key = MacCertificate.findCertificateKey(null, - SigningBase.getInstallerCert(certIndex), - SigningBase.getKeyChain()); - validateCertificate(key); - validateCertificateTrust(SigningBase.getInstallerCert(certIndex)); - } - - private static void validateCertificate(String key) { - if (key != null) { - MacCertificate certificate = new MacCertificate(key); - if (!certificate.isValid()) { - TKit.throwSkippedException("Certifcate expired: " + key); - } else { - return; - } - } - - TKit.throwSkippedException("Cannot find required certifciates: " + key); - } - - private static void validateCertificateTrust(String name) { - // Certificates using the default user name must be trusted by user. - List result = new Executor() - .setExecutable("/usr/bin/security") - .addArguments("dump-trust-settings") - .executeWithoutExitCodeCheckAndGetOutput(); - result.stream().forEachOrdered(TKit::trace); - TKit.assertTextStream(name) - .predicate((line, what) -> line.trim().endsWith(what)) - .orElseThrow(() -> TKit.throwSkippedException( - "Certifcate not trusted by current user: " + name)) - .apply(result.stream()); - } - - public static void isXcodeDevToolsInstalled() { - int code = Executor.of("/usr/bin/xcrun", "--help") - .executeWithoutExitCodeCheck().getExitCode(); - if (code != 0) { - TKit.throwSkippedException("Missing Xcode with command line developer tools"); - } - } - -} diff --git a/test/jdk/tools/jpackage/share/ErrorTest.java b/test/jdk/tools/jpackage/share/ErrorTest.java index 5260dceae32..0af215d7d43 100644 --- a/test/jdk/tools/jpackage/share/ErrorTest.java +++ b/test/jdk/tools/jpackage/share/ErrorTest.java @@ -35,6 +35,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; import java.util.regex.Pattern; @@ -46,6 +47,7 @@ import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.CannedFormattedString; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JPackageStringBundle; +import jdk.jpackage.test.MacHelper; import jdk.jpackage.test.PackageType; import jdk.jpackage.test.TKit; @@ -539,25 +541,64 @@ public final class ErrorTest { ).map(argGroup -> { return testSpec().noAppDesc().addArgs(argGroup.asArray()).addArgs("--app-image", Token.APP_IMAGE.token()) .error("ERR_InvalidOptionWithAppImageSigning", argGroup.arg()); - }).mapMulti((builder, acc) -> { - // It should bail out with the same error message regardless of `--mac-sign` option. - acc.accept(builder.create()); - acc.accept(builder.addArgs("--mac-sign").create()); - }).toList()); + // It should bail out with the same error message regardless of `--mac-sign` option. + }).mapMulti(ErrorTest::duplicateForMacSign).toList()); testCases.addAll(createMutuallyExclusive( new ArgumentGroup("--mac-signing-key-user-name", "foo"), new ArgumentGroup("--mac-app-image-sign-identity", "bar") - ).map(TestSpec.Builder::create).toList()); + ).mapMulti(ErrorTest::duplicateForMacSign).toList()); testCases.addAll(createMutuallyExclusive( new ArgumentGroup("--mac-signing-key-user-name", "foo"), new ArgumentGroup("--mac-installer-sign-identity", "bar") - ).map(TestSpec.Builder::nativeType).map(TestSpec.Builder::create).toList()); + ).map(TestSpec.Builder::nativeType).mapMulti(ErrorTest::duplicateForMacSign).toList()); return toTestArgs(testCases.stream()); } + @Test(ifOS = MACOS) + public static void testAppContentWarning() { + // --app-content and --type app-image + // Expect `message.codesign.failed.reason.app.content` message in the log. + // This is not a fatal error, just a warning. + // To make jpackage fail, specify invalid signing identity. + final var cmd = JPackageCommand.helloAppImage() + .addArguments("--app-content", TKit.TEST_SRC_ROOT.resolve("apps/dukeplug.png")) + .addArguments("--mac-sign", "--mac-app-image-sign-identity", "foo"); + + final List expectedStrings = new ArrayList<>(); + expectedStrings.add(JPackageStringBundle.MAIN.cannedFormattedString("message.codesign.failed.reason.app.content")); + + final var xcodeWarning = JPackageStringBundle.MAIN.cannedFormattedString("message.codesign.failed.reason.xcode.tools"); + if (!MacHelper.isXcodeDevToolsInstalled()) { + expectedStrings.add(xcodeWarning); + } + + defaultInit(cmd, expectedStrings); + + if (MacHelper.isXcodeDevToolsInstalled()) { + // Check there is no warning about missing xcode command line developer tools. + cmd.validateOutput(TKit.assertTextStream(xcodeWarning.getValue()).negate()); + } + + cmd.execute(1); + } + + private static void duplicate(TestSpec.Builder builder, Consumer accumulator, Consumer mutator) { + accumulator.accept(builder.create()); + mutator.accept(builder); + accumulator.accept(builder.create()); + } + + private static void duplicateAddArgs(TestSpec.Builder builder, Consumer accumulator, String...args) { + duplicate(builder, accumulator, b -> b.addArgs(args)); + } + + private static void duplicateForMacSign(TestSpec.Builder builder, Consumer accumulator) { + duplicateAddArgs(builder, accumulator, "--mac-sign"); + } + private record UnsupportedPlatformOption(String name, Optional value) { UnsupportedPlatformOption { Objects.requireNonNull(name);