From 87e2a7e40def6c6c0055e3d8336a0b4801ac3127 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Sat, 15 Dec 2012 19:15:58 +0400 Subject: [PATCH] [git] Start writing cucumber tests. * First scenario for cherry-pick tests. * GitCucumberWorld to contain environment variables visible from everywhere. * Move initialization stuff from GitLightTest to static methods of GitTestInitUtil to reuse in GeneralStepdefs. * Add cucumber-jvm & cucumber-groovy to git4idea classpath. --- plugins/git4idea/git4idea.iml | 4 + .../git4idea/CherryPickeStepdefs.groovy | 88 +++++++++++++++++++ .../git4idea/GeneralStepdefs.groovy | 47 ++++++++++ .../git4idea/cherry-pick-auto-commit.feature | 28 ++++++ .../git4idea/GitCucumberWorld.java | 22 +++++ .../git4idea/test/GitLightTest.groovy | 61 ++----------- .../git4idea/test/GitTestImpl.groovy | 2 +- .../git4idea/test/GitTestInitUtil.groovy | 61 +++++++++++++ 8 files changed, 260 insertions(+), 53 deletions(-) create mode 100644 plugins/git4idea/test-features/git4idea/CherryPickeStepdefs.groovy create mode 100644 plugins/git4idea/test-features/git4idea/GeneralStepdefs.groovy create mode 100644 plugins/git4idea/test-features/git4idea/cherry-pick-auto-commit.feature create mode 100644 plugins/git4idea/test-stepdefs/git4idea/GitCucumberWorld.java create mode 100644 plugins/git4idea/testFramework/git4idea/test/GitTestInitUtil.groovy diff --git a/plugins/git4idea/git4idea.iml b/plugins/git4idea/git4idea.iml index 34c8ed92ec04..b0ecaa1607db 100644 --- a/plugins/git4idea/git4idea.iml +++ b/plugins/git4idea/git4idea.iml @@ -8,6 +8,8 @@ + + @@ -73,6 +75,8 @@ + + diff --git a/plugins/git4idea/test-features/git4idea/CherryPickeStepdefs.groovy b/plugins/git4idea/test-features/git4idea/CherryPickeStepdefs.groovy new file mode 100644 index 000000000000..8cdca56d25b5 --- /dev/null +++ b/plugins/git4idea/test-features/git4idea/CherryPickeStepdefs.groovy @@ -0,0 +1,88 @@ +package git4idea +import com.intellij.dvcs.test.MockVirtualFile +import com.intellij.notification.Notification +import com.intellij.openapi.vcs.FilePathImpl +import com.intellij.openapi.vcs.changes.Change +import com.intellij.openapi.vcs.changes.ChangeListManager +import com.intellij.openapi.vcs.changes.LocalChangeList +import com.intellij.openapi.vcs.history.VcsRevisionNumber +import com.intellij.openapi.vfs.newvfs.impl.NullVirtualFile +import com.intellij.testFramework.vcs.MockChangeListManager +import com.intellij.testFramework.vcs.MockContentRevision +import git4idea.history.browser.GitCherryPicker +import git4idea.history.browser.GitCommit +import git4idea.history.browser.SHAHash +import git4idea.history.wholeTree.AbstractHash +import git4idea.test.TestNotificator + +import static com.intellij.dvcs.test.Executor.echo +import static cucumber.runtime.groovy.EN.* +import static git4idea.GitCucumberWorld.* +import static git4idea.test.GitExecutor.git +import static git4idea.test.GitScenarios.checkout +import static junit.framework.Assert.assertEquals +/** + * + * @author Kirill Likhodedov + */ + +String remCommit + +Given(~'^(enabled|disabled) auto-commit in the settings$') { String state -> + boolean enabled = state.equals("enabled") + myPlatformFacade.getSettings(myProject).setAutoCommitOnCherryPick(enabled); +} + +Given(~'^branch "([^"]*)" with commit "([^"]*)" by "([^"]*)" modifying (.+):$') { String branch, String commitMessage, String author, + String file, String content -> + checkout(myRepository, branch) + echo(file, content) + git("commit -am $commitMessage --author '$author <$author@example.com>'") + checkout(myRepository, "master") +} + +When(~'^I cherry-pick the commit "(.+)"$') { String msg -> + String hash = git("log --grep $msg --pretty=%H --all"); + remCommit = hash + new GitCherryPicker(myProject, myGit, myPlatformFacade, myPlatformFacade.getSettings(myProject).isAutoCommitOnCherryPick()) + .cherryPick(Collections.singletonMap(myRepository, Collections.singletonList(commit(hash, msg)))); +} + +private GitCommit commit(String hash, String message) { + AbstractHash ahash = AbstractHash.create(hash); + List changes = new ArrayList(); + changes.add(new Change(null, new MockContentRevision(new FilePathImpl(new MockVirtualFile("name")), VcsRevisionNumber.NULL))); + return new GitCommit(NullVirtualFile.INSTANCE, ahash, SHAHash.emulate(ahash), "John Smith", null, null, message, message, + null, null, null, null, null, null, null, changes, 0); +} + +Then(~'^the last commit is$') { String message -> + String actual = git("log -1 --pretty=%B"); + message = message.replace("#hash", remCommit) + assertEquals("Commit doesn't match", message, actual); +} + +And(~'^notification "([^"]*)" is shown$') { String title -> + assertEquals "Notification title is incorrect", title, lastNotification().title +} + +private Notification lastNotification() { + (myPlatformFacade.getNotificator(myProject) as TestNotificator).lastNotification +} + +And(~'^no new changelists are created$') {-> + assertOnlyDefaultChangelist() +} + +void assertOnlyDefaultChangelist() { + String DEFAULT = MockChangeListManager.DEFAULT_CHANGE_LIST_NAME; + assertChangeLists( [DEFAULT], DEFAULT) +} + +void assertChangeLists(Collection changeLists, String activeChangelist) { + ChangeListManager changeListManager = myPlatformFacade.getChangeListManager(myProject) + List lists = changeListManager.changeLists + Collection listNames = lists.collect { it.name } + assertEquals "Change lists are different", changeLists.toSet(), listNames.toSet() + assertEquals "Wrong active changelist", activeChangelist, changeListManager.defaultChangeList.name +} diff --git a/plugins/git4idea/test-features/git4idea/GeneralStepdefs.groovy b/plugins/git4idea/test-features/git4idea/GeneralStepdefs.groovy new file mode 100644 index 000000000000..9ce5cd9b073a --- /dev/null +++ b/plugins/git4idea/test-features/git4idea/GeneralStepdefs.groovy @@ -0,0 +1,47 @@ +package git4idea +import com.intellij.dvcs.test.MockProject +import com.intellij.openapi.util.Disposer +import com.intellij.openapi.util.io.FileUtil +import git4idea.test.GitTestImpl +import git4idea.test.GitTestPlatformFacade + +import static com.intellij.dvcs.test.Executor.cd +import static com.intellij.dvcs.test.Executor.mkdir +import static com.intellij.dvcs.test.Executor.touch +import static cucumber.runtime.groovy.EN.Given +import static cucumber.runtime.groovy.Hooks.After +import static cucumber.runtime.groovy.Hooks.Before +import static git4idea.GitCucumberWorld.* +import static git4idea.test.GitExecutor.git +import static git4idea.test.GitScenarios.checkout +import static git4idea.test.GitTestInitUtil.createRepository + +/** + * General step definitions and hooks used by all cucumber tests. + * + * @author Kirill Likhodedov + */ + +Before() { + myTestRoot = FileUtil.createTempDirectory("", "").getPath() + cd myTestRoot + myProjectRoot = mkdir ("project") + myProject = new MockProject(myProjectRoot) + myPlatformFacade = new GitTestPlatformFacade() + myGit = new GitTestImpl() + + cd(myProjectRoot) + myRepository = createRepository(myProjectRoot, myPlatformFacade, myProject) +} + +After() { + FileUtil.delete(new File(myTestRoot)) + Disposer.dispose(myProject) +} + +Given(~'^file (.*) on master:$') { String filename, String content -> + checkout(myRepository, "master") + touch(filename, content) + git("add $filename") + git("commit -m 'adding $filename'") +} \ No newline at end of file diff --git a/plugins/git4idea/test-features/git4idea/cherry-pick-auto-commit.feature b/plugins/git4idea/test-features/git4idea/cherry-pick-auto-commit.feature new file mode 100644 index 000000000000..92ed5c7d7866 --- /dev/null +++ b/plugins/git4idea/test-features/git4idea/cherry-pick-auto-commit.feature @@ -0,0 +1,28 @@ +Feature: Git Cherry-Pick When Auto-Commit is selected + + Background: + Given enabled auto-commit in the settings + Given file file.txt on master: + """ + first line + + last line (space is to have possibility to avoid conflicts) + """ + Given branch "feature" with commit "fix_1" by "John Bro" modifying file.txt: + """ + first line + + last line on branch feature + """ + + Scenario: Simple cherry-pick + When I cherry-pick the commit "fix_1" + Then the last commit is + """ + fix_1 + (cherry picked from commit #hash) + """ + And notification "Cherry-pick successful" is shown + And no new changelists are created + + diff --git a/plugins/git4idea/test-stepdefs/git4idea/GitCucumberWorld.java b/plugins/git4idea/test-stepdefs/git4idea/GitCucumberWorld.java new file mode 100644 index 000000000000..375c000f9ce5 --- /dev/null +++ b/plugins/git4idea/test-stepdefs/git4idea/GitCucumberWorld.java @@ -0,0 +1,22 @@ +package git4idea; + +import com.intellij.dvcs.test.MockProject; +import git4idea.commands.Git; +import git4idea.repo.GitRepository; + +/** + *

The container of test environment variables which should be visible from any step definition script.

+ *

Most of the fields are populated in the Before hook of the {@link GeneralStepdefs}.

+ * + * @author Kirill Likhodedov + */ +public class GitCucumberWorld { + + public static String myTestRoot; + public static String myProjectRoot; + public static MockProject myProject; + public static GitPlatformFacade myPlatformFacade; + public static Git myGit; + public static GitRepository myRepository; + +} diff --git a/plugins/git4idea/testFramework/git4idea/test/GitLightTest.groovy b/plugins/git4idea/testFramework/git4idea/test/GitLightTest.groovy index 577328ed0b42..d2cf7886dc81 100644 --- a/plugins/git4idea/testFramework/git4idea/test/GitLightTest.groovy +++ b/plugins/git4idea/testFramework/git4idea/test/GitLightTest.groovy @@ -16,13 +16,11 @@ package git4idea.test import com.intellij.dvcs.test.MockProject -import com.intellij.dvcs.test.MockVirtualFile import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.io.FileUtil import git4idea.GitPlatformFacade import git4idea.commands.Git import git4idea.repo.GitRepository -import git4idea.repo.GitRepositoryImpl import org.junit.After import org.junit.Before /** @@ -34,30 +32,26 @@ import org.junit.Before * * @author Kirill Likhodedov */ -@Mixin(GitExecutor) -class GitLightTest { - - private static final String USER_NAME = "John Doe"; - private static final String USER_EMAIL = "John.Doe@example.com"; +class GitLightTest extends GitExecutor { /** * The file system root of test files. * Automatically deleted on {@link #tearDown()}. * Tests should create new files only inside this directory. */ - protected String myTestRoot + public String myTestRoot /** * The file system root of the project. All project should locate inside this directory. */ - protected String myProjectRoot + public String myProjectRoot - protected MockProject myProject - protected GitPlatformFacade myPlatformFacade - protected Git myGit + public MockProject myProject + public GitPlatformFacade myPlatformFacade + public Git myGit @Before - protected void setUp() { + public void setUp() { myTestRoot = FileUtil.createTempDirectory("", "").getPath() cd myTestRoot myProjectRoot = mkdir ("project") @@ -72,26 +66,8 @@ class GitLightTest { Disposer.dispose(myProject) } - protected GitRepository createRepository(String rootDir) { - initRepo(rootDir) - - // TODO this smells hacky - // the constructor and notifyListeners() should probably be private - // getPresentableUrl should probably be final, and we should have a better VirtualFile implementation for tests. - GitRepository repository = new GitRepositoryImpl(new MockVirtualFile(rootDir), myPlatformFacade, myProject, myProject, true) { - @Override - protected void notifyListeners() { - } - - @Override - String getPresentableUrl() { - return rootDir; - } - } - - registerRepository(repository) - - return repository + public GitRepository createRepository(String rootDir) { + return GitTestInitUtil.createRepository(rootDir, myPlatformFacade, myProject) } /** @@ -103,23 +79,4 @@ class GitLightTest { cd source git("remote add $targetName $myTestRoot/$target"); } - - private void registerRepository(GitRepositoryImpl repository) { - ((GitTestRepositoryManager)myPlatformFacade.getRepositoryManager(myProject)).add(repository) - } - - private void initRepo(String repoRoot) { - cd repoRoot - git("init") - setupUsername(); - touch("file.txt") - git("add file.txt") - git("commit -m initial") - } - - private void setupUsername() { - git("config user.name $USER_NAME") - git("config user.email $USER_EMAIL") - } - } diff --git a/plugins/git4idea/testFramework/git4idea/test/GitTestImpl.groovy b/plugins/git4idea/testFramework/git4idea/test/GitTestImpl.groovy index 2593e631f4ee..fddc63797e4c 100644 --- a/plugins/git4idea/testFramework/git4idea/test/GitTestImpl.groovy +++ b/plugins/git4idea/testFramework/git4idea/test/GitTestImpl.groovy @@ -197,7 +197,7 @@ public class GitTestImpl implements Git { @NotNull String hash, boolean autoCommit, @NotNull GitLineHandlerListener... listeners) { - throw new UnsupportedOperationException(); + execute(repository, "cherry-pick -x ${autoCommit ? "" : "-n"} $hash") } @NotNull diff --git a/plugins/git4idea/testFramework/git4idea/test/GitTestInitUtil.groovy b/plugins/git4idea/testFramework/git4idea/test/GitTestInitUtil.groovy new file mode 100644 index 000000000000..850323ee78dd --- /dev/null +++ b/plugins/git4idea/testFramework/git4idea/test/GitTestInitUtil.groovy @@ -0,0 +1,61 @@ +package git4idea.test + +import com.intellij.dvcs.test.MockVirtualFile +import com.intellij.openapi.project.Project +import git4idea.GitPlatformFacade +import git4idea.repo.GitRepository +import git4idea.repo.GitRepositoryImpl + +/** + * + * @author Kirill Likhodedov + */ +class GitTestInitUtil { + + private static final String USER_NAME = "John Doe"; + private static final String USER_EMAIL = "John.Doe@example.com"; + + /** + * Init, set up username and make initial commit. + * @param repoRoot + */ + public static void initRepo(String repoRoot) { + com.intellij.dvcs.test.Executor.cd repoRoot + git4idea.test.GitExecutor.git("init") + setupUsername(); + com.intellij.dvcs.test.Executor.touch("initial.txt") + git4idea.test.GitExecutor.git("add initial.txt") + git4idea.test.GitExecutor.git("commit -m initial") + } + + public static void setupUsername() { + git4idea.test.GitExecutor.git("config user.name $USER_NAME") + git4idea.test.GitExecutor.git("config user.email $USER_EMAIL") + } + + public static GitRepository createRepository(String rootDir, GitPlatformFacade platformFacade, Project project) { + GitTestInitUtil.initRepo(rootDir) + + // TODO this smells hacky + // the constructor and notifyListeners() should probably be private + // getPresentableUrl should probably be final, and we should have a better VirtualFile implementation for tests. + GitRepository repository = new GitRepositoryImpl(new MockVirtualFile(rootDir), platformFacade, project, project, true) { + @Override + protected void notifyListeners() { + } + + @Override + String getPresentableUrl() { + return rootDir; + } + } + + registerRepository(repository, platformFacade, project) + + return repository + } + + private static void registerRepository(GitRepository repository, GitPlatformFacade platformFacade, Project project) { + ((GitTestRepositoryManager)platformFacade.getRepositoryManager(project)).add(repository) + } +}