/* * Copyright 2015-present Facebook, Inc. * * 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 com.facebook.buck.util.versioncontrol; import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; import static org.hamcrest.Matchers.hasSize; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assume.assumeTrue; import com.facebook.buck.cli.FakeBuckConfig; import com.facebook.buck.testutil.integration.TestDataHelper; import com.facebook.buck.util.TestProcessExecutorFactory; import com.facebook.buck.zip.Unzip; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; import org.hamcrest.Matchers; import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; public class HgCmdLineInterfaceIntegrationTest { @Rule public ExpectedException exception = ExpectedException.none(); private static final String HG_REPOS_ZIP = "hg_repos.zip"; private static final String REPOS_DIR = "hg_repos"; private static final String REPO_TWO_DIR = "hg_repo_two"; private static final String REPO_THREE_DIR = "hg_repo_three"; private static final String REPO_WITH_SUB_DIR = "hg_repo_with_subdir"; /** * * * * <p>Test data: * * <p>The following repo is used in the tests: * * <pre> * @ e1b8ef branch_from_master3 * | diverge from master_3 further * | * @ 00618f * | diverge from master_3 * | * o 90e0a6 master3 * | commit3 * | * | o 65b545 branch_from_master2 * |/ diverge from master_2 * | * o 8b1b79 master2 * | commit2 * | * o f5091a master1 * commit1 * </pre> * * There are two different variants (both stored inside HG_REPOS_ZIP): * * <p>hg_repo_two: above, current tip @branch_from_master2, and no local changes. hg_repo_three: * above, current tip @branch_from_master3, and with local changes. * * <p>Additionally hg_repo_with_subdir is a new hg_repo with a directory called subdir */ @SuppressWarnings("javadoc") @ClassRule public static TemporaryFolder tempFolder = new TemporaryFolder(); private static VersionControlCmdLineInterface repoTwoCmdLine; private static VersionControlCmdLineInterface repoThreeCmdLine; private static Path reposPath; @BeforeClass public static void setUpClass() throws IOException, InterruptedException { reposPath = explodeReposZip(); repoTwoCmdLine = makeCmdLine(reposPath.resolve(REPO_TWO_DIR)); repoThreeCmdLine = makeCmdLine(reposPath.resolve(REPO_THREE_DIR)); } @Before public void setUp() throws InterruptedException { assumeTrue(repoTwoCmdLine.isSupportedVersionControlSystem()); } @Test public void whenWorkingDirectoryUnchangedThenHasWorkingDirectoryChangesReturnsFalse() throws VersionControlCommandFailedException, InterruptedException { assertThat(repoTwoCmdLine.changedFiles("."), hasSize(0)); } @Test public void whenWorkingDirectoryChangedThenHasWorkingDirectoryChangesReturnsTrue() throws VersionControlCommandFailedException, InterruptedException { assertEquals( ImmutableSet.of("A tracked_change", "? local_change"), repoThreeCmdLine.changedFiles(".")); } @Test public void testChangedFilesFromHead() throws VersionControlCommandFailedException, InterruptedException { assertEquals( ImmutableSet.of("A tracked_change", "? local_change"), repoThreeCmdLine.changedFiles(".")); } @Test public void testChangedFilesFromCommonAncestor() throws VersionControlCommandFailedException, InterruptedException { ImmutableSet<String> changedFiles = repoThreeCmdLine.changedFiles("ancestor(., master3)"); assertThat( changedFiles, Matchers.containsInAnyOrder( "A tracked_change", "A change3", "A change3-2", "? local_change")); } @Test public void testDiffBetweenTheSameRevision() throws VersionControlCommandFailedException, InterruptedException { exception.expect(VersionControlCommandFailedException.class); repoThreeCmdLine.diffBetweenRevisions("adf7a0", "adf7a0"); } @Test public void testDiffBetweenDiffs() throws VersionControlCommandFailedException, InterruptedException { ImmutableList<String> expectedValue = ImmutableList.of( "# HG changeset patch", "# User Joe Blogs <joe.blogs@fb.com>", "# Date 1440589545 -3600", "# Wed Aug 26 12:45:45 2015 +0100", "# Node ID 2911b3cab6b24374a3649ebb96b0e53324e9c02e", "# Parent b1fd7e5896af8aa30e3e797ef1445605eec6d055", "diverge from master_2", "", "diff --git a/change2 b/change2", "new file mode 100644", ""); assertEquals( String.join("\n", expectedValue), repoThreeCmdLine.diffBetweenRevisions("b1fd7e", "2911b3")); } @Test public void testExtractRawManifestNoChanges() throws VersionControlCommandFailedException, InterruptedException, IOException { HgCmdLineInterface hgCmdLineInterface = makeHgCmdLine(reposPath.resolve(REPO_TWO_DIR)); String path = hgCmdLineInterface.extractRawManifest(); List<String> lines = Files.readAllLines( Paths.get(path), Charset.forName(System.getProperty("file.encoding", "UTF-8"))); List<String> expected = ImmutableList.of( "change2\0b80de5d138758541c5f05265ad144ab9fa86d1db", "file1\0b80de5d138758541c5f05265ad144ab9fa86d1db", "file2\0b80de5d138758541c5f05265ad144ab9fa86d1db"); assertEquals(lines, expected); } @Test public void testExtractRawManifestFileRenamed() throws VersionControlCommandFailedException, InterruptedException, IOException { // In order to make changes without affecting other tests, extract a new repository copy Path localTempFolder = Files.createTempDirectory(tempFolder.getRoot().toPath(), "temp-repo"); Path localReposPath = explodeReposZip(localTempFolder); Files.delete(localReposPath.resolve(REPO_TWO_DIR + "/file1")); HgCmdLineInterface hgCmdLineInterface = makeHgCmdLine(localReposPath.resolve(REPO_TWO_DIR)); String path = hgCmdLineInterface.extractRawManifest(); List<String> lines = Files.readAllLines( Paths.get(path), Charset.forName(System.getProperty("file.encoding", "UTF-8"))); List<String> expected = ImmutableList.of( "change2\u0000b80de5d138758541c5f05265ad144ab9fa86d1db", "file1\u0000b80de5d138758541c5f05265ad144ab9fa86d1db", "file2\u0000b80de5d138758541c5f05265ad144ab9fa86d1db", "file1\u00000000000000000000000000000000000000000000d"); assertEquals(lines, expected); } @Test public void testHgRootSubdir() throws VersionControlCommandFailedException, InterruptedException, IOException { // Use a subdir of the repository HgCmdLineInterface hgCmdLineInterface = makeHgCmdLine(reposPath.resolve(REPO_WITH_SUB_DIR + "/subdir")); Path result = hgCmdLineInterface.getHgRoot(); // Use toRealPath to follow the pecularities of the OS X tempdir system, which uses a // /var -> /private/var symlink. assertEquals(result, reposPath.resolve(REPO_WITH_SUB_DIR).toRealPath()); } @Test public void testHgRootOutsideRepo() throws VersionControlCommandFailedException, InterruptedException { // Note: reposPath is not a hg repository, so we have to create a HgCmdLineInterface directly // here. HgCmdLineInterface hgCmdLineInterface = new HgCmdLineInterface( new TestProcessExecutorFactory(), reposPath, new VersionControlBuckConfig(FakeBuckConfig.builder().build()).getHgCmd(), ImmutableMap.of()); Path result = hgCmdLineInterface.getHgRoot(); assertNull(result); } private static Path explodeReposZip() throws InterruptedException, IOException { return explodeReposZip(tempFolder.getRoot().toPath()); } private static Path explodeReposZip(Path destination) throws InterruptedException, IOException { Path testDataDir = TestDataHelper.getTestDataDirectory(HgCmdLineInterfaceIntegrationTest.class); Path hgRepoZipPath = testDataDir.resolve(HG_REPOS_ZIP); Path hgRepoZipCopyPath = destination.resolve(HG_REPOS_ZIP); Files.copy(hgRepoZipPath, hgRepoZipCopyPath, REPLACE_EXISTING); Path reposPath = destination.resolve(REPOS_DIR); Unzip.extractZipFile( hgRepoZipCopyPath, reposPath, Unzip.ExistingFileMode.OVERWRITE_AND_CLEAN_DIRECTORIES); return reposPath; } private static VersionControlCmdLineInterface makeCmdLine(Path repoRootDir) throws InterruptedException { return new DelegatingVersionControlCmdLineInterface( repoRootDir, new TestProcessExecutorFactory(), new VersionControlBuckConfig(FakeBuckConfig.builder().build()).getHgCmd(), ImmutableMap.of()); } private static HgCmdLineInterface makeHgCmdLine(Path repoRootDir) { return new HgCmdLineInterface( new TestProcessExecutorFactory(), repoRootDir, new VersionControlBuckConfig(FakeBuckConfig.builder().build()).getHgCmd(), ImmutableMap.of()); } }