From 9efcc2b30c8ef322b935019762c3e86859b4f533 Mon Sep 17 00:00:00 2001 From: ShodiBoy1 Date: Wed, 30 Sep 2026 20:34:33 +0200 Subject: [PATCH 1/4] #2576: fix cli tests failing on macOS --- .../ide/commandlet/CheckCommandletTest.java | 3 +- .../tools/ide/tool/CveCheckInstallTest.java | 32 +++++++++++------ .../tool/repository/ToolRepositoryMock.java | 34 ++++++++++++++++--- 3 files changed, 54 insertions(+), 15 deletions(-) diff --git a/cli/src/test/java/com/devonfw/tools/ide/commandlet/CheckCommandletTest.java b/cli/src/test/java/com/devonfw/tools/ide/commandlet/CheckCommandletTest.java index 798d66223d..ed899db160 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/commandlet/CheckCommandletTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/commandlet/CheckCommandletTest.java @@ -48,7 +48,8 @@ void testCheckMissingGitignoreWithoutFix(@TempDir Path tempDir) throws IOExcepti CheckCommandlet check = new CheckCommandlet(context); assertThrows(CliException.class, check::run); - Path gitignore = tempDir.resolve(".gitignore"); + // findRepositoryRoot resolves symlinks, so /var and /private/var must not be compared as different paths. + Path gitignore = context.getFileAccess().toRealPath(tempDir).resolve(".gitignore"); assertThat(gitignore).doesNotExist(); assertThat(context).log().hasEntries(IdeLogEntry.ofWarning(gitignore + ": No .gitignore found in repository root.")); } diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/CveCheckInstallTest.java b/cli/src/test/java/com/devonfw/tools/ide/tool/CveCheckInstallTest.java index ff92570855..792c74e4a9 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/CveCheckInstallTest.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/CveCheckInstallTest.java @@ -44,8 +44,8 @@ class CveCheckInstallTest extends AbstractIdeContextTest { /** - * + * Install Intellij with a configured version for which a version above it is the nearest safe upgrade. Ensures the documented "nearest" suggestion (see - * + * {@code documentation/security.adoc}) also offers versions greater than the configured one. + + * Install Intellij with a configured version for which a version above it is the nearest safe upgrade. Ensures the documented "nearest" suggestion (see + * {@code documentation/security.adoc}) also offers versions greater than the configured one. */ @Test void testInstallToolNearestSuggestsMinimalSafeUpgrade() { @@ -58,10 +58,10 @@ void testInstallToolNearestSuggestsMinimalSafeUpgrade() { context.setAnswers("nearest"); //act - commandlet.install(); + ToolInstallation installation = commandlet.install(); //assert - assertThat(context.getSoftwarePath().resolve("intellij").resolve(IdeTestContext.FILE_SOFTWARE_VERSION)).exists().hasContent("2022.3.2"); + assertInstalledVersion(installation, "2022.3.2"); } /** @@ -100,10 +100,10 @@ void testInstallToolCurrent() { context.setAnswers("current"); //act - commandlet.install(); + ToolInstallation installation = commandlet.install(); //assert - assertThat(context.getSoftwarePath().resolve("intellij").resolve(IdeTestContext.FILE_SOFTWARE_VERSION)).exists().hasContent("2023.3.3"); + assertInstalledVersion(installation, "2023.3.3"); assertThat(context.getSoftwarePath().resolve("java").resolve(IdeTestContext.FILE_SOFTWARE_VERSION)).exists().hasContent("17.0.10_7"); } @@ -115,10 +115,10 @@ void testInstallToolNearest() { context.setAnswers("nearest"); //act - commandlet.install(); + ToolInstallation installation = commandlet.install(); //assert - assertThat(context.getSoftwarePath().resolve("intellij").resolve(IdeTestContext.FILE_SOFTWARE_VERSION)).exists().hasContent("2022.3.2"); + assertInstalledVersion(installation, "2022.3.2"); assertThat(context.getSoftwarePath().resolve("java").resolve(IdeTestContext.FILE_SOFTWARE_VERSION)).exists().hasContent("17.0.10_7"); } @@ -133,12 +133,24 @@ void testInstallToolLatest() { context.setAnswers("latest"); //act - commandlet.install(); + ToolInstallation installation = commandlet.install(); //assert - assertThat(context.getSoftwarePath().resolve("intellij").resolve(IdeTestContext.FILE_SOFTWARE_VERSION)).exists().hasContent("2025.1.1.1"); + assertInstalledVersion(installation, "2025.1.1.1"); assertThat(context.getSoftwareRepositoryPath().resolve(ToolRepository.ID_DEFAULT).resolve("java").resolve("java").resolve("21.0.6_7") .resolve(IdeTestContext.FILE_SOFTWARE_VERSION)).exists().hasContent("21.0.6_7"); } + /** + * Asserts {@link IdeTestContext#FILE_SOFTWARE_VERSION} on the installation root. On macOS {@code software/intellij} links into the {@code .app} bundle, and + * the version file is not written there because changing a bundle after codesign breaks the seal. + * + * @param installation the installation returned by {@link Intellij#install()}. + * @param version the expected version file content. + */ + private static void assertInstalledVersion(ToolInstallation installation, String version) { + + assertThat(installation.rootDir().resolve(IdeTestContext.FILE_SOFTWARE_VERSION)).exists().hasContent(version); + } + } diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java b/cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java index 8933cf8870..b986d9e383 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java @@ -17,9 +17,11 @@ import org.slf4j.LoggerFactory; import com.devonfw.tools.ide.context.IdeContext; +import com.devonfw.tools.ide.io.TarCompression; import com.devonfw.tools.ide.tool.AbstractToolCommandlet; import com.devonfw.tools.ide.url.model.file.UrlDownloadFile; import com.devonfw.tools.ide.url.model.file.UrlDownloadFileMetadata; +import com.devonfw.tools.ide.util.FilenameUtil; import com.devonfw.tools.ide.version.GenericVersionRange; import com.devonfw.tools.ide.version.VersionIdentifier; import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; @@ -107,18 +109,20 @@ public Path download(String tool, String edition, VersionIdentifier version, Abs UrlDownloadFileMetadata metadata = getMetadata(tool, edition, version, toolCommandlet); String url = metadata.getUrls().iterator().next(); if (url.startsWith(VARIABLE_TESTBASEURL)) { + // FileAccess.compress builds tar and zip only. Fixtures named .dmg or .pkg are served as tgz. + String archiveUrl = toCompressibleArchiveUrl(url); try (ByteArrayOutputStream baos = new ByteArrayOutputStream(1024)) { - this.context.getFileAccess().compress(archiveFolder, baos, url); + this.context.getFileAccess().compress(archiveFolder, baos, archiveUrl); byte[] body = baos.toByteArray(); - String path = url.substring(VARIABLE_TESTBASEURL.length()); + String path = archiveUrl.substring(VARIABLE_TESTBASEURL.length()); stubFor(get(urlMatching(path)).willReturn( aResponse().withStatus(200).withBody(body))); - String resolvedUrl = url.replace(VARIABLE_TESTBASEURL, this.wmRuntimeInfo.getHttpBaseUrl()); + String resolvedUrl = archiveUrl.replace(VARIABLE_TESTBASEURL, this.wmRuntimeInfo.getHttpBaseUrl()); UrlDownloadFile urlDownloadFile = (UrlDownloadFile) metadata; metadata = new UrlDownloadFile(urlDownloadFile.getParent(), urlDownloadFile.getName(), Set.of(resolvedUrl)); return super.download(metadata); } catch (IOException e) { - throw new IllegalStateException("Failed to create mock archive for " + url, e); + throw new IllegalStateException("Failed to create mock archive for " + archiveUrl, e); } } else { throw new IllegalStateException("Invalid URL: " + url); @@ -127,4 +131,26 @@ public Path download(String tool, String edition, VersionIdentifier version, Abs return archiveFolder; } + /** + * Returns a URL whose extension {@code FileAccess.compress} can build. Extensions other than tar and zip (for example {@code dmg}) are rewritten to + * {@code tgz}, which is the archive format of the test infrastructure. + * + * @param url the download URL from the test fixture. + * @return {@code url} when its extension is compressible, otherwise the same URL with a {@code tgz} extension. + */ + private static String toCompressibleArchiveUrl(String url) { + + String extension = FilenameUtil.getExtension(url); + if ((extension != null) && (("zip".equals(extension)) || (TarCompression.of(extension) != null))) { + return url; + } + String tgzExtension = "." + TarCompression.GZ.getCombinedExtension(); + int lastDot = url.lastIndexOf('.'); + int lastSlash = Math.max(url.lastIndexOf('/'), url.lastIndexOf('\\')); + if (lastDot <= lastSlash) { + return url + tgzExtension; + } + return url.substring(0, lastDot) + tgzExtension; + } + } From a7ebd0eafdb0c4582bdeb274c00217f1f91b32c3 Mon Sep 17 00:00:00 2001 From: T9 <103292348+shodiBoy1@users.noreply.github.com> Date: Thu, 8 Oct 2026 17:57:44 +0200 Subject: [PATCH 2/4] Update cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java Co-authored-by: Lukas --- .../tools/ide/tool/repository/ToolRepositoryMock.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java b/cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java index b986d9e383..126958709e 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java @@ -145,12 +145,12 @@ private static String toCompressibleArchiveUrl(String url) { return url; } String tgzExtension = "." + TarCompression.GZ.getCombinedExtension(); - int lastDot = url.lastIndexOf('.'); - int lastSlash = Math.max(url.lastIndexOf('/'), url.lastIndexOf('\\')); - if (lastDot <= lastSlash) { + int lastDotIndex = url.lastIndexOf('.'); + int lastSlashIndex = Math.max(url.lastIndexOf('/'), url.lastIndexOf('\\')); + if (lastDotIndex <= lastSlashIndex) { return url + tgzExtension; } - return url.substring(0, lastDot) + tgzExtension; + return url.substring(0, lastDotIndex) + tgzExtension; } } From eb6256c9309092dbf86c7510f593388857051b42 Mon Sep 17 00:00:00 2001 From: T9 <103292348+shodiBoy1@users.noreply.github.com> Date: Tue, 13 Oct 2026 16:09:40 +0200 Subject: [PATCH 3/4] Update cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java Co-authored-by: quando632 --- .../devonfw/tools/ide/tool/repository/ToolRepositoryMock.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java b/cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java index 126958709e..f5e8d9b7cc 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java @@ -141,7 +141,7 @@ public Path download(String tool, String edition, VersionIdentifier version, Abs private static String toCompressibleArchiveUrl(String url) { String extension = FilenameUtil.getExtension(url); - if ((extension != null) && (("zip".equals(extension)) || (TarCompression.of(extension) != null))) { + if (!"dmg".equals(extension) && !"pkg".equals(extension)) { return url; } String tgzExtension = "." + TarCompression.GZ.getCombinedExtension(); From f4306a78bc55b96444a0cc83e1a40f75baba306b Mon Sep 17 00:00:00 2001 From: T9 <103292348+shodiBoy1@users.noreply.github.com> Date: Wed, 14 Oct 2026 17:41:00 +0200 Subject: [PATCH 4/4] Update cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java Co-authored-by: quando632 --- .../ide/tool/repository/ToolRepositoryMock.java | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java b/cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java index f5e8d9b7cc..6a2de51c3a 100644 --- a/cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java +++ b/cli/src/test/java/com/devonfw/tools/ide/tool/repository/ToolRepositoryMock.java @@ -132,11 +132,11 @@ public Path download(String tool, String edition, VersionIdentifier version, Abs } /** - * Returns a URL whose extension {@code FileAccess.compress} can build. Extensions other than tar and zip (for example {@code dmg}) are rewritten to - * {@code tgz}, which is the archive format of the test infrastructure. + * Returns a URL that {@code FileAccess.compress} can build. Fixtures for {@code dmg} and {@code pkg} cannot be created by the test infrastructure, so + * their extension is rewritten to {@code tgz}. * * @param url the download URL from the test fixture. - * @return {@code url} when its extension is compressible, otherwise the same URL with a {@code tgz} extension. + * @return {@code url} unchanged, or the same URL with a {@code tgz} extension for {@code dmg} and {@code pkg}. */ private static String toCompressibleArchiveUrl(String url) { @@ -144,13 +144,7 @@ private static String toCompressibleArchiveUrl(String url) { if (!"dmg".equals(extension) && !"pkg".equals(extension)) { return url; } - String tgzExtension = "." + TarCompression.GZ.getCombinedExtension(); - int lastDotIndex = url.lastIndexOf('.'); - int lastSlashIndex = Math.max(url.lastIndexOf('/'), url.lastIndexOf('\\')); - if (lastDotIndex <= lastSlashIndex) { - return url + tgzExtension; - } - return url.substring(0, lastDotIndex) + tgzExtension; + return url.substring(0, url.lastIndexOf('.')) + "." + TarCompression.GZ.getCombinedExtension(); } }