From 9728561e7991d180c76a69c06d70c7311cf7018e Mon Sep 17 00:00:00 2001 From: Kevin Willford Date: Wed, 17 Jul 2019 15:31:42 -0600 Subject: [PATCH] Extend GitRepoTests to allow include mode (#1331) * Extend GitRepoTests to allow include mode The GitRepoTests can be initialized with a ValidateWorkingTree mode that is currently a boolean. If enabled, we will add extra checks to make sure the working tree of our virtual enlistment matches the enlistment from a vanilla Git repo. To extend this to the "include" mode, we need to first modify this boolean into an enum and add it as an extra option. Second, we need to be very careful about what we are comparing. We will no longer virtualize outside of the included folders. Be careful to include files in the root directory. The functional tests can then be run with "--partial-mode" to exercise only this option, which will isolate the test failures to this setting AND keep the test suite from getting too slow. Currently, the partial mode space is probably wider than necessary and can be reduced in later iterations. This does provide _some_ coverage. Signed-off-by: Derrick Stolee * Use enum for passing into all tests instead of an int * Clean up functional tests file system should extensions * Rename argument to --include-mode to match the feature * Add included folders below top level --- .../GVFS.FunctionalTests.csproj | 2 +- GVFS/GVFS.FunctionalTests/Program.cs | 21 ++++- GVFS/GVFS.FunctionalTests/Settings.cs | 7 ++ .../Should/FileSystemShouldExtensions.cs | 60 ++++++++++++-- .../Tests/GitCommands/AddStageTests.cs | 5 +- .../Tests/GitCommands/CheckoutTests.cs | 9 +- .../GitCommands/CherryPickConflictTests.cs | 5 +- .../GitCommands/CreatePlaceholderTests.cs | 5 +- .../GitCommands/DeleteEmptyFolderTests.cs | 10 +-- .../Tests/GitCommands/EnumerationMergeTest.cs | 5 +- .../Tests/GitCommands/GitCommandsTests.cs | 13 +-- .../Tests/GitCommands/GitRepoTests.cs | 82 ++++++++++++++++--- .../Tests/GitCommands/HashObjectTests.cs | 5 +- .../Tests/GitCommands/MergeConflictTests.cs | 5 +- .../Tests/GitCommands/RebaseConflictTests.cs | 5 +- .../Tests/GitCommands/RebaseTests.cs | 5 +- .../Tests/GitCommands/ResetHardTests.cs | 7 +- .../Tests/GitCommands/ResetMixedTests.cs | 11 +-- .../Tests/GitCommands/ResetSoftTests.cs | 5 +- .../Tests/GitCommands/RmTests.cs | 5 +- .../Tests/GitCommands/StatusTests.cs | 3 +- .../Tests/GitCommands/UpdateIndexTests.cs | 5 +- .../Tests/GitCommands/UpdateRefTests.cs | 5 +- GVFS/GVFS.Tests/DataSources.cs | 3 +- .../Should/EnumerableShouldExtensions.cs | 4 +- 25 files changed, 217 insertions(+), 75 deletions(-) diff --git a/GVFS/GVFS.FunctionalTests/GVFS.FunctionalTests.csproj b/GVFS/GVFS.FunctionalTests/GVFS.FunctionalTests.csproj index 7bff05e04b..821815ac43 100644 --- a/GVFS/GVFS.FunctionalTests/GVFS.FunctionalTests.csproj +++ b/GVFS/GVFS.FunctionalTests/GVFS.FunctionalTests.csproj @@ -1,4 +1,4 @@ - + Exe diff --git a/GVFS/GVFS.FunctionalTests/Program.cs b/GVFS/GVFS.FunctionalTests/Program.cs index 89957dfe7d..7a2c67e108 100644 --- a/GVFS/GVFS.FunctionalTests/Program.cs +++ b/GVFS/GVFS.FunctionalTests/Program.cs @@ -1,4 +1,5 @@ -using GVFS.FunctionalTests.Tools; +using GVFS.FunctionalTests.Properties; +using GVFS.FunctionalTests.Tools; using GVFS.Tests; using System; using System.Collections.Generic; @@ -42,7 +43,13 @@ public static void Main(string[] args) { Console.WriteLine("Running the full suite of tests"); - GVFSTestConfig.GitRepoTestsValidateWorkTree = DataSources.AllBools; + List modes = new List(); + foreach (Settings.ValidateWorkingTreeMode mode in Enum.GetValues(typeof(Settings.ValidateWorkingTreeMode))) + { + modes.Add(new object[] { mode }); + } + + GVFSTestConfig.GitRepoTestsValidateWorkTree = modes.ToArray(); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { @@ -55,10 +62,18 @@ public static void Main(string[] args) } else { + Settings.ValidateWorkingTreeMode validateMode = Settings.ValidateWorkingTreeMode.Full; + + if (runner.HasCustomArg("--include-mode")) + { + validateMode = Settings.ValidateWorkingTreeMode.IncludeMode; + includeCategories.Add(Categories.GitCommands); + } + GVFSTestConfig.GitRepoTestsValidateWorkTree = new object[] { - new object[] { true } + new object[] { validateMode }, }; if (runner.HasCustomArg("--extra-only")) diff --git a/GVFS/GVFS.FunctionalTests/Settings.cs b/GVFS/GVFS.FunctionalTests/Settings.cs index e5db230bea..f54199ec5a 100644 --- a/GVFS/GVFS.FunctionalTests/Settings.cs +++ b/GVFS/GVFS.FunctionalTests/Settings.cs @@ -6,6 +6,13 @@ namespace GVFS.FunctionalTests.Properties { public static class Settings { + public enum ValidateWorkingTreeMode + { + None = 0, + Full = 1, + IncludeMode = 2, + } + public static class Default { public static string CurrentDirectory { get; private set; } diff --git a/GVFS/GVFS.FunctionalTests/Should/FileSystemShouldExtensions.cs b/GVFS/GVFS.FunctionalTests/Should/FileSystemShouldExtensions.cs index f4c381f260..6edf07367b 100644 --- a/GVFS/GVFS.FunctionalTests/Should/FileSystemShouldExtensions.cs +++ b/GVFS/GVFS.FunctionalTests/Should/FileSystemShouldExtensions.cs @@ -201,10 +201,11 @@ public DirectoryAdapter WithDeepStructure( FileSystemRunner fileSystem, string otherPath, bool ignoreCase = false, - bool compareContent = false) + bool compareContent = false, + string[] withinPrefixes = null) { otherPath.ShouldBeADirectory(this.runner); - CompareDirectories(fileSystem, otherPath, this.Path, ignoreCase, compareContent); + CompareDirectories(fileSystem, otherPath, this.Path, ignoreCase, compareContent, withinPrefixes); return this; } @@ -251,12 +252,54 @@ public DirectoryInfo WithAttribute(FileAttributes attribute) return info; } + private static bool IsMatchedPath(FileSystemInfo info, string repoRoot, string[] prefixes) + { + if (prefixes == null || prefixes.Length == 0) + { + return true; + } + + string localPath = info.FullName.Substring(repoRoot.Length + 1); + + if (localPath.Equals(".git", StringComparison.OrdinalIgnoreCase)) + { + // Include _just_ the .git folder. + // All sub-items are not included in the enumerator. + return true; + } + + if (!localPath.Contains(System.IO.Path.DirectorySeparatorChar) && + (info.Attributes & FileAttributes.Directory) != FileAttributes.Directory) + { + // If it is a file in the root folder, then include it. + return true; + } + + foreach (string prefixDir in prefixes) + { + if (localPath.StartsWith(prefixDir, StringComparison.OrdinalIgnoreCase)) + { + return true; + } + + if (prefixDir.StartsWith(localPath, StringComparison.OrdinalIgnoreCase) && + Directory.Exists(info.FullName)) + { + // For example: localPath = "GVFS" and prefix is "GVFS\\GVFS". + return true; + } + } + + return false; + } + private static void CompareDirectories( FileSystemRunner fileSystem, string expectedPath, string actualPath, bool ignoreCase, - bool compareContent) + bool compareContent, + string[] withinPrefixes) { IEnumerable expectedEntries = new DirectoryInfo(expectedPath).EnumerateFileSystemInfos("*", SearchOption.AllDirectories); IEnumerable actualEntries = new DirectoryInfo(actualPath).EnumerateFileSystemInfos("*", SearchOption.AllDirectories); @@ -265,6 +308,7 @@ private static void CompareDirectories( IEnumerator expectedEnumerator = expectedEntries .Where(x => !x.FullName.Contains(dotGitFolder)) .OrderBy(x => x.FullName) + .Where(x => IsMatchedPath(x, expectedPath, withinPrefixes)) .GetEnumerator(); IEnumerator actualEnumerator = actualEntries .Where(x => !x.FullName.Contains(dotGitFolder)) @@ -279,7 +323,7 @@ private static void CompareDirectories( bool nameIsEqual = false; if (ignoreCase) { - nameIsEqual = actualEnumerator.Current.Name.Equals(expectedEnumerator.Current.Name, StringComparison.OrdinalIgnoreCase); + nameIsEqual = actualEnumerator.Current.Name.Equals(expectedEnumerator.Current.Name, StringComparison.OrdinalIgnoreCase); } else { @@ -297,6 +341,7 @@ private static void CompareDirectories( if (Directory.GetFileSystemEntries(expectedEnumerator.Current.FullName, "*", SearchOption.TopDirectoryOnly).Length == 0) { expectedMoved = expectedEnumerator.MoveNext(); + continue; } } @@ -306,15 +351,15 @@ private static void CompareDirectories( if ((expectedEnumerator.Current.Attributes & FileAttributes.Directory) == FileAttributes.Directory) { - (actualEnumerator.Current.Attributes & FileAttributes.Directory).ShouldEqual(FileAttributes.Directory, $"expected path: {expectedEnumerator.Current.FullName} actual path: {actualEnumerator.Current.FullName}"); + (actualEnumerator.Current.Attributes & FileAttributes.Directory).ShouldEqual(FileAttributes.Directory, $"expected directory path: {expectedEnumerator.Current.FullName} actual file path: {actualEnumerator.Current.FullName}"); } else { - (actualEnumerator.Current.Attributes & FileAttributes.Directory).ShouldNotEqual(FileAttributes.Directory, $"expected path: {expectedEnumerator.Current.FullName} actual path: {actualEnumerator.Current.FullName}"); + (actualEnumerator.Current.Attributes & FileAttributes.Directory).ShouldNotEqual(FileAttributes.Directory, $"expected file path: {expectedEnumerator.Current.FullName} actual directory path: {actualEnumerator.Current.FullName}"); FileInfo expectedFileInfo = (expectedEnumerator.Current as FileInfo).ShouldNotBeNull(); FileInfo actualFileInfo = (actualEnumerator.Current as FileInfo).ShouldNotBeNull(); - actualFileInfo.Length.ShouldEqual(expectedFileInfo.Length); + actualFileInfo.Length.ShouldEqual(expectedFileInfo.Length, $"File lengths do not agree expected: {expectedEnumerator.Current.FullName} = {expectedFileInfo.Length} actual: {actualEnumerator.Current.FullName} = {actualFileInfo.Length}"); if (compareContent) { @@ -327,6 +372,7 @@ private static void CompareDirectories( } StringBuilder errorEntries = new StringBuilder(); + if (expectedMoved) { do diff --git a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/AddStageTests.cs b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/AddStageTests.cs index 31f4298612..9d18b94fdf 100644 --- a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/AddStageTests.cs +++ b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/AddStageTests.cs @@ -1,4 +1,5 @@ -using GVFS.FunctionalTests.Tools; +using GVFS.FunctionalTests.Properties; +using GVFS.FunctionalTests.Tools; using NUnit.Framework; using System.IO; using System.Threading; @@ -9,7 +10,7 @@ namespace GVFS.FunctionalTests.Tests.GitCommands [Category(Categories.GitCommands)] public class AddStageTests : GitRepoTests { - public AddStageTests(bool validateWorkingTree) + public AddStageTests(Settings.ValidateWorkingTreeMode validateWorkingTree) : base(enlistmentPerTest: false, validateWorkingTree: validateWorkingTree) { } diff --git a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/CheckoutTests.cs b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/CheckoutTests.cs index f8ae3833a5..f8cbb0b31b 100644 --- a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/CheckoutTests.cs +++ b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/CheckoutTests.cs @@ -1,4 +1,5 @@ -using GVFS.FunctionalTests.Should; +using GVFS.FunctionalTests.Properties; +using GVFS.FunctionalTests.Should; using GVFS.FunctionalTests.Tools; using GVFS.Tests.Should; using Microsoft.Win32.SafeHandles; @@ -15,7 +16,7 @@ namespace GVFS.FunctionalTests.Tests.GitCommands [Category(Categories.GitCommands)] public class CheckoutTests : GitRepoTests { - public CheckoutTests(bool validateWorkingTree) + public CheckoutTests(Settings.ValidateWorkingTreeMode validateWorkingTree) : base(enlistmentPerTest: true, validateWorkingTree: validateWorkingTree) { } @@ -238,11 +239,11 @@ public void CheckoutBranchAfterReadingAllFilesAndVerifyContentsCorrect() this.ValidateGitCommand("checkout " + GitRepoTests.ConflictTargetBranch); this.Enlistment.RepoRoot.ShouldBeADirectory(this.FileSystem) - .WithDeepStructure(this.FileSystem, this.ControlGitRepo.RootPath, compareContent: true); + .WithDeepStructure(this.FileSystem, this.ControlGitRepo.RootPath, compareContent: true, withinPrefixes: this.pathPrefixes); this.ValidateGitCommand("checkout " + GitRepoTests.ConflictSourceBranch); this.Enlistment.RepoRoot.ShouldBeADirectory(this.FileSystem) - .WithDeepStructure(this.FileSystem, this.ControlGitRepo.RootPath, compareContent: true); + .WithDeepStructure(this.FileSystem, this.ControlGitRepo.RootPath, compareContent: true, withinPrefixes: this.pathPrefixes); // Verify modified paths contents GVFSHelpers.ModifiedPathsContentsShouldEqual(this.Enlistment, this.FileSystem, "A .gitattributes" + GVFSHelpers.ModifiedPathsNewLine); diff --git a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/CherryPickConflictTests.cs b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/CherryPickConflictTests.cs index a428cef1ca..f6e508a798 100644 --- a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/CherryPickConflictTests.cs +++ b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/CherryPickConflictTests.cs @@ -1,4 +1,5 @@ -using NUnit.Framework; +using GVFS.FunctionalTests.Properties; +using NUnit.Framework; namespace GVFS.FunctionalTests.Tests.GitCommands { @@ -6,7 +7,7 @@ namespace GVFS.FunctionalTests.Tests.GitCommands [Category(Categories.GitCommands)] public class CherryPickConflictTests : GitRepoTests { - public CherryPickConflictTests(bool validateWorkingTree) + public CherryPickConflictTests(Settings.ValidateWorkingTreeMode validateWorkingTree) : base(enlistmentPerTest: true, validateWorkingTree: validateWorkingTree) { } diff --git a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/CreatePlaceholderTests.cs b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/CreatePlaceholderTests.cs index 7d1d8d8eef..8116824efe 100644 --- a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/CreatePlaceholderTests.cs +++ b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/CreatePlaceholderTests.cs @@ -1,4 +1,5 @@ -using GVFS.FunctionalTests.Should; +using GVFS.FunctionalTests.Properties; +using GVFS.FunctionalTests.Should; using GVFS.FunctionalTests.Tools; using NUnit.Framework; using System.IO; @@ -13,7 +14,7 @@ public class CreatePlaceholderTests : GitRepoTests { private static readonly string FileToRead = Path.Combine("GVFS", "GVFS", "Program.cs"); - public CreatePlaceholderTests(bool validateWorkingTree) + public CreatePlaceholderTests(Settings.ValidateWorkingTreeMode validateWorkingTree) : base(enlistmentPerTest: true, validateWorkingTree: validateWorkingTree) { } diff --git a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/DeleteEmptyFolderTests.cs b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/DeleteEmptyFolderTests.cs index f8cb410002..e7556d5694 100644 --- a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/DeleteEmptyFolderTests.cs +++ b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/DeleteEmptyFolderTests.cs @@ -1,5 +1,5 @@ -using GVFS.FunctionalTests.Should; -using GVFS.FunctionalTests.Tools; +using GVFS.FunctionalTests.Properties; +using GVFS.FunctionalTests.Should; using NUnit.Framework; namespace GVFS.FunctionalTests.Tests.GitCommands @@ -8,7 +8,7 @@ namespace GVFS.FunctionalTests.Tests.GitCommands [Category(Categories.GitCommands)] public class DeleteEmptyFolderTests : GitRepoTests { - public DeleteEmptyFolderTests(bool validateWorkingTree) + public DeleteEmptyFolderTests(Settings.ValidateWorkingTreeMode validateWorkingTree) : base(enlistmentPerTest: true, validateWorkingTree: validateWorkingTree) { } @@ -20,7 +20,7 @@ public void VerifyResetHardDeletesEmptyFolders() this.RunGitCommand("reset --hard HEAD"); this.Enlistment.RepoRoot.ShouldBeADirectory(this.FileSystem) - .WithDeepStructure(this.FileSystem, this.ControlGitRepo.RootPath); + .WithDeepStructure(this.FileSystem, this.ControlGitRepo.RootPath, withinPrefixes: this.pathPrefixes); } [TestCase] @@ -30,7 +30,7 @@ public void VerifyCleanDeletesEmptyFolders() this.RunGitCommand("clean -fd"); this.Enlistment.RepoRoot.ShouldBeADirectory(this.FileSystem) - .WithDeepStructure(this.FileSystem, this.ControlGitRepo.RootPath); + .WithDeepStructure(this.FileSystem, this.ControlGitRepo.RootPath, withinPrefixes: this.pathPrefixes); } private void SetupFolderDeleteTest() diff --git a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/EnumerationMergeTest.cs b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/EnumerationMergeTest.cs index 5163c365d1..6b2f0abee7 100644 --- a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/EnumerationMergeTest.cs +++ b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/EnumerationMergeTest.cs @@ -1,4 +1,5 @@ -using NUnit.Framework; +using GVFS.FunctionalTests.Properties; +using NUnit.Framework; namespace GVFS.FunctionalTests.Tests.GitCommands { @@ -10,7 +11,7 @@ public class EnumerationMergeTest : GitRepoTests // enumeration when they don't fit in a user's buffer private const string EnumerationReproCommitish = "FunctionalTests/20170602"; - public EnumerationMergeTest(bool validateWorkingTree) + public EnumerationMergeTest(Settings.ValidateWorkingTreeMode validateWorkingTree) : base(enlistmentPerTest: true, validateWorkingTree: validateWorkingTree) { } diff --git a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/GitCommandsTests.cs b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/GitCommandsTests.cs index 0c557158b5..b83db0d344 100644 --- a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/GitCommandsTests.cs +++ b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/GitCommandsTests.cs @@ -1,4 +1,5 @@ -using GVFS.FunctionalTests.Should; +using GVFS.FunctionalTests.Properties; +using GVFS.FunctionalTests.Should; using GVFS.FunctionalTests.Tools; using GVFS.Tests.Should; using NUnit.Framework; @@ -12,11 +13,11 @@ namespace GVFS.FunctionalTests.Tests.GitCommands [Category(Categories.GitCommands)] public class GitCommandsTests : GitRepoTests { + public const string TopLevelFolderToCreate = "level1"; private const string EncodingFileFolder = "FilenameEncoding"; private const string EncodingFilename = "ريلٌأكتوبرûمارسأغسطسºٰٰۂْٗ۵ريلٌأك.txt"; private const string ContentWhenEditingFile = "// Adding a comment to the file"; private const string UnknownTestName = "Unknown"; - private const string TopLevelFolderToCreate = "level1"; private const string SubFolderToCreate = "level2"; private static readonly string EditFilePath = Path.Combine("GVFS", "GVFS.Common", "GVFSContext.cs"); @@ -26,7 +27,7 @@ public class GitCommandsTests : GitRepoTests private static readonly string RenameFolderPathFrom = Path.Combine("GVFS", "GVFS.Common", "PrefetchPacks"); private static readonly string RenameFolderPathTo = Path.Combine("GVFS", "GVFS.Common", "PrefetchPacksRenamed"); - public GitCommandsTests(bool validateWorkingTree) + public GitCommandsTests(Settings.ValidateWorkingTreeMode validateWorkingTree) : base(enlistmentPerTest: false, validateWorkingTree: validateWorkingTree) { } @@ -586,7 +587,7 @@ public void AddFileCommitThenDeleteAndCommit() this.RunGitCommand("commit -m \"Delete file for AddFileCommitThenDeleteAndCommit\""); this.ValidateGitCommand("checkout tests/functional/AddFileCommitThenDeleteAndCommit_before"); this.Enlistment.RepoRoot.ShouldBeADirectory(this.FileSystem) - .WithDeepStructure(this.FileSystem, this.ControlGitRepo.RootPath); + .WithDeepStructure(this.FileSystem, this.ControlGitRepo.RootPath, withinPrefixes: this.pathPrefixes); this.ValidateGitCommand("checkout tests/functional/AddFileCommitThenDeleteAndCommit_after"); } @@ -674,7 +675,7 @@ public void AddFolderAndFileCommitThenResetSoftAndResetMixed() this.ValidateGitCommand("checkout -b tests/functional/AddFileCommitThenDeleteAndResetSoft"); string folderPath = "test_folder"; this.CreateFolder(folderPath); - string filePath = Path.Combine(folderPath + "testfile.txt"); + string filePath = Path.Combine(folderPath, "testfile.txt"); this.CreateFile("Some new content for the file", filePath); this.ValidateGitCommand("status"); this.ValidateGitCommand("add ."); @@ -1080,7 +1081,7 @@ private void CommitChangesSwitchBranchSwitchBack(Action fileSystemAction, [Calle this.RunGitCommand("commit -m \"Change for {0}\"", branch); this.ValidateGitCommand("checkout " + this.ControlGitRepo.Commitish); this.Enlistment.RepoRoot.ShouldBeADirectory(this.FileSystem) - .WithDeepStructure(this.FileSystem, this.ControlGitRepo.RootPath); + .WithDeepStructure(this.FileSystem, this.ControlGitRepo.RootPath, withinPrefixes: this.pathPrefixes); this.ValidateGitCommand("checkout {0}", branch); } diff --git a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/GitRepoTests.cs b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/GitRepoTests.cs index 6d42bd973e..8799cc24c4 100644 --- a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/GitRepoTests.cs +++ b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/GitRepoTests.cs @@ -1,10 +1,10 @@ using GVFS.FunctionalTests.FileSystemRunners; +using GVFS.FunctionalTests.Properties; using GVFS.FunctionalTests.Should; using GVFS.FunctionalTests.Tools; using GVFS.Tests.Should; using NUnit.Framework; -using NUnit.Framework.Interfaces; -using System; +using System.Collections.Generic; using System.IO; using System.Linq; @@ -22,10 +22,62 @@ public abstract class GitRepoTests protected const string DeepDirectoryWithOneFile = "FunctionalTests/20181010_DeepFolderOneFile"; protected const string DeepDirectoryWithOneDifferentFile = "FunctionalTests/20181010_DeepFolderOneDifferentFile"; + protected string[] pathPrefixes; + + // These are the folders for the include mode that are needed for the functional tests + // because they are the folders that the tests rely on to be there. + private static readonly string[] IncludeModeFolders = new string[] + { + "a", + "AddFileAfterFolderRename_Test", + "AddFileAfterFolderRename_TestRenamed", + "AddFoldersAndFilesAndRenameFolder_Test", + "AddFoldersAndFilesAndRenameFolder_TestRenamed", + "c", + "CheckoutNewBranchFromStartingPointTest", + "CheckoutOrhpanBranchFromStartingPointTest", + "d", + "DeleteFileWithNameAheadOfDotAndSwitchCommits", + "EnumerateAndReadTestFiles", + "ErrorWhenPathTreatsFileAsFolderMatchesNTFS", + "file.txt", // Changes to a folder in one test + "foo.cpp", // Changes to a folder in one test + "FilenameEncoding", + "GitCommandsTests", + "GVFlt_BugRegressionTest", + "GVFlt_DeleteFileTest", + "GVFlt_DeleteFolderTest", + "GVFlt_EnumTest", + "GVFlt_FileAttributeTest", + "GVFlt_FileEATest", + "GVFlt_FileOperationTest", + "GVFlt_MoveFileTest", + "GVFlt_MoveFolderTest", + "GVFlt_MultiThreadTest", + "GVFlt_SetLinkTest", + Path.Combine("GVFS", "GVFS"), + Path.Combine("GVFS", "GVFS.Common"), + GitCommandsTests.TopLevelFolderToCreate, + "ResetTwice_OnlyDeletes_Test", + "ResetTwice_OnlyEdits_Test", + "Test_ConflictTests", + "Test_EPF_GitCommandsTestOnlyFileFolder", + "Test_EPF_MoveRenameFileTests", + "Test_EPF_MoveRenameFileTests_2", + "Test_EPF_MoveRenameFolderTests", + "Test_EPF_UpdatePlaceholderTests", + "Test_EPF_WorkingDirectoryTests", + "test_folder", + "TrailingSlashTests", + }; + + // Add directory separator for matching paths since they should be directories + private static readonly string[] PathPrefixesForIncludeMode = IncludeModeFolders.Select(x => x + Path.DirectorySeparatorChar).ToArray(); + private bool enlistmentPerTest; - private bool validateWorkingTree; + private Settings.ValidateWorkingTreeMode validateWorkingTree; - public GitRepoTests(bool enlistmentPerTest, bool validateWorkingTree) + public GitRepoTests(bool enlistmentPerTest, Settings.ValidateWorkingTreeMode validateWorkingTree) { this.enlistmentPerTest = enlistmentPerTest; this.validateWorkingTree = validateWorkingTree; @@ -81,14 +133,20 @@ public virtual void SetupForTest() this.CreateEnlistment(); } + if (this.validateWorkingTree == Settings.ValidateWorkingTreeMode.IncludeMode) + { + new GVFSProcess(this.Enlistment).AddIncludedFolders(IncludeModeFolders); + this.pathPrefixes = PathPrefixesForIncludeMode; + } + this.ValidateGitCommand("checkout " + this.ControlGitRepo.Commitish); this.CheckHeadCommitTree(); - if (this.validateWorkingTree) - { - this.Enlistment.RepoRoot.ShouldBeADirectory(this.FileSystem) - .WithDeepStructure(this.FileSystem, this.ControlGitRepo.RootPath); + if (this.validateWorkingTree != Settings.ValidateWorkingTreeMode.None) + { + this.Enlistment.RepoRoot.ShouldBeADirectory(this.FileSystem) + .WithDeepStructure(this.FileSystem, this.ControlGitRepo.RootPath, withinPrefixes: this.pathPrefixes); } this.ValidateGitCommand("status"); @@ -106,10 +164,10 @@ protected void TestValidationAndCleanup(bool ignoreCase = false) { this.CheckHeadCommitTree(); - if (this.validateWorkingTree) + if (this.validateWorkingTree != Settings.ValidateWorkingTreeMode.None) { this.Enlistment.RepoRoot.ShouldBeADirectory(this.FileSystem) - .WithDeepStructure(this.FileSystem, this.ControlGitRepo.RootPath, ignoreCase: ignoreCase); + .WithDeepStructure(this.FileSystem, this.ControlGitRepo.RootPath, ignoreCase: ignoreCase, withinPrefixes: this.pathPrefixes); } this.RunGitCommand("reset --hard -q HEAD"); @@ -120,10 +178,10 @@ protected void TestValidationAndCleanup(bool ignoreCase = false) // If enlistmentPerTest is true we can always validate the working tree because // this is the last place we'll use it - if (this.validateWorkingTree || this.enlistmentPerTest) + if ((this.validateWorkingTree != Settings.ValidateWorkingTreeMode.None) || this.enlistmentPerTest) { this.Enlistment.RepoRoot.ShouldBeADirectory(this.FileSystem) - .WithDeepStructure(this.FileSystem, this.ControlGitRepo.RootPath, ignoreCase: ignoreCase); + .WithDeepStructure(this.FileSystem, this.ControlGitRepo.RootPath, ignoreCase: ignoreCase, withinPrefixes: this.pathPrefixes); } } finally diff --git a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/HashObjectTests.cs b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/HashObjectTests.cs index 242fcded84..b60b545978 100644 --- a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/HashObjectTests.cs +++ b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/HashObjectTests.cs @@ -1,4 +1,5 @@ -using GVFS.FunctionalTests.Should; +using GVFS.FunctionalTests.Properties; +using GVFS.FunctionalTests.Should; using GVFS.FunctionalTests.Tools; using NUnit.Framework; using System.IO; @@ -10,7 +11,7 @@ namespace GVFS.FunctionalTests.Tests.GitCommands public class HashObjectTests : GitRepoTests { public HashObjectTests() - : base(enlistmentPerTest: false, validateWorkingTree: false) + : base(enlistmentPerTest: false, validateWorkingTree: Settings.ValidateWorkingTreeMode.None) { } diff --git a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/MergeConflictTests.cs b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/MergeConflictTests.cs index 492d97e781..a602462e97 100644 --- a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/MergeConflictTests.cs +++ b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/MergeConflictTests.cs @@ -1,4 +1,5 @@ -using GVFS.FunctionalTests.Tools; +using GVFS.FunctionalTests.Properties; +using GVFS.FunctionalTests.Tools; using GVFS.Tests.Should; using NUnit.Framework; @@ -8,7 +9,7 @@ namespace GVFS.FunctionalTests.Tests.GitCommands [Category(Categories.GitCommands)] public class MergeConflictTests : GitRepoTests { - public MergeConflictTests(bool validateWorkingTree) + public MergeConflictTests(Settings.ValidateWorkingTreeMode validateWorkingTree) : base(enlistmentPerTest: true, validateWorkingTree: validateWorkingTree) { } diff --git a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/RebaseConflictTests.cs b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/RebaseConflictTests.cs index 1853897a7e..14282c8edf 100644 --- a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/RebaseConflictTests.cs +++ b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/RebaseConflictTests.cs @@ -1,4 +1,5 @@ -using NUnit.Framework; +using GVFS.FunctionalTests.Properties; +using NUnit.Framework; namespace GVFS.FunctionalTests.Tests.GitCommands { @@ -6,7 +7,7 @@ namespace GVFS.FunctionalTests.Tests.GitCommands [Category(Categories.GitCommands)] public class RebaseConflictTests : GitRepoTests { - public RebaseConflictTests(bool validateWorkingTree) + public RebaseConflictTests(Settings.ValidateWorkingTreeMode validateWorkingTree) : base(enlistmentPerTest: true, validateWorkingTree: validateWorkingTree) { } diff --git a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/RebaseTests.cs b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/RebaseTests.cs index 64f1d23532..9b60773af8 100644 --- a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/RebaseTests.cs +++ b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/RebaseTests.cs @@ -1,4 +1,5 @@ -using NUnit.Framework; +using GVFS.FunctionalTests.Properties; +using NUnit.Framework; namespace GVFS.FunctionalTests.Tests.GitCommands { @@ -6,7 +7,7 @@ namespace GVFS.FunctionalTests.Tests.GitCommands [Category(Categories.GitCommands)] public class RebaseTests : GitRepoTests { - public RebaseTests(bool validateWorkingTree) + public RebaseTests(Settings.ValidateWorkingTreeMode validateWorkingTree) : base(enlistmentPerTest: true, validateWorkingTree: validateWorkingTree) { } diff --git a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/ResetHardTests.cs b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/ResetHardTests.cs index 8fcaac274c..c41cc384d5 100644 --- a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/ResetHardTests.cs +++ b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/ResetHardTests.cs @@ -1,4 +1,5 @@ -using GVFS.FunctionalTests.Should; +using GVFS.FunctionalTests.Properties; +using GVFS.FunctionalTests.Should; using NUnit.Framework; namespace GVFS.FunctionalTests.Tests.GitCommands @@ -9,7 +10,7 @@ public class ResetHardTests : GitRepoTests { private const string ResetHardCommand = "reset --hard"; - public ResetHardTests(bool validateWorkingTree) + public ResetHardTests(Settings.ValidateWorkingTreeMode validateWorkingTree) : base(enlistmentPerTest: true, validateWorkingTree: validateWorkingTree) { } @@ -22,7 +23,7 @@ public void VerifyResetHardDeletesEmptyFolders() this.ValidateGitCommand("reset --hard HEAD~1"); this.ShouldNotExistOnDisk("Test_EPF_GitCommandsTestOnlyFileFolder"); this.Enlistment.RepoRoot.ShouldBeADirectory(this.FileSystem) - .WithDeepStructure(this.FileSystem, this.ControlGitRepo.RootPath); + .WithDeepStructure(this.FileSystem, this.ControlGitRepo.RootPath, withinPrefixes: this.pathPrefixes); } [TestCase] diff --git a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/ResetMixedTests.cs b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/ResetMixedTests.cs index 556c90dfd9..2d1e727a8a 100644 --- a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/ResetMixedTests.cs +++ b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/ResetMixedTests.cs @@ -1,4 +1,5 @@ -using GVFS.FunctionalTests.Should; +using GVFS.FunctionalTests.Properties; +using GVFS.FunctionalTests.Should; using NUnit.Framework; namespace GVFS.FunctionalTests.Tests.GitCommands @@ -7,7 +8,7 @@ namespace GVFS.FunctionalTests.Tests.GitCommands [Category(Categories.GitCommands)] public class ResetMixedTests : GitRepoTests { - public ResetMixedTests(bool validateWorkingTree) + public ResetMixedTests(Settings.ValidateWorkingTreeMode validateWorkingTree) : base(enlistmentPerTest: true, validateWorkingTree: validateWorkingTree) { } @@ -101,17 +102,17 @@ public void ResetMixedAndCheckoutFile() // Then reset --mixed to the parent commit, and validate that the deleted files did not come back into the projection this.ValidateGitCommand("reset --mixed HEAD~1"); this.Enlistment.RepoRoot.ShouldBeADirectory(this.FileSystem) - .WithDeepStructure(this.FileSystem, this.ControlGitRepo.RootPath); + .WithDeepStructure(this.FileSystem, this.ControlGitRepo.RootPath, withinPrefixes: this.pathPrefixes); // And checkout a file (without changing branches) and ensure that that doesn't update the projection either this.ValidateGitCommand("checkout HEAD~2 .gitattributes"); this.Enlistment.RepoRoot.ShouldBeADirectory(this.FileSystem) - .WithDeepStructure(this.FileSystem, this.ControlGitRepo.RootPath); + .WithDeepStructure(this.FileSystem, this.ControlGitRepo.RootPath, withinPrefixes: this.pathPrefixes); // And now if we checkout the original commit, the deleted files should stay deleted this.ValidateGitCommand("checkout FunctionalTests/20170602"); this.Enlistment.RepoRoot.ShouldBeADirectory(this.FileSystem) - .WithDeepStructure(this.FileSystem, this.ControlGitRepo.RootPath); + .WithDeepStructure(this.FileSystem, this.ControlGitRepo.RootPath, withinPrefixes: this.pathPrefixes); } protected override void CreateEnlistment() diff --git a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/ResetSoftTests.cs b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/ResetSoftTests.cs index fccf86de3c..064d874909 100644 --- a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/ResetSoftTests.cs +++ b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/ResetSoftTests.cs @@ -1,4 +1,5 @@ -using NUnit.Framework; +using GVFS.FunctionalTests.Properties; +using NUnit.Framework; namespace GVFS.FunctionalTests.Tests.GitCommands { @@ -6,7 +7,7 @@ namespace GVFS.FunctionalTests.Tests.GitCommands [Category(Categories.GitCommands)] public class ResetSoftTests : GitRepoTests { - public ResetSoftTests(bool validateWorkingTree) + public ResetSoftTests(Settings.ValidateWorkingTreeMode validateWorkingTree) : base(enlistmentPerTest: true, validateWorkingTree: validateWorkingTree) { } diff --git a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/RmTests.cs b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/RmTests.cs index e4414bfb47..2c430079d0 100644 --- a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/RmTests.cs +++ b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/RmTests.cs @@ -1,4 +1,5 @@ -using GVFS.FunctionalTests.Should; +using GVFS.FunctionalTests.Properties; +using GVFS.FunctionalTests.Should; using GVFS.FunctionalTests.Tools; using NUnit.Framework; using System.IO; @@ -9,7 +10,7 @@ namespace GVFS.FunctionalTests.Tests.GitCommands public class RmTests : GitRepoTests { public RmTests() - : base(enlistmentPerTest: false, validateWorkingTree: false) + : base(enlistmentPerTest: false, validateWorkingTree: Settings.ValidateWorkingTreeMode.None) { } diff --git a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/StatusTests.cs b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/StatusTests.cs index bc61b1b1b3..bc5c776c25 100644 --- a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/StatusTests.cs +++ b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/StatusTests.cs @@ -1,4 +1,5 @@ using GVFS.FunctionalTests.FileSystemRunners; +using GVFS.FunctionalTests.Properties; using GVFS.FunctionalTests.Should; using GVFS.FunctionalTests.Tools; using GVFS.Tests.Should; @@ -13,7 +14,7 @@ namespace GVFS.FunctionalTests.Tests.GitCommands [Category(Categories.GitCommands)] public class StatusTests : GitRepoTests { - public StatusTests(bool validateWorkingTree) + public StatusTests(Settings.ValidateWorkingTreeMode validateWorkingTree) : base(enlistmentPerTest: true, validateWorkingTree: validateWorkingTree) { } diff --git a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/UpdateIndexTests.cs b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/UpdateIndexTests.cs index 3424103259..b42d5c5281 100644 --- a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/UpdateIndexTests.cs +++ b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/UpdateIndexTests.cs @@ -1,4 +1,5 @@ -using GVFS.FunctionalTests.Tools; +using GVFS.FunctionalTests.Properties; +using GVFS.FunctionalTests.Tools; using NUnit.Framework; using System.IO; @@ -8,7 +9,7 @@ namespace GVFS.FunctionalTests.Tests.GitCommands [Category(Categories.GitCommands)] public class UpdateIndexTests : GitRepoTests { - public UpdateIndexTests(bool validateWorkingTree) + public UpdateIndexTests(Settings.ValidateWorkingTreeMode validateWorkingTree) : base(enlistmentPerTest: true, validateWorkingTree: validateWorkingTree) { } diff --git a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/UpdateRefTests.cs b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/UpdateRefTests.cs index f3c3eaa048..48084b9d1a 100644 --- a/GVFS/GVFS.FunctionalTests/Tests/GitCommands/UpdateRefTests.cs +++ b/GVFS/GVFS.FunctionalTests/Tests/GitCommands/UpdateRefTests.cs @@ -1,4 +1,5 @@ -using NUnit.Framework; +using GVFS.FunctionalTests.Properties; +using NUnit.Framework; namespace GVFS.FunctionalTests.Tests.GitCommands { @@ -6,7 +7,7 @@ namespace GVFS.FunctionalTests.Tests.GitCommands [Category(Categories.GitCommands)] public class UpdateRefTests : GitRepoTests { - public UpdateRefTests(bool validateWorkingTree) + public UpdateRefTests(Settings.ValidateWorkingTreeMode validateWorkingTree) : base(enlistmentPerTest: true, validateWorkingTree: validateWorkingTree) { } diff --git a/GVFS/GVFS.Tests/DataSources.cs b/GVFS/GVFS.Tests/DataSources.cs index c333ed1e03..1d7024f216 100644 --- a/GVFS/GVFS.Tests/DataSources.cs +++ b/GVFS/GVFS.Tests/DataSources.cs @@ -1,5 +1,4 @@ -using System; -namespace GVFS.Tests +namespace GVFS.Tests { public class DataSources { diff --git a/GVFS/GVFS.Tests/Should/EnumerableShouldExtensions.cs b/GVFS/GVFS.Tests/Should/EnumerableShouldExtensions.cs index d2899c7b25..db6eb443b4 100644 --- a/GVFS/GVFS.Tests/Should/EnumerableShouldExtensions.cs +++ b/GVFS/GVFS.Tests/Should/EnumerableShouldExtensions.cs @@ -23,8 +23,8 @@ public static IEnumerable ShouldBeNonEmpty(this IEnumerable group) public static Dictionary ShouldContain(this Dictionary dictionary, TKey key, TValue value) { TValue dictionaryValue; - dictionary.TryGetValue(key, out dictionaryValue).ShouldBeTrue(); - dictionaryValue.ShouldEqual(value); + dictionary.TryGetValue(key, out dictionaryValue).ShouldBeTrue($"Dictionary {nameof(ShouldContain)} does not contain {key}"); + dictionaryValue.ShouldEqual(value, $"Dictionary {nameof(ShouldContain)} does not match on key {key} expected: {value} actual: {dictionaryValue}"); return dictionary; }