view mercurial-tests/src/jetbrains/buildServer/buildTriggers/vcs/mercurial/MercurialVcsSupportTest.java @ 474:6b447cd40492 Faradi-7.1.x

TW-10076 allow to ignore commits where all files excluded by checkout rules Since 7.1 hg-plugin marks empty commits as cannot be ignored. We do that in order to show empty commits which close the branch. Since hg log doesn't contain any signs that commit closes branch, hg-plugin detects it by checking if commit has no changed files. We did that after applying checkout rules, as a result some commits with all files excluded were marked as cannot be ignored which is wrong. Now hg-plugin checks if commit is empty before applying checkout rules.
author Dmitry Neverov <dmitry.neverov@jetbrains.com>
date Mon, 10 Sep 2012 20:02:07 +0400
parents d4c061183a5f
children efba721f9a1d
line wrap: on
line source
/*
 * Copyright 2000-2011 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 jetbrains.buildServer.buildTriggers.vcs.mercurial;

import com.intellij.execution.configurations.GeneralCommandLine;
import jetbrains.buildServer.buildTriggers.vcs.mercurial.command.*;
import jetbrains.buildServer.util.TestFor;
import jetbrains.buildServer.vcs.*;
import jetbrains.buildServer.vcs.impl.VcsRootImpl;
import junit.framework.Assert;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
import org.jetbrains.annotations.NotNull;
import org.jmock.Mockery;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.*;

import static com.intellij.openapi.util.io.FileUtil.*;
import static jetbrains.buildServer.buildTriggers.vcs.mercurial.Util.buildPatch;
import static jetbrains.buildServer.buildTriggers.vcs.mercurial.Util.copyRepository;
import static jetbrains.buildServer.buildTriggers.vcs.mercurial.VcsRootBuilder.vcsRoot;
import static jetbrains.buildServer.util.Util.map;
import static jetbrains.buildServer.vcs.RepositoryStateFactory.createRepositoryState;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItem;

@Test
public class MercurialVcsSupportTest extends BaseMercurialTestCase {

  private MercurialVcsSupport myVcs;
  private String myRep2Path = new File("mercurial-tests/testData/rep2").getAbsolutePath();
  private ServerPluginConfig myPluginConfig;

  @BeforeMethod
  protected void setUp() throws Exception {
    super.setUp();
    Mockery context = new Mockery();
    myPluginConfig = new ServerPluginConfigBuilder()
            .cachesDir(myTempFiles.createTempDir())
            .build();
    myVcs = Util.createMercurialServerSupport(context, myPluginConfig);
  }

  protected String getTestDataPath() {
    return "mercurial-tests/testData";
  }

  public void test_get_current_version() throws Exception {
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());

    assertEquals(myVcs.getCurrentVersion(vcsRoot), "9c6a6b4aede0");
    assertEquals("9c6a6b4aede0", myVcs.getVersionDisplayName("10:9c6a6b4aede0", vcsRoot));

    assertEquals(myVcs.getCurrentVersion(createVcsRoot(simpleRepo(), "test_branch")), "04c3ae4c6312");

    assertEquals(myVcs.getCurrentVersion(createVcsRoot(simpleRepo(), "name with space")), "9babcf2d5705");
  }

  private List<ModificationData> collectChanges(@NotNull VcsRoot vcsRoot, @NotNull String from, @NotNull String to, @NotNull CheckoutRules rules) throws VcsException {
    return myVcs.collectChanges(vcsRoot, from, to, rules);
  }

  public void test_collect_changes_between_two_same_roots() throws Exception {
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());
    VcsRootImpl sameVcsRoot = createVcsRoot(simpleRepo());
    List<ModificationData> changes = myVcs.collectChanges(vcsRoot, "0:9875b412a788", sameVcsRoot, "3:9522278aa38d", new CheckoutRules(""));
    do_check_for_collect_changes(changes);
  }

  public void test_collect_changes_from_non_existing_revision() throws Exception {
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());
    VcsRootImpl sameVcsRoot = createVcsRoot(simpleRepo());
    List<ModificationData> changes = myVcs.collectChanges(vcsRoot, "0:9875b412a789", sameVcsRoot, "3:9522278aa38d", new CheckoutRules(""));
    assertFalse(changes.isEmpty());//should return some changes from the toRoot
  }

  public void test_collect_changes() throws Exception {
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());
    List<ModificationData> changes = collectChanges(vcsRoot, "0:9875b412a788", "3:9522278aa38d", new CheckoutRules(""));
    do_check_for_collect_changes(changes);
  }

  private void do_check_for_collect_changes(List<ModificationData> changes) throws Exception {
    assertEquals(3, changes.size());

    ModificationData md1 = changes.get(0);
    ModificationData md2 = changes.get(1);
    ModificationData md3 = changes.get(2);
    assertEquals(md1.getVersion(), "1d446e82d356");
    assertEquals(md1.getDescription(), "new file added");
    List<VcsChange> files1 = md1.getChanges();
    assertEquals(1, files1.size());
    assertEquals(VcsChangeInfo.Type.ADDED, files1.get(0).getType());
    assertEquals(normalizePath(files1.get(0).getRelativeFileName()), "dir1/file3.txt");

    assertEquals(md2.getVersion(), "7209b1f1d793");
    assertEquals(md2.getDescription(), "file4.txt added");
    List<VcsChange> files2 = md2.getChanges();
    assertEquals(1, files2.size());
    assertEquals(files2.get(0).getType(), VcsChangeInfo.Type.ADDED);
    assertEquals(normalizePath(files2.get(0).getRelativeFileName()), "dir1/file4.txt");

    assertEquals(md3.getVersion(), "9522278aa38d");
    assertEquals(md3.getDescription(), "file removed");
    List<VcsChange> files3 = md3.getChanges();
    assertEquals(1, files3.size());
    assertEquals(files3.get(0).getType(), VcsChangeInfo.Type.REMOVED);
    assertEquals(normalizePath(files3.get(0).getRelativeFileName()), "dir1/file4.txt");
  }

  @Test
  public void test_build_patch() throws IOException, VcsException {
    setName("cleanPatch1");
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());

    ByteArrayOutputStream output = buildPatch(myVcs, vcsRoot, null, "4:b06a290a363b", new CheckoutRules(""));
    checkPatchResult(output.toByteArray());

    File clonedReposParentDir = myPluginConfig.getCachesDir();
    assertTrue(clonedReposParentDir.isDirectory());
    assertTrue(1 == clonedReposParentDir.list(new FilenameFilter() {
      public boolean accept(final File dir, final String name) {
        return name.startsWith("hg_");
      }
    }).length);
  }

  public void test_build_incremental_patch() throws IOException, VcsException {
    setName("patch1");
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());

    ByteArrayOutputStream output = buildPatch(myVcs, vcsRoot, "3:9522278aa38d", "4:b06a290a363b", new CheckoutRules(""));

    checkPatchResult(output.toByteArray());
  }

  public void test_build_incremental_patch_checkout_rules() throws IOException, VcsException {
    setName("patch1_checkout_rules");
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());

    ByteArrayOutputStream output = buildPatch(myVcs, vcsRoot, "3:9522278aa38d", "4:b06a290a363b", new CheckoutRules("+:dir1=>path"));

    checkPatchResult(output.toByteArray());
  }

  public void test_build_clean_patch_checkout_rules() throws IOException, VcsException {
    setName("cleanPatch1_checkout_rules");
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());

    ByteArrayOutputStream output = buildPatch(myVcs, vcsRoot, null, "4:b06a290a363b", new CheckoutRules("+:dir1/subdir=>."));

    checkPatchResult(output.toByteArray());
  }

  public void test_build_incremental_patch_file_with_space() throws IOException, VcsException {
    setName("patch2");
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());

    ByteArrayOutputStream output = buildPatch(myVcs, vcsRoot, "3:9522278aa38d", "6:b9deb9a1c6f4", new CheckoutRules(""));

    checkPatchResult(output.toByteArray());
  }

  public void test_clean_patch_with_subrepositories() throws Exception {
    File r1 = new File(myPluginConfig.getCachesDir(), "r1");
    File r3 = new File(myPluginConfig.getCachesDir(), "r3");
    copyDir(new File("mercurial-tests/testData/subrepos/r1"), r1);
    copyDir(new File("mercurial-tests/testData/subrepos/r3"), r3);
    moveDirWithContent(new File(r1, "hg"), new File(r1, ".hg"));
    moveDirWithContent(new File(r3, "hg"), new File(r3, ".hg"));

    VcsRootImpl root = vcsRoot().withUrl(r1.getAbsolutePath()).build();

    setName("clean_patch_with_subrepositories");
    checkPatchResult(buildPatch(myVcs, root, null, "3:d350e7209906", CheckoutRules.DEFAULT).toByteArray());
  }

  public void test_get_content() throws IOException, VcsException {
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());

    byte[] content = myVcs.getContent("dir1/subdir/file2.txt", vcsRoot, "4:b06a290a363b");
    assertEquals(new String(content), "bbb");
    content = myVcs.getContent("dir1/subdir/file2.txt", vcsRoot, "5:1d2cc6f3bc29");
    assertEquals(new String(content), "modified\r\nbbb");
  }

  public void test_get_content_in_branch() throws IOException, VcsException {
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo(), "test_branch");

    byte[] content = myVcs.getContent("file_in_branch.txt", vcsRoot, "8:04c3ae4c6312");
    assertEquals(new String(content), "file from the test_branch\r\nfile modified");
  }

  public void get_content_of_non_existing_file_should_throw_exception() throws Exception {
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());

    try {
      myVcs.getContent("non/existing/file", vcsRoot, "8:04c3ae4c6312");
      fail("getContent() should throw exception for non-existing file");
    } catch (VcsException e) {
      assertTrue(true);
    }
  }

  public void test_test_connection() throws IOException, VcsException {
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());
    vcsRoot.addProperty(Constants.REPOSITORY_PROP, "/some/non/existent/path");
    try {
      myVcs.getTestConnectionSupport().testConnection(vcsRoot);
      fail("Exception expected");
    } catch (VcsException e) {
    }
  }


  public void should_throw_friendly_exception_when_cannot_run_hg() throws Exception {
    VcsRootImpl root = createVcsRoot(simpleRepo());
    File nonExistingHg = myTempFiles.createTempFile();
    delete(nonExistingHg);
    String nonExistingHgPath = nonExistingHg.getAbsolutePath();
    root.addProperty(Constants.HG_COMMAND_PATH_PROP, nonExistingHgPath);
    try {
      myVcs.getTestConnectionSupport().testConnection(root);
      fail("Exception expected");
    } catch (VcsException e) {
      assertEquals(e.getMessage(), "Cannot find mercurial executable at path '" + nonExistingHgPath + "'");
    }
  }


  public void test_tag() throws IOException, VcsException {
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());

    String actualTag = myVcs.label("new:tag", "1:1d446e82d356", vcsRoot, new CheckoutRules(""));
    assertEquals(actualTag, "new_tag");

    // check the tag is pushed to the parent repository
    GeneralCommandLine cli = new GeneralCommandLine();
    cli.setExePath(vcsRoot.getProperty(Constants.HG_COMMAND_PATH_PROP));
    cli.setWorkDirectory(vcsRoot.getProperty(Constants.REPOSITORY_PROP));
    cli.addParameter("tags");
    CommandResult res = CommandUtil.runCommand(cli);
    assertTrue(res.getStdout().contains("new_tag"));
    assertTrue(res.getStdout().contains("1:1d446e82d356"));
  }

  public void test_tag_in_branch() throws IOException, VcsException {
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo(), "test_branch");

    String actualTag = myVcs.label("branch_tag", "7:376dcf05cd2a", vcsRoot, new CheckoutRules(""));
    assertEquals(actualTag, "branch_tag");

    // check the tag is pushed to the parent repository
    GeneralCommandLine cli = new GeneralCommandLine();
    cli.setExePath(vcsRoot.getProperty(Constants.HG_COMMAND_PATH_PROP));
    cli.setWorkDirectory(vcsRoot.getProperty(Constants.REPOSITORY_PROP));
    cli.addParameter("tags");
    CommandResult res = CommandUtil.runCommand(cli);
    assertTrue(res.getStdout().contains("branch_tag"));
    assertTrue(res.getStdout().contains("7:376dcf05cd2a"));
  }


  @TestFor(issues = "TW-10076")
  public void should_allow_to_ignore_changes_where_all_files_excluded() throws Exception {
    VcsRootImpl root = createVcsRoot(myRep2Path);
    List<ModificationData> changes = myVcs.collectChanges(root, "43023ea3f13b", "a2672ee13212", new CheckoutRules("-:.hgtags"));
    assertEquals(changes.size(), 1);
    assertTrue(changes.get(0).isCanBeIgnored());
  }


  @TestFor(issues = "TW-10076")
  public void should_not_allow_to_ignore_close_branch_commits() throws Exception {
    VcsRootImpl root = createVcsRoot(myRep2Path);
    List<ModificationData> changes = myVcs.collectChanges(root, "df04faa7575a", "43023ea3f13b", CheckoutRules.DEFAULT);
    assertEquals(changes.size(), 2);
    assertEquals(changes.get(1).getChangeCount(), 0);
    assertFalse(changes.get(1).isCanBeIgnored());
  }


  public void test_tag_with_specified_username() throws IOException, VcsException {
    final String customUserForTag = "John Doe <john@some.org>";
    File repository = copyRepository(myTempFiles, simpleRepo());
    VcsRoot root = vcsRoot().withUrl(repository.getAbsolutePath()).withUserForTag(customUserForTag).build();

    myVcs.label("tag_by_specified_user", "10:9c6a6b4aede0", root, CheckoutRules.DEFAULT);

    String currentVersion = myVcs.getCurrentVersion(root);
    List<ModificationData> changes = myVcs.collectChanges(root, "10:9c6a6b4aede0", currentVersion, CheckoutRules.DEFAULT);
    assertEquals(changes.size(), 1);
    assertEquals(changes.get(0).getUserName(), customUserForTag);
  }


  public void labeling_should_not_populate_files_in_local_mirror() throws Exception {
    VcsRootImpl root = createVcsRoot(simpleRepo());
    myVcs.getCurrentVersion(root);
    File mirror = myVcs.getMirrorManager().getMirrorDir(root.getProperty(Constants.REPOSITORY_PROP));
    File[] files = mirror.listFiles();
    assertEquals(files.length, 1);
    assertEquals(files[0].getName(), ".hg");

    myVcs.label("v1.0", "7:376dcf05cd2a", root, new CheckoutRules(""));

    files = mirror.listFiles();
    assertEquals(files.length, 1);
    assertEquals(files[0].getName(), ".hg");
  }


  public void test_collect_changes_in_branch() throws Exception {
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo(), "test_branch");

    // fromVersion(6:b9deb9a1c6f4) is not in the branch (it is in the default branch)
    List<ModificationData> changes = collectChanges(vcsRoot, "6:b9deb9a1c6f4", "7:376dcf05cd2a", CheckoutRules.DEFAULT);
    assertEquals(1, changes.size());

    ModificationData md1 = changes.get(0);
    assertEquals(md1.getVersion(), "376dcf05cd2a");
    assertEquals(md1.getDescription(), "new file added in the test_branch");
    List<VcsChange> files1 = md1.getChanges();
    assertEquals(1, files1.size());
    assertEquals(VcsChangeInfo.Type.ADDED, files1.get(0).getType());
    assertEquals(normalizePath(files1.get(0).getRelativeFileName()), "file_in_branch.txt");

    changes = collectChanges(vcsRoot, "7:376dcf05cd2a", "8:04c3ae4c6312", CheckoutRules.DEFAULT);
    assertEquals(1, changes.size());

    md1 = changes.get(0);
    assertEquals(md1.getVersion(), "04c3ae4c6312");
    assertEquals(md1.getDescription(), "file modified");
  }

  public void test_full_patch_from_branch() throws IOException, VcsException {
    setName("patch3");
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo(), "test_branch");

    ByteArrayOutputStream output = buildPatch(myVcs, vcsRoot, null, "7:376dcf05cd2a", new CheckoutRules(""));

    checkPatchResult(output.toByteArray());
  }

  public void test_full_patch_from_branch_with_checkout_rules() throws IOException, VcsException {
    setName("patch3_checkout_rules1");
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo(), "test_branch");

    ByteArrayOutputStream output = buildPatch(myVcs, vcsRoot, null, "7:376dcf05cd2a", new CheckoutRules("+:.=>path"));

    checkPatchResult(output.toByteArray());
  }

  public void test_full_patch_from_branch_with_checkout_rules_mapped_and_skipped() throws IOException, VcsException {
    setName("patch3_checkout_rules2");
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo(), "test_branch");

    ByteArrayOutputStream output = buildPatch(myVcs, vcsRoot, null, "7:376dcf05cd2a", new CheckoutRules("+:dir1=>path/dir1\n+:dir with space"));

    checkPatchResult(output.toByteArray());
  }

  public void test_incremental_patch_from_branch() throws IOException, VcsException {
    setName("patch4");
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo(), "test_branch");

    ByteArrayOutputStream output = buildPatch(myVcs, vcsRoot, "7:376dcf05cd2a", "8:04c3ae4c6312", new CheckoutRules(""));

    checkPatchResult(output.toByteArray());
  }

  @Test(enabled = false)
  public void support_anchor_branch_notation() throws IOException {
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());
    String repPath = vcsRoot.getProperty(Constants.REPOSITORY_PROP);
    vcsRoot.addProperty(Constants.REPOSITORY_PROP, repPath + "#test_branch");
    HgVcsRoot hgRoot = new HgVcsRoot(vcsRoot);
    assertEquals("test_branch", hgRoot.getBranchName());

    vcsRoot.addProperty(Constants.REPOSITORY_PROP, repPath + "#");
    hgRoot = new HgVcsRoot(vcsRoot);
    assertEquals("default", hgRoot.getBranchName());

    vcsRoot.addProperty(Constants.REPOSITORY_PROP, repPath);
    hgRoot = new HgVcsRoot(vcsRoot);
    assertEquals("default", hgRoot.getBranchName());
  }

  public void build_patch_using_custom_clone_path() throws IOException, VcsException {
    setName("cleanPatch1");
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());
    File cloneDir = myTempFiles.createTempDir();
    vcsRoot.addProperty(Constants.SERVER_CLONE_PATH_PROP, cloneDir.getAbsolutePath());

    ByteArrayOutputStream output = buildPatch(myVcs, vcsRoot, null, "4:b06a290a363b", new CheckoutRules(""));

    checkPatchResult(output.toByteArray());

    assertTrue(new File(cloneDir, new File(vcsRoot.getProperty(Constants.REPOSITORY_PROP)).getName()).isDirectory());
  }

  public void build_patch_from_newer_revision_to_earlier() throws Exception {
    setName("patch5");
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());
    ByteArrayOutputStream output = buildPatch(myVcs, vcsRoot, "6:b9deb9a1c6f4", "3:9522278aa38d", CheckoutRules.DEFAULT);
    checkPatchResult(output.toByteArray());
  }

  public void build_patch_from_unknown_revision() throws Exception {
    setName("patch6");
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());
    ByteArrayOutputStream output = buildPatch(myVcs, vcsRoot, "6:hahahahahaha", "3:9522278aa38d", new CheckoutRules("+:.=>path"));
    checkPatchResult(output.toByteArray());
  }

  private String mergeCommittsRepo() {
    return new File("mercurial-tests/testData/rep2").getAbsolutePath();
  }

  public void test_collect_changes_between_two_different_roots() throws Exception {
    VcsRootImpl defaultRoot = createVcsRoot(mergeCommittsRepo());
    VcsRootImpl branchRoot = createVcsRoot(mergeCommittsRepo(), "test");
    List<ModificationData> changes = myVcs.collectChanges(defaultRoot, "11:48177654181c", branchRoot, "10:fc524efc2bc4", CheckoutRules.DEFAULT);
    assertEquals(changes.size(), 2);

    assertEquals(changes.get(0).getVersion(), "8c44244d6645");
    assertEquals(changes.get(1).getVersion(), "fc524efc2bc4");
  }

  public void collectChanges_should_return_all_changes_from_branch() throws Exception {
    VcsRootImpl defaultBranchRoot = createVcsRoot(myRep2Path, "default");
    VcsRootImpl personalBranchRoot = createVcsRoot(myRep2Path, "personal-branch");
    List<ModificationData> modifications = myVcs.collectChanges(defaultBranchRoot, "16:505c5b9d01e6", personalBranchRoot, "17:9ec402c74298", CheckoutRules.DEFAULT);
    assertEquals(3, modifications.size());
  }

  public void test_collect_changes_merge() throws Exception {
    VcsRootImpl vcsRoot = createVcsRoot(mergeCommittsRepo());

    List<ModificationData> changes = collectChanges(vcsRoot, "1:a3d15477d297", "4:6eeb8974fe67", CheckoutRules.DEFAULT);
    assertEquals(changes.size(), 3);

    assertEquals(changes.get(0).getVersion(), "db8a04d262f3");
    assertEquals(changes.get(1).getVersion(), "2538c02bafeb");
    assertEquals(changes.get(2).getVersion(), "6eeb8974fe67");

    assertFiles(Arrays.asList("A dir1/file1.txt"), changes.get(0));
    assertFiles(Arrays.asList("A dir2/file2.txt"), changes.get(1));
    assertFiles(Arrays.asList("A dir1/file1.txt", "A dir2/file2.txt"), changes.get(2));
  }

  public void test_collect_changes_merge_conflict() throws Exception {
    VcsRootImpl vcsRoot = createVcsRoot(mergeCommittsRepo());

    List<ModificationData> changes = collectChanges(vcsRoot, "6:6066b677d026", "8:b6e2d176fe8e", CheckoutRules.DEFAULT);
    assertEquals(changes.size(), 2);

    assertFiles(Arrays.asList("A dir4/file41.txt"), changes.get(0));
    assertFiles(Arrays.asList("M dir4/file41.txt", "A dir4/file42.txt", "A dir4/file43.txt", "R dir3/file3.txt"), changes.get(1));
  }

  public void test_collect_changes_merge_conflict_named_branch() throws Exception {
    VcsRootImpl vcsRoot = createVcsRoot(mergeCommittsRepo());

    List<ModificationData> changes = collectChanges(vcsRoot, "8:b6e2d176fe8e", "12:1e620196c4b6", CheckoutRules.DEFAULT);
    assertEquals(changes.size(), 4);

    assertFiles(Arrays.asList("A dir6/file6.txt"), changes.get(2));
    assertFiles(Arrays.asList("M dir6/file6.txt", "A dir5/file5.txt"), changes.get(3));
  }

  //TW-17530
  public void test_collect_changes_with_exclude_checkout_rules() throws Exception {
    VcsRootImpl root = createVcsRoot(simpleRepo());
    collectChanges(root, "0:9875b412a788", "10:9c6a6b4aede0", new CheckoutRules("-:dir1\n" +
            "-:dir with space"));
  }

  //TW-10172
  public void should_not_fill_server_clone_path() {
    assertFalse(myVcs.getDefaultVcsProperties().containsKey(Constants.SERVER_CLONE_PATH_PROP));

    Map<String, String> rootProperties = new HashMap<String, String>() {{
      put(Constants.HG_COMMAND_PATH_PROP, "hg");
      put(Constants.REPOSITORY_PROP, "http://somewhere.com/path");
    }};

    assertFalse(rootProperties.containsKey(Constants.SERVER_CLONE_PATH_PROP));
    myVcs.getVcsPropertiesProcessor().process(rootProperties);
    assertFalse(rootProperties.containsKey(Constants.SERVER_CLONE_PATH_PROP));
  }

  public void use_compressed_transfer_by_default() {
    VcsRootImpl root = new VcsRootImpl(1, Constants.VCS_NAME);
    root.addAllProperties(myVcs.getDefaultVcsProperties());
    root.addProperty(Constants.REPOSITORY_PROP, "http://host.com/path");
    HgVcsRoot hgRoot = new HgVcsRoot(root);
    assertFalse(hgRoot.isUncompressedTransfer());
  }


  //TW-15762
  public void should_use_clone_to_root_parameter() throws IOException, VcsException {
    VcsRootImpl vcsRoot = createVcsRoot(simpleRepo());
    File cloneDir = myTempFiles.createTempDir();
    vcsRoot.addProperty(Constants.SERVER_CLONE_PATH_PROP, cloneDir.getAbsolutePath());
    myVcs.getCurrentVersion(vcsRoot);
  }


  public void test_getPersonalBranchDescription_when_branch_contains_commits() throws Exception {
    VcsRootImpl originalRoot = createVcsRoot(simpleRepo());
    PersonalBranchDescription description = myVcs.getPersonalBranchDescription(originalRoot, "name with space");
    assertNotNull(description);
    assertEquals(description.getBranchId(), "376dcf05cd2a");
    assertEquals(description.getUsername(), "Pavel.Sher");
  }


  public void test_getPersonalBranchDescription_when_branch_doesnot_contain_commits() throws Exception {
    VcsRootImpl originalRoot = createVcsRoot(simpleRepo());
    PersonalBranchDescription description = myVcs.getPersonalBranchDescription(originalRoot, "default");
    assertNull(description);
  }


  public void labeling_should_not_change_vcs_root_settings() throws Exception {
    VcsRootImpl root = createVcsRoot(simpleRepo(), "test_branch");
    assertNull(root.getProperty(Constants.SERVER_CLONE_PATH_PROP));
    myVcs.label("branch_tag", "7:376dcf05cd2a", root, CheckoutRules.DEFAULT);
    assertNull(root.getProperty(Constants.SERVER_CLONE_PATH_PROP));
  }


  public void hg_version_should_not_depend_on_locale() throws IOException, VcsException {
    HgRepo repo = new HgRepo(new File(simpleRepo()), Util.getHgPath(), new AuthSettings(null, null));
    HgVersion defaultLocaleVersion = repo.version().call();

    VersionCommand russianLocalVersion = new VersionCommand(Util.getHgPath(), new File(simpleRepo())) {
      @Override
      protected GeneralCommandLine createCommandLine() {
        GeneralCommandLine commandLine = super.createCommandLine();
        Map<String, String> env = commandLine.getEnvParams();
        if (env == null)
          env = new HashMap<String, String>();
        env.put("LANG", "ru_RU");
        env.put("LANGUAGE", "ru_RU");
        env.put("LC_MESSAGE", "ru_RU");
        commandLine.setEnvParams(env);
        return commandLine;
      }
    };

    HgVersion russianLocaleVersion = russianLocalVersion.call();
    assertEquals(russianLocaleVersion, defaultLocaleVersion);
  }


  public void collect_changes_between_states() throws Exception {
    VcsRootImpl root = createVcsRoot(myRep2Path);
    List<ModificationData> changes = myVcs.collectChanges(root,
            createRepositoryState(map("default", "1e620196c4b6"), "default"),
            createRepositoryState(map("default", "505c5b9d01e6", "personal-branch", "96b78d73081d"), "default"),
            CheckoutRules.DEFAULT);
    assertEquals(changes.size(), 4);
    assertThat(changes, hasItem(withVersion("dec47d2d49bf")));
    assertThat(changes, hasItem(withVersion("78e67807f916")));
    assertThat(changes, hasItem(withVersion("96b78d73081d")));
    assertThat(changes, hasItem(withVersion("505c5b9d01e6")));
  }


  public void collect_changes_between_states_does_not_report_duplicate_changes() throws Exception {
    VcsRootImpl root = createVcsRoot(myRep2Path);
    List<ModificationData> changes = myVcs.collectChanges(root,
            createRepositoryState(map("default", "8c44244d6645"), "default"),
            createRepositoryState(map("default", "505c5b9d01e6", "personal-branch", "9ec402c74298"), "default"),
            CheckoutRules.DEFAULT);
    assertEquals(changes.size(), 8);
    assertThat(changes, hasItem(withVersion("9ec402c74298")));
    assertThat(changes, hasItem(withVersion("505c5b9d01e6")));
    assertThat(changes, hasItem(withVersion("96b78d73081d")));
    assertThat(changes, hasItem(withVersion("78e67807f916")));
    assertThat(changes, hasItem(withVersion("dec47d2d49bf")));
    assertThat(changes, hasItem(withVersion("1e620196c4b6")));
    assertThat(changes, hasItem(withVersion("48177654181c")));
    assertThat(changes, hasItem(withVersion("fc524efc2bc4")));
  }


  private ModificationDataVersionMatcher withVersion(@NotNull String version) {
    return new ModificationDataVersionMatcher(version);
  }

  class ModificationDataVersionMatcher extends TypeSafeMatcher<ModificationData> {

    private final String myVersion;

    public ModificationDataVersionMatcher(@NotNull String version) {
      myVersion = version;
    }

    @Override
    public boolean matchesSafely(ModificationData m) {
      return myVersion.equals(m.getVersion());
    }

    public void describeTo(Description description) {
      description.appendText("modification with version").appendValue(myVersion);
    }
  }


  private void assertFiles(final List<String> expectedFiles, final ModificationData modificationData) {
    Set<String> actualFiles = new HashSet<String>();
    for (VcsChange vc: modificationData.getChanges()) {
      actualFiles.add(toFileStatus(vc.getType()) + " " + vc.getRelativeFileName());
    }
    Assert.assertEquals("Actual files: " + actualFiles.toString(), new HashSet<String>(expectedFiles), actualFiles);
  }

  private String toFileStatus(VcsChange.Type type) {
    switch (type) {
      case ADDED:
        return "A";
      case REMOVED:
        return "R";
      case CHANGED:
        return "M";
    }
    return "?";
  }

  private Object normalizePath(final String path) {
    return path.replace(File.separatorChar, '/');
  }


  public void test_collect_changes_using_checkout_rules() {
    assertTrue(myVcs.getCollectChangesPolicy() instanceof CollectChangesByCheckoutRules);
  }
}