[Mercurial Tests] Introduced HgSingleUserTestCase, HgCollaborativeTestCase, HgTestRep...
authorKirill Likhodedov <kirill.likhodedov@jetbrains.com>
Wed, 28 Jul 2010 07:55:17 +0000 (11:55 +0400)
committerKirill Likhodedov <kirill.likhodedov@jetbrains.com>
Wed, 28 Jul 2010 07:55:17 +0000 (11:55 +0400)
18 files changed:
plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgAbstractTestCase.java
plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgAddTestCase.java
plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgCollaborativeTestCase.java [new file with mode: 0644]
plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgCopyTestCase.java
plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgDeleteTestCase.java
plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgFromClonedTestCase.java
plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgHistoryTestCase.java
plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgLogTestCase.java
plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgMergeTestCase.java [new file with mode: 0644]
plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgMoveTestCase.java
plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgPushTestCase.java [new file with mode: 0644]
plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgRenameTestCase.java
plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgResolveConflictTestCase.java
plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgRevertTestCase.java
plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgSingleUserTestCase.java [new file with mode: 0644]
plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgTestChangeListManager.java [moved from plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/TestChangeListManager.java with 90% similarity]
plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgTestOutputParser.java [new file with mode: 0644]
plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgTestRepository.java [new file with mode: 0644]

index bf6c44932ee223dcead468ef631a3e331a5462f6..d29c536e8b59386005b2bc2884035e6bbb437f3d 100644 (file)
@@ -23,6 +23,7 @@ import com.intellij.testFramework.AbstractVcsTestCase;
 import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory;
 import com.intellij.testFramework.fixtures.TempDirTestFixture;
 import com.intellij.vcsUtil.VcsUtil;
+import org.jetbrains.annotations.Nullable;
 import org.testng.annotations.BeforeMethod;
 import org.zmlx.hg4idea.HgFile;
 import org.zmlx.hg4idea.HgVcs;
@@ -38,10 +39,6 @@ public abstract class HgAbstractTestCase extends AbstractVcsTestCase {
 
   public static final String HG_EXECUTABLE_PATH = "IDEA_TEST_HG_EXECUTABLE_PATH";
 
-  protected File myProjectRepo;
-  protected TempDirTestFixture myTempDirTestFixture;
-  protected TestChangeListManager myChangeListManager;
-
   // some shortcuts to use in tests
   protected static final String AFILE = "a.txt";
   protected static final String BDIR = "b";
@@ -50,83 +47,92 @@ public abstract class HgAbstractTestCase extends AbstractVcsTestCase {
   protected static final String FILE_CONTENT = "Sample file content.";
   protected static final String FILE_CONTENT_2 = "some other file content";
 
+  protected File myProjectDir; // location of the project repository. Initialized differently in each test: by init or by clone.
+  protected HgTestChangeListManager myChangeListManager;
+
   @BeforeMethod
   protected void setUp() throws Exception {
-    setHGExecutablePath();
-
-    myTempDirTestFixture = IdeaTestFixtureFactory.getFixtureFactory().createTempDirTestFixture();
-    myTempDirTestFixture.setUp();
-    myProjectRepo = new File(myTempDirTestFixture.getTempDirPath());
-
-    ProcessOutput processOutput = runHg(myProjectRepo, "init");
-    verify(processOutput);
-    initProject(myProjectRepo);
-    activateVCS(HgVcs.VCS_NAME);
-
-    myChangeListManager = new TestChangeListManager(myProject);
-
-    enableSilentOperation(VcsConfiguration.StandardConfirmation.ADD);
-    enableSilentOperation(VcsConfiguration.StandardConfirmation.REMOVE);
-  }
-
-  protected void setHGExecutablePath() {
     // setting hg executable
     String exec = System.getenv(HG_EXECUTABLE_PATH);
-    System.out.println("exec: " + exec);
     if (exec != null) {
-      System.out.println("Using external");
       myClientBinaryPath = new File(exec);
     }
     if (exec == null || !myClientBinaryPath.exists()) {
-      System.out.println("Using checked in");
-      File pluginRoot = new File(PluginPathManager.getPluginHomePath(HgVcs.VCS_NAME));
+      final File pluginRoot = new File(PluginPathManager.getPluginHomePath(HgVcs.VCS_NAME));
       myClientBinaryPath = new File(pluginRoot, "testData/bin");
     }
-
     HgVcs.setTestHgExecutablePath(myClientBinaryPath.getPath());
+
+    myTraceClient = true;
+  }
+
+  /**
+   * Creates a new Mercurial repository in a temporary test directory.
+   * @return created repository
+   */
+  protected HgTestRepository createRepository() throws Exception {
+    final TempDirTestFixture dirFixture = createFixtureDir();
+    final File repo = new File(dirFixture.getTempDirPath());
+    ProcessOutput processOutput = runHg(repo, "init");
+    verify(processOutput);
+    return new HgTestRepository(this, dirFixture);
+  }
+
+  protected static TempDirTestFixture createFixtureDir() throws Exception {
+    final TempDirTestFixture fixture = IdeaTestFixtureFactory.getFixtureFactory().createTempDirTestFixture();
+    fixture.setUp();
+    return fixture;
+  }
+
+  protected void enableSilentOperation(final VcsConfiguration.StandardConfirmation op) {
+    setStandardConfirmation(HgVcs.VCS_NAME, op, VcsShowConfirmationOption.Value.DO_ACTION_SILENTLY);
+  }
+
+  protected void disableSilentOperation(final VcsConfiguration.StandardConfirmation op) {
+    setStandardConfirmation(HgVcs.VCS_NAME, op, VcsShowConfirmationOption.Value.DO_NOTHING_SILENTLY);
   }
 
   /**
    * Runs the hg command.
+   *
    * @param commandLine the name of the command and its arguments.
    */
   protected ProcessOutput runHgOnProjectRepo(String... commandLine) throws IOException {
-    return runHg(myProjectRepo, commandLine);
+    return runHg(myProjectDir, commandLine);
   }
 
+  /**
+   * Verifies the status of the file calling native 'hg status' command.
+   *
+   * @param status status as returned by {@link #added(java.lang.String)} and other methods.
+   * @throws IOException
+   */
+  protected void verifyStatus(String... status) throws IOException {
+    verify(runHg(myProjectDir, "status"), status);
+}
   /**
    * Calls "hg add ." to add everything to the index.
    */
   protected ProcessOutput addAll() throws IOException {
-    return runHgOnProjectRepo("add", ".");
+    return runHg(myProjectDir, "add", ".");
   }
 
   /**
    * Calls "hg commit -m &lt;commitMessage&gt;" to commit the index.
    */
   protected ProcessOutput commitAll(String commitMessage) throws IOException {
-    return runHgOnProjectRepo("commit", "-m", commitMessage);
+    return runHg(myProjectDir, "commit", "-m", commitMessage);
   }
 
   protected HgFile getHgFile(String... filepath) {
-    File fileToInclude = myProjectRepo;
+    File fileToInclude = myProjectDir;
     for (String path : filepath) {
       fileToInclude = new File(fileToInclude, path);
     }
     return new HgFile(myWorkingCopyDir, fileToInclude);
   }
+                       
 
-  protected void enableSilentOperation(final VcsConfiguration.StandardConfirmation op) {
-    setStandardConfirmation(
-      HgVcs.VCS_NAME, op, VcsShowConfirmationOption.Value.DO_ACTION_SILENTLY
-    );
-  }
-
-  protected void disableSilentOperation(final VcsConfiguration.StandardConfirmation op) {
-    setStandardConfirmation(
-      HgVcs.VCS_NAME, op, VcsShowConfirmationOption.Value.DO_NOTHING_SILENTLY
-    );
-  }
 
   protected VirtualFile makeFile(File file) throws IOException {
     file.createNewFile();
@@ -135,8 +141,13 @@ public abstract class HgAbstractTestCase extends AbstractVcsTestCase {
     return VcsUtil.getVirtualFile(file);
   }
 
-  protected ProcessOutput runHg(File aHgRepository, String... commandLine) throws IOException {
-    return runClient(HgVcs.HG_EXECUTABLE_FILE_NAME, null, aHgRepository, commandLine);
+  /**
+   * Executes the given native Mercurial command with parameters in the given working directory.
+   * @param workingDir  working directory where the command will be executed. May be null.
+   * @param commandLine command and parameters (e.g. 'status, -m').
+   */
+  protected ProcessOutput runHg(@Nullable File workingDir, String... commandLine) throws IOException {
+    return runClient(HgVcs.HG_EXECUTABLE_FILE_NAME, null, workingDir, commandLine);
   }
 
   protected File fillFile(File aParentDir, String[] filePath, String fileContents) throws FileNotFoundException {
@@ -157,49 +168,4 @@ public abstract class HgAbstractTestCase extends AbstractVcsTestCase {
     return outputFile;
   }
 
-  /**
-   * Verifies the status of the file calling native 'hg status' command.
-   * @param status status as returned by {@link #added(java.lang.String)} and other methods.
-   * @throws IOException
-   */
-  protected void verifyStatus(String... status) throws IOException {
-    verify(runHgOnProjectRepo("status"), status);
-  }
-
-  public static String added(String... path) {
-    return "A " + path(path);
-  }
-
-  public static String removed(String... path) {
-    return "R " + path(path);
-  }
-
-  public static String unknown(String... path) {
-    return "? " + path(path);
-  }
-
-  public static String modified(String... path) {
-    return "M " + path(path);
-  }
-
-  public static String missing(String... path) {
-    return "! " + path(path);
-  }
-
-  public static String path(String... line) {
-    StringBuilder builder = new StringBuilder();
-
-    int linePartCount = line.length;
-
-    for (int i = 0; i < linePartCount; i++) {
-      String linePart = line[i];
-      builder.append(linePart);
-
-      if (i < linePartCount - 1) {
-        builder.append(File.separator);
-      }
-    }
-
-    return builder.toString();
-  }
 }
index 9f945b1270335d98596e547fb16a3ea822f325eb..4d0918f582af1321d4e87428ac3fa447c52f51d3 100644 (file)
@@ -15,10 +15,12 @@ package org.zmlx.hg4idea.test;
 import com.intellij.openapi.vfs.VirtualFile;
 import org.testng.annotations.Test;
 
+import static org.zmlx.hg4idea.test.HgTestOutputParser.added;
+
 /**
  * Tests adding files to the Mercurial repository.
  */
-public class HgAddTestCase extends HgAbstractTestCase {
+public class HgAddTestCase extends HgSingleUserTestCase {
 
   /**
    * 1. Create a file in the file system.
@@ -27,7 +29,7 @@ public class HgAddTestCase extends HgAbstractTestCase {
    */
   @Test
   public void fileAddedViaChangeListShouldBeAddedToHg() throws Exception {
-    final VirtualFile vf = myTempDirTestFixture.createFile(AFILE);
+    final VirtualFile vf = myRepo.getDirFixture().createFile(AFILE);
     myChangeListManager.addUnversionedFilesToVcs(vf);
     verifyStatus(added(AFILE));
     myChangeListManager.checkFilesAreInList(true, vf);
@@ -51,9 +53,9 @@ public class HgAddTestCase extends HgAbstractTestCase {
    */
   @Test
   public void filesInDirsAddedViaChangeListShouldBeAddedToHg() throws Exception {
-    final VirtualFile afile = myTempDirTestFixture.createFile(AFILE);
-    final VirtualFile bdir = myTempDirTestFixture.findOrCreateDir(BDIR);
-    final VirtualFile bfile = myTempDirTestFixture.createFile(BFILE_PATH);
+    final VirtualFile afile = myRepo.getDirFixture().createFile(AFILE);
+    final VirtualFile bdir = myRepo.getDirFixture().findOrCreateDir(BDIR);
+    final VirtualFile bfile = myRepo.getDirFixture().createFile(BFILE_PATH);
     myChangeListManager.addUnversionedFilesToVcs(afile, bdir, bfile);
     verifyStatus(added(AFILE), added(BFILE_PATH));
     myChangeListManager.checkFilesAreInList(true, afile, bfile);
diff --git a/plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgCollaborativeTestCase.java b/plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgCollaborativeTestCase.java
new file mode 100644 (file)
index 0000000..b5c2925
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2000-2010 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.zmlx.hg4idea.test;
+
+import com.intellij.execution.process.ProcessOutput;
+import com.intellij.openapi.vcs.VcsConfiguration;
+import com.intellij.testFramework.fixtures.TempDirTestFixture;
+import org.testng.annotations.BeforeMethod;
+import org.zmlx.hg4idea.HgVcs;
+
+import java.io.File;
+
+/**
+ * The parent of all tests, where at least two repositories communicate with each other.
+ * This is used to test collaborative tasks, such as push, pull, merge and others.
+ * @author Kirill Likhodedov
+ */
+public class HgCollaborativeTestCase extends HgAbstractTestCase {
+
+  protected HgTestRepository myParentRepo;
+  protected HgTestRepository myRepo;
+
+  @BeforeMethod
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+
+    myParentRepo = createRepository();
+    myRepo = cloneFrom(myParentRepo);
+
+    myProjectDir = new File(myRepo.getDirFixture().getTempDirPath());
+
+    initProject(myProjectDir);
+    activateVCS(HgVcs.VCS_NAME);
+    myChangeListManager = new HgTestChangeListManager(myProject);
+
+    enableSilentOperation(VcsConfiguration.StandardConfirmation.ADD);
+    enableSilentOperation(VcsConfiguration.StandardConfirmation.REMOVE);
+  }
+
+  /**
+   * Clones a repository from the given one. New repository is located in a temporary test directory.
+   * @param parent repository to clone from.
+   * @return New repository cloned from the given parent.
+   */
+  protected HgTestRepository cloneFrom(HgTestRepository parent) throws Exception {
+    final TempDirTestFixture dirFixture = createFixtureDir();
+    final ProcessOutput processOutput = runHg(null, "clone", parent.getDirFixture().getTempDirPath(), dirFixture.getTempDirPath());
+    verify(processOutput);
+    return new HgTestRepository(this, dirFixture);
+  }
+
+}
index f58ce982a6b27cd3570e5492a85341dfb5a359a8..9dfbab6b8bf308c4659d4dd2b5d9f444062d9e56 100644 (file)
@@ -17,14 +17,14 @@ import org.testng.annotations.Test;
 
 import java.io.File;
 
-public class HgCopyTestCase extends HgAbstractTestCase {
+public class HgCopyTestCase extends HgSingleUserTestCase {
 
   @Test
   public void testCopyUnmodifiedFile() throws Exception {
     VirtualFile file = createFileInCommand("a.txt", "new file content");
     runHgOnProjectRepo("commit", "-m", "added file");
     copyFileInCommand(file, "b.txt");
-    verify(runHgOnProjectRepo("status"), added("b.txt"));
+    verify(runHgOnProjectRepo("status"), HgTestOutputParser.added("b.txt"));
   }
 
   @Test
@@ -32,16 +32,16 @@ public class HgCopyTestCase extends HgAbstractTestCase {
     VirtualFile file = createFileInCommand("a.txt", "new file content");
     runHgOnProjectRepo("commit", "-m", "added file");
     editFileInCommand(myProject, file, "newer content");
-    verify(runHgOnProjectRepo("status"), modified("a.txt"));
+    verify(runHgOnProjectRepo("status"), HgTestOutputParser.modified("a.txt"));
     copyFileInCommand(file, "b.txt");
-    verify(runHgOnProjectRepo("status"), modified("a.txt"), added("b.txt"));
+    verify(runHgOnProjectRepo("status"), HgTestOutputParser.modified("a.txt"), HgTestOutputParser.added("b.txt"));
   }
 
   @Test
   public void testCopyUnversionedFile() throws Exception {
     VirtualFile file = makeFile(new File(myWorkingCopyDir.getPath(), "a.txt"));
     copyFileInCommand(file, "b.txt");
-    verify(runHgOnProjectRepo("status"), unknown("a.txt"), unknown("b.txt"));
+    verify(runHgOnProjectRepo("status"), HgTestOutputParser.unknown("a.txt"), HgTestOutputParser.unknown("b.txt"));
   }
 
   @Test
@@ -50,7 +50,7 @@ public class HgCopyTestCase extends HgAbstractTestCase {
     runHgOnProjectRepo("commit", "-m", "added file");
     copyFileInCommand(file, "b.txt");
     copyFileInCommand(file, "c.txt");
-    verify(runHgOnProjectRepo("status"), added("b.txt"), added("c.txt"));
+    verify(runHgOnProjectRepo("status"), HgTestOutputParser.added("b.txt"), HgTestOutputParser.added("c.txt"));
   }
 
   @Test
@@ -59,7 +59,7 @@ public class HgCopyTestCase extends HgAbstractTestCase {
     createFileInCommand(parent, "a.txt", "new file content");
     runHgOnProjectRepo("commit", "-m", "added file");
     copyFileInCommand(parent, "org");
-    verify(runHgOnProjectRepo("status"), added("org", "a.txt"));
+    verify(runHgOnProjectRepo("status"), HgTestOutputParser.added("org", "a.txt"));
   }
 
 }
index b118ffc62d2469a14dabc6b8a84d67892a633e05..070cf7ea14e97c01e73402b8b6efe26aa6df3e86 100644 (file)
@@ -18,20 +18,20 @@ import org.testng.annotations.Test;
 
 import java.io.File;
 
-public class HgDeleteTestCase extends HgAbstractTestCase {
+public class HgDeleteTestCase extends HgSingleUserTestCase {
 
   @Test
   public void testDeleteUnmodifiedFile() throws Exception {
     VirtualFile file = createFileInCommand("a.txt", "new file content");
     runHgOnProjectRepo("commit", "-m", "added file");
     deleteFileInCommand(file);
-    verify(runHgOnProjectRepo("status"), removed("a.txt"));
+    verify(runHgOnProjectRepo("status"), HgTestOutputParser.removed("a.txt"));
   }
 
   @Test
   public void testDeleteUnversionedFile() throws Exception {
     VirtualFile file = makeFile(new File(myWorkingCopyDir.getPath(), "a.txt"));
-    verify(runHgOnProjectRepo("status"), unknown("a.txt"));
+    verify(runHgOnProjectRepo("status"), HgTestOutputParser.unknown("a.txt"));
     deleteFileInCommand(file);
     Assert.assertFalse(file.exists());
   }
@@ -48,9 +48,9 @@ public class HgDeleteTestCase extends HgAbstractTestCase {
     VirtualFile file = createFileInCommand("a.txt", "new file content");
     runHgOnProjectRepo("commit", "-m", "added file");
     editFileInCommand(myProject, file, "even newer content");
-    verify(runHgOnProjectRepo("status"), modified("a.txt"));
+    verify(runHgOnProjectRepo("status"), HgTestOutputParser.modified("a.txt"));
     deleteFileInCommand(file);
-    verify(runHgOnProjectRepo("status"), removed("a.txt"));
+    verify(runHgOnProjectRepo("status"), HgTestOutputParser.removed("a.txt"));
   }
 
   @Test
@@ -59,7 +59,7 @@ public class HgDeleteTestCase extends HgAbstractTestCase {
     createFileInCommand(parent, "a.txt", "new file content");
     runHgOnProjectRepo("commit", "-m", "added file");
     deleteFileInCommand(parent);
-    verify(runHgOnProjectRepo("status"), removed("com", "a.txt"));
+    verify(runHgOnProjectRepo("status"), HgTestOutputParser.removed("com", "a.txt"));
   }
 
 }
index 05a632198a3b5c34b4b82bb4d7063bc944d89e81..2d00b2ee7bf57d0b4e1452f565f2b6a569b5218a 100644 (file)
@@ -12,7 +12,6 @@
 // limitations under the License.
 package org.zmlx.hg4idea.test;
 
-import com.intellij.openapi.vcs.VcsConfiguration;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory;
 import com.intellij.testFramework.fixtures.TempDirTestFixture;
@@ -25,7 +24,10 @@ import java.io.File;
 
 import static org.testng.Assert.assertTrue;
 
-public class HgFromClonedTestCase extends HgAbstractTestCase {
+/**
+ * TODO: substitute by new interface from HgCollaborativeTestCase and HgTestRepository.
+ */
+public class HgFromClonedTestCase extends HgCollaborativeTestCase {
 
   protected File remoteRepo;
   protected File projectRepo;
@@ -34,8 +36,9 @@ public class HgFromClonedTestCase extends HgAbstractTestCase {
   protected VirtualFile projectRepoVirtualFile;
 
   @BeforeMethod
+  @Override
   public void setUp() throws Exception {
-    setHGExecutablePath();
+    super.setUp();
 
     remoteRepoDir = IdeaTestFixtureFactory.getFixtureFactory().createTempDirTestFixture();
     projectRepoDir = IdeaTestFixtureFactory.getFixtureFactory().createTempDirTestFixture();
@@ -47,9 +50,6 @@ public class HgFromClonedTestCase extends HgAbstractTestCase {
     activateVCS(HgVcs.VCS_NAME);
 
     projectRepoVirtualFile = VcsUtil.getVirtualFile(projectRepo);
-
-    enableSilentOperation(VcsConfiguration.StandardConfirmation.ADD);
-    enableSilentOperation(VcsConfiguration.StandardConfirmation.REMOVE);
   }
 
   private File cloneRemoteRepository(TempDirTestFixture projectRepoDir, File remoteRepo, String destination) throws Exception {
@@ -73,7 +73,7 @@ public class HgFromClonedTestCase extends HgAbstractTestCase {
     File aFile = fillFile(remoteRepo, new String[]{"com", "a.txt"}, "file contents");
 
     verify(runHg(remoteRepo, "add", aFile.getPath()));
-    verify(runHg(remoteRepo, "status"), added("com", "a.txt"));
+    verify(runHg(remoteRepo, "status"), HgTestOutputParser.added("com", "a.txt"));
     verify(runHg(remoteRepo, "commit", "-m", "initial contents"));
 
     return remoteRepo;
index b0d3be8157d0bbeace4f116a45780448c50e57c8..cf398c9c4687eef3f8df3bac7e14d426a545a753 100644 (file)
@@ -17,7 +17,7 @@ import static org.testng.Assert.assertTrue;
 /**
  * HgHistoryTestCase tests retrieving file history and specific revisions.
  */
-public class HgHistoryTestCase extends HgAbstractTestCase {
+public class HgHistoryTestCase extends HgSingleUserTestCase {
 
   /**
    * 1. Make two versions of a file (create, add, commit, modify, commit).
@@ -27,11 +27,11 @@ public class HgHistoryTestCase extends HgAbstractTestCase {
   @Test
   public void testCurrentAndPreviousRevisions() throws Exception {
     int versions = 0;
-    fillFile(myProjectRepo, new String[]{ AFILE }, FILE_CONTENT);
+    fillFile(myProjectDir, new String[]{ AFILE }, FILE_CONTENT);
     addAll();
     commitAll("initial content");
     versions++;
-    fillFile(myProjectRepo, new String[] { AFILE} , FILE_CONTENT_2);
+    fillFile(myProjectDir, new String[] { AFILE} , FILE_CONTENT_2);
     commitAll("updated content");
     versions++;
 
@@ -58,7 +58,7 @@ public class HgHistoryTestCase extends HgAbstractTestCase {
   public void renameShouldPreserveFileHistory() throws Exception {
     int versions = 0;
 
-    fillFile(myProjectRepo, new String[]{ AFILE }, FILE_CONTENT);
+    fillFile(myProjectDir, new String[]{ AFILE }, FILE_CONTENT);
     addAll();
     commitAll("initial content");
     versions++;
@@ -67,7 +67,7 @@ public class HgHistoryTestCase extends HgAbstractTestCase {
     commitAll("file renamed");
     versions++;
 
-    fillFile(myProjectRepo, new String[]{ BFILE }, FILE_CONTENT_2);
+    fillFile(myProjectDir, new String[]{ BFILE }, FILE_CONTENT_2);
     commitAll("updated content");
     versions++;
 
@@ -88,7 +88,7 @@ public class HgHistoryTestCase extends HgAbstractTestCase {
   }
 
   private VcsHistorySession getHistorySession(String relativePath) throws VcsException {
-    return HgVcs.getInstance(myProject).getVcsHistoryProvider().createSessionFor(VcsUtil.getFilePath(new File(myProjectRepo, relativePath), false));
+    return HgVcs.getInstance(myProject).getVcsHistoryProvider().createSessionFor(VcsUtil.getFilePath(new File(myProjectDir, relativePath), false));
   }
 
 }
index 581cb62e38fa775f9536b3a8d9ac4f073f5d044a..65e02297031a4212724bbd7deab78442291fa03c 100644 (file)
@@ -20,15 +20,15 @@ import java.util.List;
 
 import static org.testng.Assert.assertEquals;
 
-public class HgLogTestCase extends HgAbstractTestCase {
+public class HgLogTestCase extends HgSingleUserTestCase {
   
   @Test
   public void testCommitMessagesWithMultipleLines() throws Exception {
-    fillFile(myProjectRepo, new String[]{"file.txt"}, "initial contents");
+    fillFile(myProjectDir, new String[]{"file.txt"}, "initial contents");
     runHgOnProjectRepo("add", ".");
     runHgOnProjectRepo("commit", "-m", "initial\ncontents");
 
-    fillFile(myProjectRepo, new String[]{"file.txt"}, "updated contents");
+    fillFile(myProjectDir, new String[]{"file.txt"}, "updated contents");
     runHgOnProjectRepo("commit", "-m", "updated\ncontents");
 
     List<HgFileRevision> fileLog = new HgLogCommand(myProject).execute(getHgFile("file.txt"), 10, false);
diff --git a/plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgMergeTestCase.java b/plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgMergeTestCase.java
new file mode 100644 (file)
index 0000000..99f3a19
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2008-2010 Victor Iacoban
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software distributed under
+// the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+// either express or implied. See the License for the specific language governing permissions and
+// limitations under the License.
+package org.zmlx.hg4idea.test;
+
+import org.testng.annotations.Test;
+
+/**
+ * Tests adding files to the Mercurial repository.
+ */
+public class HgMergeTestCase extends HgCollaborativeTestCase {
+
+  @Test
+  public void testRevertUncommittedMerge() throws Exception {
+    HgTestRepository central = createRepository();
+    HgTestRepository worker = cloneFrom(central);
+  }
+
+
+}
index af9e863d2bef996a9928098528216b457a55bb3a..97dfb4a7d82f10271540888aac7eb27fbaa85b47 100644 (file)
@@ -17,7 +17,7 @@ import org.testng.annotations.Test;
 
 import java.io.File;
 
-public class HgMoveTestCase extends HgAbstractTestCase {
+public class HgMoveTestCase extends HgSingleUserTestCase {
 
   @Test
   public void testMoveNewFile() throws Exception {
@@ -27,7 +27,7 @@ public class HgMoveTestCase extends HgAbstractTestCase {
     VirtualFile parent2 = createDirInCommand(myWorkingCopyDir, "org");
     moveFileInCommand(file, parent2);
 
-    verify(runHgOnProjectRepo("status"), added("org", "a.txt"));
+    verify(runHgOnProjectRepo("status"), HgTestOutputParser.added("org", "a.txt"));
   }
 
   @Test
@@ -39,7 +39,7 @@ public class HgMoveTestCase extends HgAbstractTestCase {
     VirtualFile parent2 = createDirInCommand(myWorkingCopyDir, "org");
     moveFileInCommand(file, parent2);
 
-    verify(runHgOnProjectRepo("status"), added("org", "a.txt"), removed("com", "a.txt"));
+    verify(runHgOnProjectRepo("status"), HgTestOutputParser.added("org", "a.txt"), HgTestOutputParser.removed("com", "a.txt"));
   }
 
   @Test
@@ -52,7 +52,7 @@ public class HgMoveTestCase extends HgAbstractTestCase {
     VirtualFile parent2 = createDirInCommand(myWorkingCopyDir, "org");
     moveFileInCommand(dir, parent2);
 
-    verify(runHgOnProjectRepo("status"), added("org", "zzz", "a.txt"), removed("com", "zzz", "a.txt"));
+    verify(runHgOnProjectRepo("status"), HgTestOutputParser.added("org", "zzz", "a.txt"), HgTestOutputParser.removed("com", "zzz", "a.txt"));
   }
 
   @Test
@@ -62,12 +62,12 @@ public class HgMoveTestCase extends HgAbstractTestCase {
     File unversionedFile = new File(parent1.getPath(), "a.txt");
     VirtualFile file = makeFile(unversionedFile);
 
-    verify(runHgOnProjectRepo("status"), unknown("com", "a.txt"));
+    verify(runHgOnProjectRepo("status"), HgTestOutputParser.unknown("com", "a.txt"));
 
     VirtualFile parent2 = createDirInCommand(myWorkingCopyDir, "org");
     moveFileInCommand(file, parent2);
 
-    verify(runHgOnProjectRepo("status"), unknown("org", "a.txt"));
+    verify(runHgOnProjectRepo("status"), HgTestOutputParser.unknown("org", "a.txt"));
   }
 
 }
diff --git a/plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgPushTestCase.java b/plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgPushTestCase.java
new file mode 100644 (file)
index 0000000..d7328ac
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2000-2010 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.zmlx.hg4idea.test;
+
+import com.intellij.openapi.vfs.VirtualFile;
+import org.testng.annotations.Test;
+import org.zmlx.hg4idea.command.HgCommandResult;
+import org.zmlx.hg4idea.command.HgErrorUtil;
+import org.zmlx.hg4idea.command.HgPushCommand;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+
+/**
+ * @author Kirill Likhodedov
+ */
+public class HgPushTestCase extends HgCollaborativeTestCase {
+
+  /**
+   * Tests 'push' using only native commands.
+   * This is to test the harness.
+   */
+  @Test
+  public void testNativeCommands() throws Exception {
+    myRepo.getDirFixture().createFile(AFILE);
+    myRepo.add();
+    myRepo.commit();
+    myRepo.push();
+
+    myParentRepo.update();
+    assertNotNull(myParentRepo.getDirFixture().getFile(AFILE));
+  }
+
+  /**
+   * Testing HgPushCommand:
+   * 1. Create a file, add to the VCS and commit via ChangeListManager.
+   * 2. Push via HgPushCommand.
+   * 3. Natively update parent repository.
+   * 4. Verify that the changes appeared there.
+   */
+  @Test
+  public void testHgPushCommand() throws Exception {
+   final VirtualFile vf = myRepo.getDirFixture().createFile(AFILE);
+    myChangeListManager.addUnversionedFilesToVcs(vf);
+    myChangeListManager.checkFilesAreInList(true, vf);
+    myChangeListManager.commitFiles(vf);
+
+    final HgPushCommand command = new HgPushCommand(myProject, myRepo.getDir(), myParentRepo.getDir().getUrl());
+    final HgCommandResult result = command.execute();
+    assertNotNull(result);
+    assertFalse(HgErrorUtil.isAbort(result));
+
+    myParentRepo.update();
+    assertNotNull(myParentRepo.getDirFixture().getFile(AFILE));
+  }
+
+}
index 8d8310071b1fa8ce313a7b74bba29327eab8c50d..fb02a4371fa2c1b1dc0ddf92a3413409415b0bfd 100644 (file)
@@ -17,14 +17,14 @@ import org.testng.annotations.Test;
 
 import java.io.File;
 
-public class HgRenameTestCase extends HgAbstractTestCase {
+public class HgRenameTestCase extends HgSingleUserTestCase {
 
   @Test
   public void testRenameUnmodifiedFile() throws Exception {
     VirtualFile file = createFileInCommand("a.txt", "new file content");
     runHgOnProjectRepo("commit", "-m", "added file");
     renameFileInCommand(file, "b.txt");
-    verify(runHgOnProjectRepo("status"), added("b.txt"), removed("a.txt"));
+    verify(runHgOnProjectRepo("status"), HgTestOutputParser.added("b.txt"), HgTestOutputParser.removed("a.txt"));
   }
 
   @Test
@@ -32,16 +32,16 @@ public class HgRenameTestCase extends HgAbstractTestCase {
     VirtualFile file = createFileInCommand("a.txt", "new file content");
     runHgOnProjectRepo("commit", "-m", "added file");
     editFileInCommand(myProject, file, "modified new file content");
-    verify(runHgOnProjectRepo("status"), modified("a.txt"));
+    verify(runHgOnProjectRepo("status"), HgTestOutputParser.modified("a.txt"));
     renameFileInCommand(file, "b.txt");
-    verify(runHgOnProjectRepo("status"), added("b.txt"), removed("a.txt"));
+    verify(runHgOnProjectRepo("status"), HgTestOutputParser.added("b.txt"), HgTestOutputParser.removed("a.txt"));
   }
 
   @Test
   public void testRenameNewFile() throws Exception {
     VirtualFile file = createFileInCommand("a.txt", "new file content");
     renameFileInCommand(file, "b.txt");
-    verify(runHgOnProjectRepo("status"), added("b.txt"));
+    verify(runHgOnProjectRepo("status"), HgTestOutputParser.added("b.txt"));
   }
 
   @Test
@@ -50,7 +50,7 @@ public class HgRenameTestCase extends HgAbstractTestCase {
     runHgOnProjectRepo("commit", "-m", "added file");
     renameFileInCommand(file, "b.txt");
     renameFileInCommand(file, "c.txt");
-    verify(runHgOnProjectRepo("status"), added("c.txt"), removed("a.txt"));
+    verify(runHgOnProjectRepo("status"), HgTestOutputParser.added("c.txt"), HgTestOutputParser.removed("a.txt"));
   }
 
   @Test
@@ -59,7 +59,7 @@ public class HgRenameTestCase extends HgAbstractTestCase {
     createFileInCommand(parent, "a.txt", "new file content");
     runHgOnProjectRepo("commit", "-m", "added file");
     renameFileInCommand(parent, "org");
-    verify(runHgOnProjectRepo("status"), added("org", "a.txt"), removed("com", "a.txt"));
+    verify(runHgOnProjectRepo("status"), HgTestOutputParser.added("org", "a.txt"), HgTestOutputParser.removed("com", "a.txt"));
   }
 
   @Test
@@ -68,20 +68,20 @@ public class HgRenameTestCase extends HgAbstractTestCase {
 
     File unversionedFile = new File(parent.getPath(), "a.txt");
     makeFile(unversionedFile);
-    verify(runHgOnProjectRepo("status"), unknown("com", "a.txt"));
+    verify(runHgOnProjectRepo("status"), HgTestOutputParser.unknown("com", "a.txt"));
 
     renameFileInCommand(parent, "org");
-    verify(runHgOnProjectRepo("status"), unknown("org", "a.txt"));
+    verify(runHgOnProjectRepo("status"), HgTestOutputParser.unknown("org", "a.txt"));
   }
 
   @Test
   public void testRenameUnversionedFile() throws Exception {
     File unversionedFile = new File(myWorkingCopyDir.getPath(), "a.txt");
     VirtualFile file = makeFile(unversionedFile);
-    verify(runHgOnProjectRepo("status"), unknown("a.txt"));
+    verify(runHgOnProjectRepo("status"), HgTestOutputParser.unknown("a.txt"));
 
     renameFileInCommand(file, "b.txt");
-    verify(runHgOnProjectRepo("status"), unknown("b.txt"));
+    verify(runHgOnProjectRepo("status"), HgTestOutputParser.unknown("b.txt"));
   }
 
 }
index bf5a0df75e61a3cec4e10c97ead65e2b21b5f517..cb0c76ce94922dc93e7183f82ae7e24e595fecd4 100644 (file)
@@ -17,7 +17,7 @@ import org.testng.Assert;
 import org.testng.annotations.Test;
 import org.zmlx.hg4idea.command.HgResolveCommand;
 
-public class HgResolveConflictTestCase extends HgAbstractTestCase {
+public class HgResolveConflictTestCase extends HgSingleUserTestCase {
 
   public static final String BASE = "one\n" +
     "conflicting\n" +
@@ -47,7 +47,7 @@ public class HgResolveConflictTestCase extends HgAbstractTestCase {
 
     runHgOnProjectRepo("--config", "ui.merge=internal:merge", "merge");
 
-    VirtualFile repoFile = makeFile(myProjectRepo);
+    VirtualFile repoFile = makeFile(myProjectDir);
     HgResolveCommand.MergeData data = new HgResolveCommand(myProject).getResolveData(repoFile, repoFile.findChild("conflicting"));
 
     Assert.assertEquals(data.getBase(), BASE.getBytes(),
index 674835517c0c434e05468ae579b4069c2f837f37..5450ab4e7c27f254b7dd1379e6c02949f92abf7d 100644 (file)
@@ -9,14 +9,14 @@ import java.nio.charset.Charset;
 
 import static org.testng.Assert.assertEquals;
 
-public class HgRevertTestCase extends HgAbstractTestCase {
+public class HgRevertTestCase extends HgSingleUserTestCase {
   @Test
   public void testRevertToCurrentRevision() throws Exception {
-    fillFile(myProjectRepo, new String[]{"file.txt"}, "initial contents");
+    fillFile(myProjectDir, new String[]{"file.txt"}, "initial contents");
     runHgOnProjectRepo("add", ".");
     runHgOnProjectRepo("commit", "-m", "initial contents");
 
-    fillFile(myProjectRepo, new String[]{"file.txt"}, "new contents");
+    fillFile(myProjectDir, new String[]{"file.txt"}, "new contents");
 
     HgRevertCommand revertCommand = new HgRevertCommand(myProject);
     revertCommand.execute(getHgFile("file.txt"), null, false);
@@ -30,11 +30,11 @@ public class HgRevertTestCase extends HgAbstractTestCase {
 
   @Test
   public void testRevertToGivenRevision() throws Exception {
-    fillFile(myProjectRepo, new String[]{"file.txt"}, "initial contents");
+    fillFile(myProjectDir, new String[]{"file.txt"}, "initial contents");
     runHgOnProjectRepo("add", ".");
     runHgOnProjectRepo("commit", "-m", "initial contents");
 
-    fillFile(myProjectRepo, new String[]{"file.txt"}, "new contents");
+    fillFile(myProjectDir, new String[]{"file.txt"}, "new contents");
     runHgOnProjectRepo("commit", "-m", "new contents");
 
     HgRevertCommand revertCommand = new HgRevertCommand(myProject);
diff --git a/plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgSingleUserTestCase.java b/plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgSingleUserTestCase.java
new file mode 100644 (file)
index 0000000..abea09e
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2000-2010 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.zmlx.hg4idea.test;
+
+import com.intellij.openapi.vcs.VcsConfiguration;
+import org.testng.annotations.BeforeMethod;
+import org.zmlx.hg4idea.HgVcs;
+
+import java.io.File;
+
+/**
+ * HgSingleUserTestCase is the parent of test cases for single user workflow.
+ * It doesn't include collaborate tasks such as cloning, pushing, etc.
+ * @author Kirill Likhodedov
+ */
+public class HgSingleUserTestCase extends HgAbstractTestCase {
+
+  protected HgTestRepository myRepo;
+
+  @BeforeMethod
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+
+    myRepo = createRepository();
+    myProjectDir = new File(myRepo.getDirFixture().getTempDirPath());
+    
+    initProject(myProjectDir);
+    activateVCS(HgVcs.VCS_NAME);
+    myChangeListManager = new HgTestChangeListManager(myProject);
+
+    enableSilentOperation(VcsConfiguration.StandardConfirmation.ADD);
+    enableSilentOperation(VcsConfiguration.StandardConfirmation.REMOVE);
+  }
+
+}
\ No newline at end of file
similarity index 90%
rename from plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/TestChangeListManager.java
rename to plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgTestChangeListManager.java
index 791699be0f9f6b27c6c1bd62d3fbde2885543174..96bbc3ff97dbdebff150a02e52f796567ef51da0 100644 (file)
@@ -19,6 +19,7 @@ import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.vcs.changes.Change;
 import com.intellij.openapi.vcs.changes.ChangeListManagerImpl;
+import com.intellij.openapi.vcs.changes.LocalChangeList;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.util.containers.HashSet;
 import org.testng.Assert;
@@ -29,15 +30,17 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 
+import static org.testng.Assert.assertNotNull;
+
 /**
  * The ChangeListManagerImpl extension with some useful helper methods for tests.
  * @author Kirill Likhodedov
  */
-public class TestChangeListManager {
+public class HgTestChangeListManager {
 
   private ChangeListManagerImpl peer;
 
-  public TestChangeListManager(Project project) {
+  public HgTestChangeListManager(Project project) {
     peer = ChangeListManagerImpl.getInstanceImpl(project);
   }
 
@@ -79,7 +82,10 @@ public class TestChangeListManager {
     for (VirtualFile f : files) {
       changes.addAll(peer.getChangesIn(f));
     }
-    Assert.assertTrue(peer.commitChangesSynchronouslyWithResult(peer.getDefaultChangeList(), changes));
+    final LocalChangeList list = peer.getDefaultChangeList();
+    assertNotNull(list);
+    list.setComment("A comment to a commit");
+    Assert.assertTrue(peer.commitChangesSynchronouslyWithResult(list, changes));
   }
 
   public void removeFiles(final VirtualFile file) {
diff --git a/plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgTestOutputParser.java b/plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgTestOutputParser.java
new file mode 100644 (file)
index 0000000..d619efb
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2000-2010 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.zmlx.hg4idea.test;
+
+import java.io.File;
+
+/**
+ * Helper class for parsing outputs of mercurial commands.
+ * @author Kirill Likhodedov
+ */
+public class HgTestOutputParser {
+
+  public static String added(String... path) {
+    return "A " + path(path);
+  }
+
+  public static String removed(String... path) {
+    return "R " + path(path);
+  }
+
+  public static String unknown(String... path) {
+    return "? " + path(path);
+  }
+
+  public static String modified(String... path) {
+    return "M " + path(path);
+  }
+
+  public static String missing(String... path) {
+    return "! " + path(path);
+  }
+
+  public static String path(String... line) {
+    StringBuilder builder = new StringBuilder();
+
+    int linePartCount = line.length;
+
+    for (int i = 0; i < linePartCount; i++) {
+      String linePart = line[i];
+      builder.append(linePart);
+
+      if (i < linePartCount - 1) {
+        builder.append(File.separator);
+      }
+    }
+
+    return builder.toString();
+  }
+}
diff --git a/plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgTestRepository.java b/plugins/hg4idea/testSrc/org/zmlx/hg4idea/test/HgTestRepository.java
new file mode 100644 (file)
index 0000000..2cf7d01
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2000-2010 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.zmlx.hg4idea.test;
+
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.testFramework.fixtures.TempDirTestFixture;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Representation of a Mercurial repository for tests purposes.
+ * @author Kirill Likhodedov
+ */
+class HgTestRepository {
+  @NotNull private final HgAbstractTestCase myTest;
+  @NotNull private final TempDirTestFixture myDirFixture;
+  @Nullable private final HgTestRepository myParent; // cloned from
+
+  HgTestRepository(@NotNull HgAbstractTestCase test, @NotNull TempDirTestFixture dir) {
+    this(test, dir, null);
+  }
+
+  /**
+   * @param test   test instance
+   * @param dir    repository root
+   * @param parent parent repository where this repository is cloned from, if one exists.
+   */
+  HgTestRepository(@NotNull HgAbstractTestCase test, @NotNull TempDirTestFixture dir, @Nullable HgTestRepository parent) {
+    myTest = test;
+    myDirFixture = dir;
+    myParent = parent;
+  }
+
+  @NotNull
+  TempDirTestFixture getDirFixture() {
+    return myDirFixture;
+  }
+
+  /**
+   * Natively executes the given mercurial command.
+   * @param commandWithParameters Mercurial command with parameters. E.g. ["status", "-a"]
+   */
+  void execute(String... commandWithParameters) throws IOException {
+    myTest.runHg(new File(myDirFixture.getTempDirPath()), commandWithParameters);
+  }
+
+  void add() throws IOException {
+    execute("add");
+  }
+
+  void commit() throws IOException {
+    execute("commit", "-m", "Sample commit message");
+  }
+
+  void update() throws IOException {
+    execute("update");
+  }
+
+  void push() throws IOException {
+    execute("push");
+  }
+
+  public VirtualFile getDir() {
+    return myDirFixture.getFile(".");
+  }
+}