using System; using System.Collections.Generic; using System.IO.Compression; using System.Linq; using System.Threading.Tasks; using Alphaleonis.Win32.Filesystem; using Microsoft.VisualStudio.TestTools.UnitTesting; using Wabbajack.Common; namespace Wabbajack.VirtualFileSystem.Test { [TestClass] public class VFSTests { private const string VFS_TEST_DIR = "vfs_test_dir"; private static readonly string VFS_TEST_DIR_FULL = Path.Combine(Directory.GetCurrentDirectory(), VFS_TEST_DIR); private Context context; public TestContext TestContext { get; set; } public WorkQueue Queue { get; set; } [TestInitialize] public void Setup() { Utils.LogMessages.Subscribe(f => TestContext.WriteLine(f.ShortDescription)); if (Directory.Exists(VFS_TEST_DIR)) Utils.DeleteDirectory(VFS_TEST_DIR); Directory.CreateDirectory(VFS_TEST_DIR); Queue = new WorkQueue(); context = new Context(Queue); } [TestMethod] public async Task FilesAreIndexed() { AddFile("test.txt", "This is a test"); await AddTestRoot(); var file = context.Index.ByFullPath[Path.Combine(VFS_TEST_DIR_FULL, "test.txt")]; Assert.IsNotNull(file); Assert.AreEqual(file.Size, 14); Assert.AreEqual(file.Hash, "qX0GZvIaTKM="); } private async Task AddTestRoot() { await context.AddRoot(VFS_TEST_DIR_FULL); await context.WriteToFile(Path.Combine(VFS_TEST_DIR_FULL, "vfs_cache.bin")); await context.IntegrateFromFile(Path.Combine(VFS_TEST_DIR_FULL, "vfs_cache.bin")); } [TestMethod] public async Task ArchiveContentsAreIndexed() { AddFile("archive/test.txt", "This is a test"); ZipUpFolder("archive", "test.zip"); await AddTestRoot(); var abs_path = Path.Combine(VFS_TEST_DIR_FULL, "test.zip"); var file = context.Index.ByFullPath[abs_path]; Assert.IsNotNull(file); Assert.AreEqual(128, file.Size); Assert.AreEqual(abs_path.FileHash(), file.Hash); Assert.IsTrue(file.IsArchive); var inner_file = file.Children.First(); Assert.AreEqual(14, inner_file.Size); Assert.AreEqual("qX0GZvIaTKM=", inner_file.Hash); Assert.AreSame(file, file.Children.First().Parent); } [TestMethod] public async Task DuplicateFileHashes() { AddFile("archive/test.txt", "This is a test"); ZipUpFolder("archive", "test.zip"); AddFile("test.txt", "This is a test"); await AddTestRoot(); var files = context.Index.ByHash["qX0GZvIaTKM="]; Assert.AreEqual(files.Count(), 2); } [TestMethod] public async Task DeletedFilesAreRemoved() { AddFile("test.txt", "This is a test"); await AddTestRoot(); var file = context.Index.ByFullPath[Path.Combine(VFS_TEST_DIR_FULL, "test.txt")]; Assert.IsNotNull(file); Assert.AreEqual(file.Size, 14); Assert.AreEqual(file.Hash, "qX0GZvIaTKM="); File.Delete(Path.Combine(VFS_TEST_DIR_FULL, "test.txt")); await AddTestRoot(); CollectionAssert.DoesNotContain(context.Index.ByFullPath, Path.Combine(VFS_TEST_DIR_FULL, "test.txt")); } [TestMethod] public async Task UnmodifiedFilesAreNotReIndexed() { AddFile("test.txt", "This is a test"); await AddTestRoot(); var old_file = context.Index.ByFullPath[Path.Combine(VFS_TEST_DIR_FULL, "test.txt")]; var old_time = old_file.LastAnalyzed; await AddTestRoot(); var new_file = context.Index.ByFullPath[Path.Combine(VFS_TEST_DIR_FULL, "test.txt")]; Assert.AreEqual(old_time, new_file.LastAnalyzed); } [TestMethod] public async Task CanStageSimpleArchives() { AddFile("archive/test.txt", "This is a test"); ZipUpFolder("archive", "test.zip"); await AddTestRoot(); var abs_path = Path.Combine(VFS_TEST_DIR_FULL, "test.zip"); var file = context.Index.ByFullPath[abs_path + "|test.txt"]; var cleanup = await context.Stage(new List {file}); Assert.AreEqual("This is a test", File.ReadAllText(file.StagedPath)); cleanup(); } [TestMethod] public async Task CanStageNestedArchives() { AddFile("archive/test.txt", "This is a test"); ZipUpFolder("archive", "test.zip"); Directory.CreateDirectory(Path.Combine(VFS_TEST_DIR_FULL, @"archive\other\dir")); File.Move(Path.Combine(VFS_TEST_DIR_FULL, "test.zip"), Path.Combine(VFS_TEST_DIR_FULL, @"archive\other\dir\nested.zip")); ZipUpFolder("archive", "test.zip"); await AddTestRoot(); var files = context.Index.ByHash["qX0GZvIaTKM="]; var cleanup = await context.Stage(files); foreach (var file in files) Assert.AreEqual("This is a test", File.ReadAllText(file.StagedPath)); cleanup(); } [TestMethod] public async Task CanRequestPortableFileTrees() { AddFile("archive/test.txt", "This is a test"); ZipUpFolder("archive", "test.zip"); Directory.CreateDirectory(Path.Combine(VFS_TEST_DIR_FULL, @"archive\other\dir")); File.Move(Path.Combine(VFS_TEST_DIR_FULL, "test.zip"), Path.Combine(VFS_TEST_DIR_FULL, @"archive\other\dir\nested.zip")); ZipUpFolder("archive", "test.zip"); await AddTestRoot(); var files = context.Index.ByHash["qX0GZvIaTKM="]; var archive = context.Index.ByRootPath[Path.Combine(VFS_TEST_DIR_FULL, "test.zip")]; var state = context.GetPortableState(files); var new_context = new Context(Queue); await new_context.IntegrateFromPortable(state, new Dictionary {{archive.Hash, archive.FullPath}}); var new_files = new_context.Index.ByHash["qX0GZvIaTKM="]; var close = await new_context.Stage(new_files); foreach (var file in new_files) Assert.AreEqual("This is a test", File.ReadAllText(file.StagedPath)); close(); } private static void AddFile(string filename, string thisIsATest) { var fullpath = Path.Combine(VFS_TEST_DIR, filename); if (!Directory.Exists(Path.GetDirectoryName(fullpath))) Directory.CreateDirectory(Path.GetDirectoryName(fullpath)); File.WriteAllText(fullpath, thisIsATest); } private static void ZipUpFolder(string folder, string output) { var path = Path.Combine(VFS_TEST_DIR, folder); ZipFile.CreateFromDirectory(path, Path.Combine(VFS_TEST_DIR, output)); Utils.DeleteDirectory(path); } } }