using System; using System.IO; using System.Linq; using System.Text; using Moq; using NUnit.Framework; using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.Scoping; using Umbraco.Tests.TestHelpers; namespace Umbraco.Tests.IO { [TestFixture] public class ShadowFileSystemTests { // tested: // only 1 instance of this class is created // SetUp and TearDown run before/after each test // SetUp does not start before the previous TearDown returns [SetUp] public void SetUp() { SafeCallContext.Clear(); ClearFiles(); ShadowFileSystems.ResetId(); } [TearDown] public void TearDown() { SafeCallContext.Clear(); ClearFiles(); ShadowFileSystems.ResetId(); } private static void ClearFiles() { TestHelper.DeleteDirectory(IOHelper.MapPath("FileSysTests")); TestHelper.DeleteDirectory(IOHelper.MapPath("App_Data")); } private static string NormPath(string path) { return path.ToLowerInvariant().Replace("\\", "/"); } [Test] public void ShadowDeleteDirectory() { var path = IOHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore"); var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); Directory.CreateDirectory(path + "/ShadowTests/d1"); Directory.CreateDirectory(path + "/ShadowTests/d2"); var files = fs.GetFiles(""); Assert.AreEqual(0, files.Count()); var dirs = fs.GetDirectories(""); Assert.AreEqual(2, dirs.Count()); Assert.IsTrue(dirs.Contains("d1")); Assert.IsTrue(dirs.Contains("d2")); ss.DeleteDirectory("d1"); Assert.IsTrue(Directory.Exists(path + "/ShadowTests/d1")); Assert.IsTrue(fs.DirectoryExists("d1")); Assert.IsFalse(ss.DirectoryExists("d1")); dirs = ss.GetDirectories(""); Assert.AreEqual(1, dirs.Count()); Assert.IsTrue(dirs.Contains("d2")); } [Test] public void ShadowDeleteDirectoryInDir() { var path = IOHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore"); var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); Directory.CreateDirectory(path + "/ShadowTests/sub"); Directory.CreateDirectory(path + "/ShadowTests/sub/d1"); Directory.CreateDirectory(path + "/ShadowTests/sub/d2"); var files = fs.GetFiles(""); Assert.AreEqual(0, files.Count()); var dirs = ss.GetDirectories(""); Assert.AreEqual(1, dirs.Count()); Assert.IsTrue(dirs.Contains("sub")); dirs = fs.GetDirectories("sub"); Assert.AreEqual(2, dirs.Count()); Assert.IsTrue(dirs.Contains("sub/d1")); Assert.IsTrue(dirs.Contains("sub/d2")); dirs = ss.GetDirectories("sub"); Assert.AreEqual(2, dirs.Count()); Assert.IsTrue(dirs.Contains("sub/d1")); Assert.IsTrue(dirs.Contains("sub/d2")); ss.DeleteDirectory("sub/d1"); Assert.IsTrue(Directory.Exists(path + "/ShadowTests/sub/d1")); Assert.IsTrue(fs.DirectoryExists("sub/d1")); Assert.IsFalse(ss.DirectoryExists("sub/d1")); dirs = fs.GetDirectories("sub"); Assert.AreEqual(2, dirs.Count()); Assert.IsTrue(dirs.Contains("sub/d1")); Assert.IsTrue(dirs.Contains("sub/d2")); dirs = ss.GetDirectories("sub"); Assert.AreEqual(1, dirs.Count()); Assert.IsTrue(dirs.Contains("sub/d2")); } [Test] public void ShadowDeleteFile() { var path = IOHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore"); var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); File.WriteAllText(path + "/ShadowTests/f1.txt", "foo"); File.WriteAllText(path + "/ShadowTests/f2.txt", "foo"); var files = fs.GetFiles(""); Assert.AreEqual(2, files.Count()); Assert.IsTrue(files.Contains("f1.txt")); Assert.IsTrue(files.Contains("f2.txt")); files = ss.GetFiles(""); Assert.AreEqual(2, files.Count()); Assert.IsTrue(files.Contains("f1.txt")); Assert.IsTrue(files.Contains("f2.txt")); var dirs = ss.GetDirectories(""); Assert.AreEqual(0, dirs.Count()); ss.DeleteFile("f1.txt"); Assert.IsTrue(File.Exists(path + "/ShadowTests/f1.txt")); Assert.IsTrue(fs.FileExists("f1.txt")); Assert.IsFalse(ss.FileExists("f1.txt")); files = ss.GetFiles(""); Assert.AreEqual(1, files.Count()); Assert.IsTrue(files.Contains("f2.txt")); } [Test] public void ShadowDeleteFileInDir() { var path = IOHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore"); var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); Directory.CreateDirectory(path + "/ShadowTests/sub"); File.WriteAllText(path + "/ShadowTests/sub/f1.txt", "foo"); File.WriteAllText(path + "/ShadowTests/sub/f2.txt", "foo"); var files = fs.GetFiles(""); Assert.AreEqual(0, files.Count()); files = fs.GetFiles("sub"); Assert.AreEqual(2, files.Count()); Assert.IsTrue(files.Contains("sub/f1.txt")); Assert.IsTrue(files.Contains("sub/f2.txt")); files = ss.GetFiles(""); Assert.AreEqual(0, files.Count()); var dirs = ss.GetDirectories(""); Assert.AreEqual(1, dirs.Count()); Assert.IsTrue(dirs.Contains("sub")); files = ss.GetFiles("sub"); Assert.AreEqual(2, files.Count()); Assert.IsTrue(files.Contains("sub/f1.txt")); Assert.IsTrue(files.Contains("sub/f2.txt")); dirs = ss.GetDirectories("sub"); Assert.AreEqual(0, dirs.Count()); ss.DeleteFile("sub/f1.txt"); Assert.IsTrue(File.Exists(path + "/ShadowTests/sub/f1.txt")); Assert.IsTrue(fs.FileExists("sub/f1.txt")); Assert.IsFalse(ss.FileExists("sub/f1.txt")); files = fs.GetFiles("sub"); Assert.AreEqual(2, files.Count()); Assert.IsTrue(files.Contains("sub/f1.txt")); Assert.IsTrue(files.Contains("sub/f2.txt")); files = ss.GetFiles("sub"); Assert.AreEqual(1, files.Count()); Assert.IsTrue(files.Contains("sub/f2.txt")); } [Test] public void ShadowCantCreateFile() { var path = IOHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore"); var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); Assert.Throws(() => { using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) ss.AddFile("../../f1.txt", ms); }); } [Test] public void ShadowCreateFile() { var path = IOHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore"); var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); File.WriteAllText(path + "/ShadowTests/f2.txt", "foo"); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) ss.AddFile("f1.txt", ms); Assert.IsTrue(File.Exists(path + "/ShadowTests/f2.txt")); Assert.IsFalse(File.Exists(path + "/ShadowSystem/f2.txt")); Assert.IsTrue(fs.FileExists("f2.txt")); Assert.IsTrue(ss.FileExists("f2.txt")); Assert.IsFalse(File.Exists(path + "/ShadowTests/f1.txt")); Assert.IsTrue(File.Exists(path + "/ShadowSystem/f1.txt")); Assert.IsFalse(fs.FileExists("f1.txt")); Assert.IsTrue(ss.FileExists("f1.txt")); var files = ss.GetFiles(""); Assert.AreEqual(2, files.Count()); Assert.IsTrue(files.Contains("f1.txt")); Assert.IsTrue(files.Contains("f2.txt")); string content; using (var stream = ss.OpenFile("f1.txt")) content = new StreamReader(stream).ReadToEnd(); Assert.AreEqual("foo", content); } [Test] public void ShadowCreateFileInDir() { var path = IOHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore"); var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) ss.AddFile("sub/f1.txt", ms); Assert.IsFalse(File.Exists(path + "/ShadowTests/sub/f1.txt")); Assert.IsTrue(File.Exists(path + "/ShadowSystem/sub/f1.txt")); Assert.IsFalse(fs.FileExists("sub/f1.txt")); Assert.IsTrue(ss.FileExists("sub/f1.txt")); Assert.IsFalse(fs.DirectoryExists("sub")); Assert.IsTrue(ss.DirectoryExists("sub")); var dirs = fs.GetDirectories(""); Assert.AreEqual(0, dirs.Count()); dirs = ss.GetDirectories(""); Assert.AreEqual(1, dirs.Count()); Assert.IsTrue(dirs.Contains("sub")); var files = ss.GetFiles("sub"); Assert.AreEqual(1, files.Count()); string content; using (var stream = ss.OpenFile("sub/f1.txt")) content = new StreamReader(stream).ReadToEnd(); Assert.AreEqual("foo", content); } [Test] public void ShadowAbort() { var path = IOHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore"); var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) ss.AddFile("path/to/some/dir/f1.txt", ms); // file is only written to the shadow fs Assert.IsTrue(File.Exists(path + "/ShadowSystem/path/to/some/dir/f1.txt")); Assert.IsFalse(File.Exists(path + "/ShadowTests/path/to/some/dir/f1.txt")); // let the shadow fs die } [Test] public void ShadowComplete() { var path = IOHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore"); var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); Directory.CreateDirectory(path + "/ShadowTests/sub/sub"); File.WriteAllText(path + "/ShadowTests/sub/sub/f2.txt", "foo"); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) ss.AddFile("path/to/some/dir/f1.txt", ms); ss.DeleteFile("sub/sub/f2.txt"); Assert.IsTrue(File.Exists(path + "/ShadowSystem/path/to/some/dir/f1.txt")); ss.Complete(); // yes we are cleaning now //Assert.IsTrue(File.Exists(path + "/ShadowSystem/path/to/some/dir/f1.txt")); // *not* cleaning Assert.IsTrue(File.Exists(path + "/ShadowTests/path/to/some/dir/f1.txt")); Assert.IsFalse(File.Exists(path + "/ShadowTests/sub/sub/f2.txt")); } [Test] public void ShadowScopeComplete() { var path = IOHelper.MapPath("FileSysTests"); var appdata = IOHelper.MapPath("App_Data"); Directory.CreateDirectory(path); Directory.CreateDirectory(appdata); var scopedFileSystems = false; var scopeProvider = MockScopeProvider(() => scopedFileSystems); var fs = new PhysicalFileSystem(path, "ignore"); var sw = new ShadowWrapper(fs, "shadow", scopeProvider); var swa = new[] { sw }; using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) sw.AddFile("sub/f1.txt", ms); Assert.IsTrue(fs.FileExists("sub/f1.txt")); Guid id; // explicit shadow without scope does not work sw.Shadow(id = Guid.NewGuid()); Assert.IsTrue(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id)); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) sw.AddFile("sub/f2.txt", ms); Assert.IsTrue(fs.FileExists("sub/f2.txt")); sw.UnShadow(true); Assert.IsTrue(fs.FileExists("sub/f2.txt")); Assert.IsFalse(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id)); // shadow with scope but no complete does not complete scopedFileSystems = true; // pretend we have a scope var scope = new ShadowFileSystems(id = Guid.NewGuid(), swa); Assert.IsTrue(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id)); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) sw.AddFile("sub/f3.txt", ms); Assert.IsFalse(fs.FileExists("sub/f3.txt")); Assert.AreEqual(1, Directory.GetDirectories(appdata + "/TEMP/ShadowFs").Length); scope.Dispose(); scopedFileSystems = false; Assert.IsFalse(fs.FileExists("sub/f3.txt")); Assert.IsFalse(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id)); // shadow with scope and complete does complete scopedFileSystems = true; // pretend we have a scope scope = new ShadowFileSystems(id = Guid.NewGuid(), swa); Assert.IsTrue(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id)); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) sw.AddFile("sub/f4.txt", ms); Assert.IsFalse(fs.FileExists("sub/f4.txt")); Assert.AreEqual(1, Directory.GetDirectories(appdata + "/TEMP/ShadowFs").Length); scope.Complete(); scope.Dispose(); scopedFileSystems = false; TestHelper.TryAssert(() => Assert.AreEqual(0, Directory.GetDirectories(appdata + "/TEMP/ShadowFs").Length)); Assert.IsTrue(fs.FileExists("sub/f4.txt")); Assert.IsFalse(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id)); // test scope for "another thread" scopedFileSystems = true; // pretend we have a scope scope = new ShadowFileSystems(id = Guid.NewGuid(), swa); Assert.IsTrue(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id)); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) sw.AddFile("sub/f5.txt", ms); Assert.IsFalse(fs.FileExists("sub/f5.txt")); // pretend we're another thread w/out scope scopedFileSystems = false; using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) sw.AddFile("sub/f6.txt", ms); scopedFileSystems = true; // pretend we have a scope Assert.IsTrue(fs.FileExists("sub/f6.txt")); // other thread has written out to fs scope.Complete(); scope.Dispose(); scopedFileSystems = false; Assert.IsTrue(fs.FileExists("sub/f5.txt")); Assert.IsFalse(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id)); } [Test] public void ShadowScopeCompleteWithFileConflict() { var path = IOHelper.MapPath("FileSysTests"); var appdata = IOHelper.MapPath("App_Data"); Directory.CreateDirectory(path); var scopedFileSystems = false; var scopeProvider = MockScopeProvider(() => scopedFileSystems); var fs = new PhysicalFileSystem(path, "ignore"); var sw = new ShadowWrapper(fs, "shadow", scopeProvider); var swa = new[] { sw }; using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) sw.AddFile("sub/f1.txt", ms); Assert.IsTrue(fs.FileExists("sub/f1.txt")); Guid id; scopedFileSystems = true; // pretend we have a scope var scope = new ShadowFileSystems(id = Guid.NewGuid(), swa); Assert.IsTrue(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id)); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) sw.AddFile("sub/f2.txt", ms); Assert.IsFalse(fs.FileExists("sub/f2.txt")); // pretend we're another thread w/out scope scopedFileSystems = false; using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("bar"))) sw.AddFile("sub/f2.txt", ms); scopedFileSystems = true; // pretend we have a scope Assert.IsTrue(fs.FileExists("sub/f2.txt")); // other thread has written out to fs scope.Complete(); scope.Dispose(); scopedFileSystems = false; Assert.IsTrue(fs.FileExists("sub/f2.txt")); TestHelper.TryAssert(() => Assert.IsFalse(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id))); string text; using (var s = fs.OpenFile("sub/f2.txt")) using (var r = new StreamReader(s)) text = r.ReadToEnd(); // the shadow filesystem will happily overwrite anything it can Assert.AreEqual("foo", text); } [Test] public void ShadowScopeCompleteWithDirectoryConflict() { var path = IOHelper.MapPath("FileSysTests"); var appdata = IOHelper.MapPath("App_Data"); Directory.CreateDirectory(path); var scopedFileSystems = false; var scopeProvider = MockScopeProvider(() => scopedFileSystems); var fs = new PhysicalFileSystem(path, "ignore"); var sw = new ShadowWrapper(fs, "shadow", scopeProvider); var swa = new[] { sw }; using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) sw.AddFile("sub/f1.txt", ms); Assert.IsTrue(fs.FileExists("sub/f1.txt")); Guid id; scopedFileSystems = true; // pretend we have a scope var scope = new ShadowFileSystems(id = Guid.NewGuid(), swa); Assert.IsTrue(Directory.Exists(appdata + "/TEMP/ShadowFs/" + id)); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) sw.AddFile("sub/f2.txt", ms); Assert.IsFalse(fs.FileExists("sub/f2.txt")); // pretend we're another thread w/out scope scopedFileSystems = false; using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("bar"))) sw.AddFile("sub/f2.txt/f2.txt", ms); scopedFileSystems = true; // pretend we have a scope Assert.IsTrue(fs.FileExists("sub/f2.txt/f2.txt")); // other thread has written out to fs using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) sw.AddFile("sub/f3.txt", ms); Assert.IsFalse(fs.FileExists("sub/f3.txt")); scope.Complete(); try { // no way this can work since we're trying to write a file // but there's now a directory with the same name on the real fs scope.Dispose(); Assert.Fail("Expected AggregateException."); } catch (AggregateException ae) { Assert.AreEqual(1, ae.InnerExceptions.Count); var e = ae.InnerExceptions[0]; Assert.IsNotNull(e.InnerException); Assert.IsInstanceOf(e); ae = (AggregateException)e; Assert.AreEqual(1, ae.InnerExceptions.Count); e = ae.InnerExceptions[0]; Assert.IsNotNull(e.InnerException); Assert.IsInstanceOf(e.InnerException); } // still, the rest of the changes has been applied ok Assert.IsTrue(fs.FileExists("sub/f3.txt")); } [Test] public void GetFilesReturnsChildrenOnly() { var path = IOHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); File.WriteAllText(path + "/f1.txt", "foo"); Directory.CreateDirectory(path + "/test"); File.WriteAllText(path + "/test/f2.txt", "foo"); Directory.CreateDirectory(path + "/test/inner"); File.WriteAllText(path + "/test/inner/f3.txt", "foo"); path = NormPath(path); var files = Directory.GetFiles(path); Assert.AreEqual(1, files.Length); files = Directory.GetFiles(path, "*", SearchOption.AllDirectories); Assert.AreEqual(3, files.Length); var efiles = Directory.EnumerateFiles(path); Assert.AreEqual(1, efiles.Count()); efiles = Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories); Assert.AreEqual(3, efiles.Count()); } [Test] public void DeleteDirectoryAndFiles() { var path = IOHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); File.WriteAllText(path + "/f1.txt", "foo"); Directory.CreateDirectory(path + "/test"); File.WriteAllText(path + "/test/f2.txt", "foo"); Directory.CreateDirectory(path + "/test/inner"); File.WriteAllText(path + "/test/inner/f3.txt", "foo"); path = NormPath(path); TestHelper.Try(() => Directory.Delete(path, true)); TestHelper.TryAssert(() => Assert.IsFalse(File.Exists(path + "/test/inner/f3.txt"))); } [Test] public void MockTest() { var scoped = false; var provider = MockScopeProvider(() => scoped); Assert.IsFalse(provider.AmbientScope.ScopedFileSystems); scoped = true; Assert.IsTrue(provider.AmbientScope.ScopedFileSystems); } private static IScopeProviderInternal MockScopeProvider(Func f) { var scopeMock = new Mock(); scopeMock.Setup(x => x.ScopedFileSystems).Returns(f); var providerMock = new Mock(); providerMock.Setup(x => x.AmbientScope).Returns(scopeMock.Object); return providerMock.Object; } /// /// Check that GetFiles will return all files on the shadow, while returning /// just one on each of the filesystems used by the shadow. /// [Test] public void ShadowGetFiles() { // Arrange var path = IOHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore"); var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); // Act File.WriteAllText(path + "/ShadowTests/f2.txt", "foo"); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) ss.AddFile("f1.txt", ms); // Assert // ensure we get 2 files from the shadow var getFiles = ss.GetFiles(string.Empty); Assert.AreEqual(2, getFiles.Count()); var fsFiles = fs.GetFiles(string.Empty).ToArray(); Assert.AreEqual(1, fsFiles.Length); var sfsFiles = sfs.GetFiles(string.Empty).ToArray(); Assert.AreEqual(1, sfsFiles.Length); } /// /// Check that GetFiles using the filter function with empty string will return expected results /// [Test] public void ShadowGetFilesUsingEmptyFilter() { // Arrange var path = IOHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore"); var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); // Act File.WriteAllText(path + "/ShadowTests/f2.txt", "foo"); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) ss.AddFile("f1.txt", ms); // Assert // ensure we get 2 files from the shadow var getFiles = ss.GetFiles(string.Empty); Assert.AreEqual(2, getFiles.Count()); // ensure we get 0 files when using a empty filter var getFilesWithEmptyFilter = ss.GetFiles(string.Empty, ""); Assert.AreEqual(0, getFilesWithEmptyFilter.Count()); var fsFiles = fs.GetFiles(string.Empty).ToArray(); Assert.AreEqual(1, fsFiles.Length); var sfsFiles = sfs.GetFiles(string.Empty).ToArray(); Assert.AreEqual(1, sfsFiles.Length); } /// /// Check that GetFiles using the filter function with null will return expected results /// [Test] public void ShadowGetFilesUsingNullFilter() { // Arrange var path = IOHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore"); var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); // Act File.WriteAllText(path + "/ShadowTests/f2.txt", "foo"); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) ss.AddFile("f1.txt", ms); // Assert // ensure we get 2 files from the shadow var getFiles = ss.GetFiles(string.Empty); Assert.AreEqual(2, getFiles.Count()); // ensure we get 2 files when using null in filter parameter var getFilesWithNullFilter = ss.GetFiles(string.Empty, null); Assert.AreEqual(2, getFilesWithNullFilter.Count()); var fsFiles = fs.GetFiles(string.Empty).ToArray(); Assert.AreEqual(1, fsFiles.Length); var sfsFiles = sfs.GetFiles(string.Empty).ToArray(); Assert.AreEqual(1, sfsFiles.Length); } [Test] public void ShadowGetFilesUsingWildcardFilter() { // Arrange var path = IOHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore"); var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); // Act File.WriteAllText(path + "/ShadowTests/f2.txt", "foo"); File.WriteAllText(path + "/ShadowTests/f2.doc", "foo"); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) ss.AddFile("f1.txt", ms); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) ss.AddFile("f1.doc", ms); // Assert // ensure we get 4 files from the shadow var getFiles = ss.GetFiles(string.Empty); Assert.AreEqual(4, getFiles.Count()); // ensure we get only 2 of 4 files from the shadow when using filter var getFilesWithWildcardFilter = ss.GetFiles(string.Empty, "*.doc"); Assert.AreEqual(2, getFilesWithWildcardFilter.Count()); var fsFiles = fs.GetFiles(string.Empty).ToArray(); Assert.AreEqual(2, fsFiles.Length); var sfsFiles = sfs.GetFiles(string.Empty).ToArray(); Assert.AreEqual(2, sfsFiles.Length); } [Test] public void ShadowGetFilesUsingSingleCharacterFilter() { // Arrange var path = IOHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore"); var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); // Act File.WriteAllText(path + "/ShadowTests/f2.txt", "foo"); File.WriteAllText(path + "/ShadowTests/f2.doc", "foo"); File.WriteAllText(path + "/ShadowTests/f2.docx", "foo"); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) ss.AddFile("f1.txt", ms); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) ss.AddFile("f1.doc", ms); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) ss.AddFile("f1.docx", ms); // Assert // ensure we get 6 files from the shadow var getFiles = ss.GetFiles(string.Empty); Assert.AreEqual(6, getFiles.Count()); // ensure we get only 2 of 6 files from the shadow when using filter on shadow var getFilesWithWildcardSinglecharFilter = ss.GetFiles(string.Empty, "f1.d?c"); Assert.AreEqual(1, getFilesWithWildcardSinglecharFilter.Count()); // ensure we get only 2 of 6 files from the shadow when using filter on disk var getFilesWithWildcardSinglecharFilter2 = ss.GetFiles(string.Empty, "f2.d?c"); Assert.AreEqual(1, getFilesWithWildcardSinglecharFilter2.Count()); var fsFiles = fs.GetFiles(string.Empty).ToArray(); Assert.AreEqual(3, fsFiles.Length); var sfsFiles = sfs.GetFiles(string.Empty).ToArray(); Assert.AreEqual(3, sfsFiles.Length); } [Test] [Ignore("Does not work on all environments, Directory.GetFiles is broken.")] public void ShadowGetFilesUsingWildcardAndSingleCharacterFilter() { // Arrange var path = IOHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore"); var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); // Act File.WriteAllText(path + "/ShadowTests/f2.txt", "foo"); File.WriteAllText(path + "/ShadowTests/f2.doc", "foo"); File.WriteAllText(path + "/ShadowTests/f2.docx", "foo"); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) ss.AddFile("f1.txt", ms); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) ss.AddFile("f1.doc", ms); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) ss.AddFile("f1.docx", ms); // Assert // ensure we get 6 files from the shadow var getFiles = ss.GetFiles(string.Empty); Assert.AreEqual(6, getFiles.Count()); var getFilesWithWildcardSinglecharFilter = ss.GetFiles(string.Empty, "*.d?c"); Assert.AreEqual(4, getFilesWithWildcardSinglecharFilter.Count()); var getFilesWithWildcardSinglecharFilter2 = ss.GetFiles(string.Empty, "*.d?cx"); Assert.AreEqual(2, getFilesWithWildcardSinglecharFilter2.Count()); var fsFiles = fs.GetFiles(string.Empty).ToArray(); Assert.AreEqual(3, fsFiles.Length); var sfsFiles = sfs.GetFiles(string.Empty).ToArray(); Assert.AreEqual(3, sfsFiles.Length); } [Test] [Ignore("Does not work on all environments, Directory.GetFiles is broken.")] public void ShadowFileSystemFilterIsAsBrokenAsRealFileSystemFilter() { // Arrange var path = IOHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/filter"); // create files on disk and create a "fake" list of files to verify filters against File.WriteAllText(path + "/filter/f1.txt", "foo"); File.WriteAllText(path + "/filter/f1.doc", "foo"); File.WriteAllText(path + "/filter/f1.docx", "foo"); var files = new string[] { "f1.txt", "f1.doc", "f1.docx", }; var filter1 = ""; var filter2 = "*"; var filter3 = "*.doc"; var filter4 = "*.d?c"; var filter5 = "f1.doc"; var filter6 = "f1.d?c"; var filter7 = "**.d?c"; var filter8 = "f*.doc"; // Act & Assert var result1Disk = Directory.GetFiles(path + "/filter/", filter1).Select(Path.GetFileName).OrderBy(x => x).ToArray(); var result1Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter1))).OrderBy(x => x).ToArray(); Assert.AreEqual(result1Disk, result1Fake); var result2Disk = Directory.GetFiles(path + "/filter/", filter2).Select(Path.GetFileName).OrderBy(x => x).ToArray(); var result2Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter2))).OrderBy(x => x).ToArray(); Assert.AreEqual(result2Disk, result2Fake); var result3Disk = Directory.GetFiles(path + "/filter/", filter3).Select(Path.GetFileName).OrderBy(x => x).ToArray(); var result3Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter3))).OrderBy(x => x).ToArray(); Assert.AreEqual(result3Disk, result3Fake); var result4Disk = Directory.GetFiles(path + "/filter/", filter4).Select(Path.GetFileName).OrderBy(x => x).ToArray(); var result4Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter4))).OrderBy(x => x).ToArray(); Assert.AreEqual(result4Disk, result4Fake); var result5Disk = Directory.GetFiles(path + "/filter/", filter5).Select(Path.GetFileName).OrderBy(x => x).ToArray(); var result5Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter5))).OrderBy(x => x).ToArray(); Assert.AreEqual(result5Disk, result5Fake); var result6Disk = Directory.GetFiles(path + "/filter/", filter6).Select(Path.GetFileName).OrderBy(x => x).ToArray(); var result6Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter6))).OrderBy(x => x).ToArray(); Assert.AreEqual(result6Disk, result6Fake); var result7Disk = Directory.GetFiles(path + "/filter/", filter7).Select(Path.GetFileName).OrderBy(x => x).ToArray(); var result7Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter7))).OrderBy(x => x).ToArray(); Assert.AreEqual(result7Disk, result7Fake); var result8Disk = Directory.GetFiles(path + "/filter/", filter8).Select(Path.GetFileName).OrderBy(x => x).ToArray(); var result8Fake = files.Where(x => ShadowFileSystem.FilterByRegex(x, ShadowFileSystem.FilterToRegex(filter8))).OrderBy(x => x).ToArray(); Assert.AreEqual(result8Disk, result8Fake); } /// /// Returns the full paths of the files on the disk. /// Note that this will be the *actual* path of the file, meaning a file existing on the initialized FS /// will be in one location, while a file written after initializing the shadow, will exist at the /// shadow location directory. /// [Test] public void ShadowGetFullPath() { // Arrange var path = IOHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore"); var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); // Act File.WriteAllText(path + "/ShadowTests/f1.txt", "foo"); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) ss.AddFile("f2.txt", ms); // Assert var f1FullPath = ss.GetFullPath("f1.txt"); var f2FullPath = ss.GetFullPath("f2.txt"); Assert.AreEqual(Path.Combine(path, "ShadowTests", "f1.txt"), f1FullPath); Assert.AreEqual(Path.Combine(path, "ShadowSystem", "f2.txt"), f2FullPath); } /// /// Returns the path relative to the filesystem root /// /// /// This file stuff in this test is kinda irrelevant with the current implementation. /// We do tests that the files are written to the correct places and the relative path is returned correct, /// but GetRelativePath is currently really just string manipulation so files are not actually hit by the code. /// Leaving the file stuff in here for now in case the method becomes more clever at some point. /// [Test] public void ShadowGetRelativePath() { // Arrange var path = IOHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); var fs = new PhysicalFileSystem(path + "/ShadowTests/", "ignore"); var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "ignore"); var ss = new ShadowFileSystem(fs, sfs); // Act File.WriteAllText(path + "/ShadowTests/f1.txt", "foo"); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) ss.AddFile("f2.txt", ms); // Assert var f1RelativePath = ss.GetRelativePath("f1.txt"); var f2RelativePath = ss.GetRelativePath("f2.txt"); Assert.AreEqual("f1.txt", f1RelativePath); Assert.AreEqual("f2.txt", f2RelativePath); Assert.IsTrue(File.Exists(Path.Combine(path, "ShadowTests", "f1.txt"))); Assert.IsFalse(File.Exists(Path.Combine(path, "ShadowTests", "f2.txt"))); Assert.IsTrue(File.Exists(Path.Combine(path, "ShadowSystem", "f2.txt"))); Assert.IsFalse(File.Exists(Path.Combine(path, "ShadowSystem", "f1.txt"))); } /// /// Ensure the url returned contains the path relative to the FS root, /// but including the rootUrl the FS was initialized with. /// /// /// This file stuff in this test is kinda irrelevant with the current implementation. /// We do tests that the files are written to the correct places and the url is returned correct, /// but GetUrl is currently really just string manipulation so files are not actually hit by the code. /// Leaving the file stuff in here for now in case the method becomes more clever at some point. /// [Test] public void ShadowGetUrl() { // Arrange var path = IOHelper.MapPath("FileSysTests"); Directory.CreateDirectory(path); Directory.CreateDirectory(path + "/ShadowTests"); Directory.CreateDirectory(path + "/ShadowSystem"); var fs = new PhysicalFileSystem(path + "/ShadowTests/", "rootUrl"); var sfs = new PhysicalFileSystem(path + "/ShadowSystem/", "rootUrl"); var ss = new ShadowFileSystem(fs, sfs); // Act File.WriteAllText(path + "/ShadowTests/f1.txt", "foo"); using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) ss.AddFile("f2.txt", ms); // Assert var f1Url = ss.GetUrl("f1.txt"); var f2Url = ss.GetUrl("f2.txt"); Assert.AreEqual("rootUrl/f1.txt", f1Url); Assert.AreEqual("rootUrl/f2.txt", f2Url); Assert.IsTrue(File.Exists(Path.Combine(path, "ShadowTests", "f1.txt"))); Assert.IsFalse(File.Exists(Path.Combine(path, "ShadowTests", "f2.txt"))); Assert.IsTrue(File.Exists(Path.Combine(path, "ShadowSystem", "f2.txt"))); Assert.IsFalse(File.Exists(Path.Combine(path, "ShadowSystem", "f1.txt"))); } } }