From dd5eb5ccaa8faaa2a5f02482d8dc8fbf03723e9d Mon Sep 17 00:00:00 2001 From: Sophio Japharidze Date: Fri, 4 Oct 2024 15:35:00 +0200 Subject: [PATCH] SLLS-268 refactoring for better coverage --- .../folders/WorkspaceFolderBranchManager.java | 7 +- .../sonarlint/ls/util/GitUtils.java | 13 ++- .../WorkspaceFolderBranchManagerTest.java | 97 +++++++++++++++++++ .../sonarlint/ls/util/GitUtilsTests.java | 84 +++++----------- src/test/java/testutils/JavaUnzip.java | 65 +++++++++++++ 5 files changed, 199 insertions(+), 67 deletions(-) create mode 100644 src/test/java/org/sonarsource/sonarlint/ls/folders/WorkspaceFolderBranchManagerTest.java create mode 100644 src/test/java/testutils/JavaUnzip.java diff --git a/src/main/java/org/sonarsource/sonarlint/ls/folders/WorkspaceFolderBranchManager.java b/src/main/java/org/sonarsource/sonarlint/ls/folders/WorkspaceFolderBranchManager.java index f2075b5b3..b3d38a5eb 100644 --- a/src/main/java/org/sonarsource/sonarlint/ls/folders/WorkspaceFolderBranchManager.java +++ b/src/main/java/org/sonarsource/sonarlint/ls/folders/WorkspaceFolderBranchManager.java @@ -75,11 +75,6 @@ public String matchSonarProjectBranch(String folderUri, String mainBranchName, S public boolean matchProjectBranch(String folderUri, String branchNameToMatch, SonarLintCancelChecker cancelChecker) { if (cancelChecker.isCanceled()) return false; - var repo = GitUtils.getRepositoryForDir(Paths.get(URI.create(folderUri)), logOutput); - if (repo == null) { - return false; - } - var currentBranch = GitUtils.getCurrentBranch(repo); - return branchNameToMatch.equals(currentBranch); + return GitUtils.isCurrentBranch(folderUri, branchNameToMatch, logOutput); } } diff --git a/src/main/java/org/sonarsource/sonarlint/ls/util/GitUtils.java b/src/main/java/org/sonarsource/sonarlint/ls/util/GitUtils.java index 27dff6a59..a47bf3457 100644 --- a/src/main/java/org/sonarsource/sonarlint/ls/util/GitUtils.java +++ b/src/main/java/org/sonarsource/sonarlint/ls/util/GitUtils.java @@ -20,7 +20,9 @@ package org.sonarsource.sonarlint.ls.util; import java.io.IOException; +import java.net.URI; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -109,11 +111,16 @@ public static String electBestMatchingServerBranchForCurrentHead(Repository repo } } - public static String getCurrentBranch(Repository repo) { + public static boolean isCurrentBranch(String folderUri, String expectedBranch, LanguageClientLogger logOutput) { + var repo = GitUtils.getRepositoryForDir(Paths.get(URI.create(folderUri)), logOutput); + if (repo == null) { + return false; + } try { - return repo.getBranch(); + var branch = repo.getBranch(); + return branch != null && branch.equals(expectedBranch); } catch (IOException e) { - return null; + return false; } } diff --git a/src/test/java/org/sonarsource/sonarlint/ls/folders/WorkspaceFolderBranchManagerTest.java b/src/test/java/org/sonarsource/sonarlint/ls/folders/WorkspaceFolderBranchManagerTest.java new file mode 100644 index 000000000..4f29067c8 --- /dev/null +++ b/src/test/java/org/sonarsource/sonarlint/ls/folders/WorkspaceFolderBranchManagerTest.java @@ -0,0 +1,97 @@ +/* + * SonarLint Language Server + * Copyright (C) 2009-2024 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonarsource.sonarlint.ls.folders; + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.concurrent.CancellationException; +import org.eclipse.lsp4j.jsonrpc.CancelChecker; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.sonarsource.sonarlint.core.rpc.client.SonarLintCancelChecker; +import org.sonarsource.sonarlint.ls.backend.BackendServiceFacade; +import org.sonarsource.sonarlint.ls.log.LanguageClientLogger; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.mockito.Mockito.mock; +import static testutils.JavaUnzip.javaUnzip; + +class WorkspaceFolderBranchManagerTest { + private static WorkspaceFolderBranchManager underTest; + + @BeforeAll + static void setUp() { + var fakeClientLogger = mock(LanguageClientLogger.class); + var backendServiceFacade = mock(BackendServiceFacade.class); + underTest = new WorkspaceFolderBranchManager(backendServiceFacade, fakeClientLogger); + } + + @Test + void matchProjectBranch_shouldReturnTrueWhenCurrentBranch(@TempDir File projectDir) { + javaUnzip("closest-branch.zip", projectDir); + Path path = Paths.get(projectDir.getPath(), "closest-branch"); + + var cancelChecker = new SonarLintCancelChecker(DummyCancelChecker::new); + + var matchProjectBranch = underTest.matchProjectBranch(path.toUri().toString(), "current_branch", cancelChecker); + assertThat(matchProjectBranch).isTrue(); + } + + @Test + void matchProjectBranch_shouldReturnFalseWhenCanceled(@TempDir File projectDir) { + javaUnzip("closest-branch.zip", projectDir); + Path path = Paths.get(projectDir.getPath(), "closest-branch"); + + var cancelChecker = new SonarLintCancelChecker(new CanceledDummyCancelChecker()); + + var matchProjectBranch = underTest.matchProjectBranch(path.toUri().toString(), "current_branch", cancelChecker); + assertThat(matchProjectBranch).isFalse(); + } + + static class DummyCancelChecker implements CancelChecker { + private final boolean canceled = false; + + @Override + public void checkCanceled() { + if (canceled) { + throw new RuntimeException("Canceled"); + } + } + + @Override + public boolean isCanceled() { + return canceled; + } + } + + static class CanceledDummyCancelChecker implements CancelChecker { + @Override + public void checkCanceled() { + throw new CancellationException("Canceled"); + } + + @Override + public boolean isCanceled() { + return true; + } + } +} \ No newline at end of file diff --git a/src/test/java/org/sonarsource/sonarlint/ls/util/GitUtilsTests.java b/src/test/java/org/sonarsource/sonarlint/ls/util/GitUtilsTests.java index e7ccf16a4..f5649f472 100644 --- a/src/test/java/org/sonarsource/sonarlint/ls/util/GitUtilsTests.java +++ b/src/test/java/org/sonarsource/sonarlint/ls/util/GitUtilsTests.java @@ -21,31 +21,27 @@ import java.io.File; import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Enumeration; import java.util.Set; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; import org.eclipse.jgit.lib.RefDatabase; import org.eclipse.jgit.lib.Repository; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import org.sonarsource.sonarlint.ls.log.LanguageClientLogger; -import static java.lang.String.format; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static testutils.JavaUnzip.javaUnzip; class GitUtilsTests { private final LanguageClientLogger fakeClientLogger = mock(LanguageClientLogger.class); @Test - void noGitRepoShouldBeNull(@TempDir File projectDir) throws IOException { + void noGitRepoShouldBeNull(@TempDir File projectDir) { javaUnzip("no-git-repo.zip", projectDir); Path path = Paths.get(projectDir.getPath(), "no-git-repo"); Repository repo = GitUtils.getRepositoryForDir(path, fakeClientLogger); @@ -53,7 +49,7 @@ void noGitRepoShouldBeNull(@TempDir File projectDir) throws IOException { } @Test - void gitRepoShouldBeNotNull(@TempDir File projectDir) throws IOException { + void gitRepoShouldBeNotNull(@TempDir File projectDir) { javaUnzip("dummy-git.zip", projectDir); Path path = Paths.get(projectDir.getPath(), "dummy-git"); try (Repository repo = GitUtils.getRepositoryForDir(path, fakeClientLogger)) { @@ -65,7 +61,7 @@ void gitRepoShouldBeNotNull(@TempDir File projectDir) throws IOException { } @Test - void shouldElectAnalyzedBranch(@TempDir File projectDir) throws IOException { + void shouldElectAnalyzedBranch(@TempDir File projectDir) { javaUnzip("analyzed-branch.zip", projectDir); Path path = Paths.get(projectDir.getPath(), "analyzed-branch"); try (Repository repo = GitUtils.getRepositoryForDir(path, fakeClientLogger)) { @@ -77,7 +73,7 @@ void shouldElectAnalyzedBranch(@TempDir File projectDir) throws IOException { } @Test - void shouldReturnNullIfNonePresentInLocalGit(@TempDir File projectDir) throws IOException { + void shouldReturnNullIfNonePresentInLocalGit(@TempDir File projectDir) { javaUnzip("analyzed-branch.zip", projectDir); Path path = Paths.get(projectDir.getPath(), "analyzed-branch"); try (Repository repo = GitUtils.getRepositoryForDir(path, fakeClientLogger)) { @@ -89,7 +85,7 @@ void shouldReturnNullIfNonePresentInLocalGit(@TempDir File projectDir) throws IO } @Test - void shouldElectClosestBranch(@TempDir File projectDir) throws IOException { + void shouldElectClosestBranch(@TempDir File projectDir) { javaUnzip("closest-branch.zip", projectDir); Path path = Paths.get(projectDir.getPath(), "closest-branch"); @@ -103,7 +99,7 @@ void shouldElectClosestBranch(@TempDir File projectDir) throws IOException { } @Test - void shouldElectClosestBranch_even_if_no_main_branch(@TempDir File projectDir) throws IOException { + void shouldElectClosestBranch_even_if_no_main_branch(@TempDir File projectDir) { javaUnzip("closest-branch.zip", projectDir); Path path = Paths.get(projectDir.getPath(), "closest-branch"); @@ -117,7 +113,7 @@ void shouldElectClosestBranch_even_if_no_main_branch(@TempDir File projectDir) t } @Test - void shouldElectMainBranchForNonAnalyzedChildBranch(@TempDir File projectDir) throws IOException { + void shouldElectMainBranchForNonAnalyzedChildBranch(@TempDir File projectDir) { javaUnzip("child-from-non-analyzed.zip", projectDir); Path path = Paths.get(projectDir.getPath(), "child-from-non-analyzed"); try (Repository repo = GitUtils.getRepositoryForDir(path, fakeClientLogger)) { @@ -142,28 +138,34 @@ void shouldReturnNullOnException() throws IOException { } @Test - void getCurrentBranch_shouldReturnNullOnException() throws IOException { - Repository repo = mock(Repository.class); - when(repo.getBranch()).thenThrow(new IOException()); - - String branch = GitUtils.getCurrentBranch(repo); + void isCurrentBranch_shouldReturnTrueWhenCurrentBranch(@TempDir File projectDir) { + javaUnzip("closest-branch.zip", projectDir); + Path path = Paths.get(projectDir.getPath(), "closest-branch"); - assertThat(branch).isNull(); + boolean isCurrentBranch = GitUtils.isCurrentBranch(path.toUri().toString(), "current_branch", fakeClientLogger); + assertThat(isCurrentBranch).isTrue(); } @Test - void shouldReturnCurrentBranch(@TempDir File projectDir) throws IOException { + void isCurrentBranch_shouldReturnFalseWhenNotCurrentBranch(@TempDir File projectDir) { javaUnzip("closest-branch.zip", projectDir); Path path = Paths.get(projectDir.getPath(), "closest-branch"); - try (Repository repo = GitUtils.getRepositoryForDir(path, fakeClientLogger)) { - String currentBranch = GitUtils.getCurrentBranch(repo); - assertThat(currentBranch).isEqualTo("current_branch"); - } + boolean isCurrentBranch = GitUtils.isCurrentBranch(path.toUri().toString(), "not_current_branch", fakeClientLogger); + assertThat(isCurrentBranch).isFalse(); + } + + @Test + void isCurrentBranch_shouldReturnFalseWhenNoRepo(@TempDir File projectDir) { + javaUnzip("closest-branch.zip", projectDir); + Path path = Paths.get(projectDir.getPath(), "non-existent"); + + boolean isCurrentBranch = GitUtils.isCurrentBranch(path.toUri().toString(), "not_current_branch", fakeClientLogger); + assertThat(isCurrentBranch).isFalse(); } @Test - void shouldFavorCurrentBranchIfMultipleCandidates(@TempDir File projectDir) throws IOException { + void shouldFavorCurrentBranchIfMultipleCandidates(@TempDir File projectDir) { // Both main and same-as-master branches are pointing to HEAD, but same-as-master is the currently checked out branch javaUnzip("two-branches-for-head.zip", projectDir); Path path = Paths.get(projectDir.getPath(), "two-branches-for-head"); @@ -176,38 +178,4 @@ void shouldFavorCurrentBranchIfMultipleCandidates(@TempDir File projectDir) thro } } - public void javaUnzip(String zipFileName, File toDir) throws IOException { - File testRepos = new File("src/test/resources/test-repos"); - File zipFile = new File(testRepos, zipFileName); - javaUnzip(zipFile, toDir); - } - - private static void javaUnzip(File zip, File toDir) { - try { - try (ZipFile zipFile = new ZipFile(zip)) { - Enumeration entries = zipFile.entries(); - while (entries.hasMoreElements()) { - ZipEntry entry = entries.nextElement(); - File to = new File(toDir, entry.getName()); - if (entry.isDirectory()) { - forceMkdir(to); - } else { - File parent = to.getParentFile(); - forceMkdir(parent); - - Files.copy(zipFile.getInputStream(entry), to.toPath()); - } - } - } - } catch (Exception e) { - throw new IllegalStateException(format("Fail to unzip %s to %s", zip, toDir), e); - } - } - - private static void forceMkdir(final File directory) throws IOException { - if ((directory != null) && (!directory.mkdirs() && !directory.isDirectory())) { - throw new IOException("Cannot create directory '" + directory + "'."); - } - } - } diff --git a/src/test/java/testutils/JavaUnzip.java b/src/test/java/testutils/JavaUnzip.java new file mode 100644 index 000000000..5c4805d37 --- /dev/null +++ b/src/test/java/testutils/JavaUnzip.java @@ -0,0 +1,65 @@ +/* + * SonarLint Language Server + * Copyright (C) 2009-2024 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package testutils; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import static java.lang.String.format; + +public class JavaUnzip { + public static void javaUnzip(String zipFileName, File toDir) { + File testRepos = new File("src/test/resources/test-repos"); + File zipFile = new File(testRepos, zipFileName); + javaUnzip(zipFile, toDir); + } + + private static void javaUnzip(File zip, File toDir) { + try { + try (ZipFile zipFile = new ZipFile(zip)) { + Enumeration entries = zipFile.entries(); + while (entries.hasMoreElements()) { + ZipEntry entry = entries.nextElement(); + File to = new File(toDir, entry.getName()); + if (entry.isDirectory()) { + forceMkdir(to); + } else { + File parent = to.getParentFile(); + forceMkdir(parent); + + Files.copy(zipFile.getInputStream(entry), to.toPath()); + } + } + } + } catch (Exception e) { + throw new IllegalStateException(format("Fail to unzip %s to %s", zip, toDir), e); + } + } + + private static void forceMkdir(final File directory) throws IOException { + if ((directory != null) && (!directory.mkdirs() && !directory.isDirectory())) { + throw new IOException("Cannot create directory '" + directory + "'."); + } + } +}