public void AutoSaveCleanedUpIfNoModifications() { string loadedText = "A"; string autoSaveText = "B"; string filePath = fileFixture.GetPath(TargetFile.PrimaryTextFile); fileFixture.PrepareTargetFile(TargetFile.PrimaryTextFile, loadedText); PrepareAutoSave(autoSaveText); using (var wcFile = WorkingCopyTextFile.Open(filePath, AutoSaveFiles())) { // Assert transitions between auto-save states. Assert.NotNull(wcFile.AutoSaveFile); Assert.Equal(autoSaveText, wcFile.LocalCopyText); Assert.True(wcFile.ContainsChanges); wcFile.UpdateLocalCopyText(loadedText, containsChanges: false); Assert.NotNull(wcFile.AutoSaveFile); Assert.Equal(loadedText, wcFile.LocalCopyText); Assert.False(wcFile.ContainsChanges); wcFile.Dispose(); // Assert that the auto-save files have been deleted. AssertNoAutoSaveFiles(wcFile); } }
public void ReplaceWithIllegalPath() { string text1 = "A"; string text2 = "B"; fileFixture.PrepareTargetFile(TargetFile.PrimaryTextFile, text1); using (var ewh = new AutoResetEvent(false)) using (var wcFile = WorkingCopyTextFile.Open(fileFixture.GetPath(TargetFile.PrimaryTextFile), null)) { var liveTextFile = wcFile.OpenTextFile; // Lock the second file before attempting to overwrite it. fileFixture.PrepareTargetFile(TargetFile.SecondaryTextFile, FileState.LockedByAnotherProcess); // This should throw, and leave the old OpenTextFile intact. Assert.Throws <IOException>(() => wcFile.Replace(fileFixture.GetPath(TargetFile.SecondaryTextFile))); Assert.Same(liveTextFile, wcFile.OpenTextFile); Assert.False(liveTextFile.IsDisposed); Assert.Equal(text1, wcFile.LocalCopyText); Assert.False(wcFile.ContainsChanges); // Verify that auto-updates still work. wcFile.LoadedTextChanged += (_, __) => ewh.Set(); fileFixture.PrepareTargetFile(TargetFile.PrimaryTextFile, text2); ewh.WaitOne(); Assert.Equal(text2, wcFile.LoadedText); Assert.Equal(text2, wcFile.LocalCopyText); Assert.False(wcFile.ContainsChanges); } }
public void ModificationsAreAutoSaved() { string expectedLoadedText = "A"; string expectedAutoSaveText = "B"; string filePath = fileFixture.GetPath(TargetFile.PrimaryTextFile); fileFixture.PrepareTargetFile(TargetFile.PrimaryTextFile, expectedLoadedText); fileFixture.PrepareTargetFile(TargetFile.AutoSaveFile1, FileState.DoesNotExist); fileFixture.PrepareTargetFile(TargetFile.AutoSaveFile2, FileState.DoesNotExist); using (var wcFile = WorkingCopyTextFile.Open(filePath, null)) { wcFile.QueryAutoSaveFile += (_, e) => e.AutoSaveFileStreamPair = AutoSaveFiles(); wcFile.UpdateLocalCopyText(expectedAutoSaveText, containsChanges: true); Assert.True(wcFile.ContainsChanges); } // Reloading the WorkingCopyTextFile should restore the auto saved text, even when the original file is deleted. fileFixture.PrepareTargetFile(TargetFile.PrimaryTextFile, FileState.DoesNotExist); using (var wcFile = WorkingCopyTextFile.Open(filePath, AutoSaveFiles())) { Assert.Equal(expectedAutoSaveText, wcFile.LocalCopyText); Assert.True(wcFile.ContainsChanges); Assert.NotNull(wcFile.AutoSaveFile); // Assert that the auto-save file is still there, but disposed. wcFile.Dispose(); Assert.NotNull(wcFile.AutoSaveFile); Assert.True(wcFile.AutoSaveFile.IsDisposed); Assert.True(wcFile.ContainsChanges); } }
public void FailedSaveThenAutoUpdate() { string oldLoadedText = "A"; string newLoadedText = "B"; string filePath = fileFixture.GetPath(TargetFile.PrimaryTextFile); fileFixture.PrepareTargetFile(TargetFile.PrimaryTextFile, oldLoadedText); PrepareAutoSave(string.Empty); using (var ewh = new ManualResetEvent(false)) using (var wcFile = WorkingCopyTextFile.Open(filePath, AutoSaveFiles())) { fileFixture.PrepareTargetFile(TargetFile.PrimaryTextFile, FileState.LockedByAnotherProcess); Assert.Throws <IOException>(() => wcFile.Save()); wcFile.LoadedTextChanged += (_, __) => ewh.Set(); fileFixture.PrepareTargetFile(TargetFile.PrimaryTextFile, newLoadedText); ewh.WaitOne(); Assert.Equal(newLoadedText, wcFile.LoadedText); Assert.Equal(newLoadedText, wcFile.LocalCopyText); // Auto-updating should still work after being locked by another process. Assert.False(wcFile.ContainsChanges); } }
public void ExistingFileOwnership() { string text = "A"; string filePath = fileFixture.GetPath(TargetFile.PrimaryTextFile); fileFixture.PrepareTargetFile(TargetFile.PrimaryTextFile, text); // wcFile does not own textFile: textFile must still be open after wcFile is disposed. using (var textFile = new LiveTextFile(filePath)) using (var wcFile = WorkingCopyTextFile.FromLiveTextFile(textFile, null)) { Assert.False(wcFile.IsTextFileOwner); wcFile.Dispose(); Assert.NotNull(wcFile.OpenTextFile); Assert.False(textFile.IsDisposed); textFile.Dispose(); Assert.True(textFile.IsDisposed); } // wcFile owns textFile: textFile must be disposed together with wcFile. using (var wcFile = WorkingCopyTextFile.Open(filePath, null)) { var textFile = wcFile.OpenTextFile; Assert.NotNull(textFile); Assert.False(textFile.IsDisposed); wcFile.Dispose(); Assert.Same(textFile, wcFile.OpenTextFile); Assert.True(textFile.IsDisposed); } }
public void TextAutoUpdated() { string oldLoadedText = "A"; string newLoadedText = "B"; string filePath = fileFixture.GetPath(TargetFile.PrimaryTextFile); fileFixture.PrepareTargetFile(TargetFile.PrimaryTextFile, oldLoadedText); using (var ewh = new ManualResetEvent(false)) using (var wcFile = WorkingCopyTextFile.Open(filePath, null)) { // Use an EventWaitHandle to wait for the event to occur. // This works because the event will get raised on a background thread. wcFile.LoadedTextChanged += (_, __) => ewh.Set(); // Simulate that the opened text file was updated remotely. fileFixture.PrepareTargetFile(TargetFile.PrimaryTextFile, newLoadedText); ewh.WaitOne(); // Assert that the loaded text is updated automatically. Assert.Equal(newLoadedText, wcFile.LoadedText); Assert.Equal(newLoadedText, wcFile.LocalCopyText); Assert.False(wcFile.ContainsChanges); } }
public void UpdatesBlockedAfterDispose() { using (var wcFile = WorkingCopyTextFile.Open(null, null)) { Assert.Throws <InvalidOperationException>(() => wcFile.Save()); wcFile.Dispose(); Assert.Throws <ObjectDisposedException>(() => wcFile.Save()); Assert.Throws <ObjectDisposedException>(() => wcFile.UpdateLocalCopyText(string.Empty, false)); } }
public void AllowMultipleDispose() { using (var wcFile = WorkingCopyTextFile.Open(null, null)) { wcFile.Dispose(); Assert.True(wcFile.IsDisposed); wcFile.Dispose(); Assert.True(wcFile.IsDisposed); } }
public void NewFileInitialState() { using (var wcFile = WorkingCopyTextFile.Open(null, null)) { Assert.True(wcFile.IsTextFileOwner); Assert.Null(wcFile.OpenTextFile); Assert.Null(wcFile.OpenTextFilePath); AssertLiveTextFileSuccessfulLoad(string.Empty, wcFile); } }
public void ReplaceFailsWhenDisposed() { PrepareForReplaceTest("A", "B"); var wcFile = WorkingCopyTextFile.Open(fileFixture.GetPath(TargetFile.PrimaryTextFile), null); var liveTextFile = wcFile.OpenTextFile; wcFile.Dispose(); Assert.Throws <ObjectDisposedException>(() => wcFile.Replace(fileFixture.GetPath(TargetFile.SecondaryTextFile))); Assert.Same(liveTextFile, wcFile.OpenTextFile); }
public void AutoSavedNewFileInitialState(string autoSaveFileText) { PrepareAutoSave(autoSaveFileText); using (var wcFile = WorkingCopyTextFile.Open(null, AutoSaveFiles())) { Assert.True(wcFile.IsTextFileOwner); Assert.Null(wcFile.OpenTextFile); Assert.Null(wcFile.OpenTextFilePath); AssertLiveTextFileSuccessfulLoadWithAutoSave(string.Empty, autoSaveFileText, wcFile); } }
public void ReplaceWithDifferentPath() { string text1 = "A"; string text2 = "B"; string text3 = "C"; PrepareForReplaceTest(text1, text2); string primaryFilePath = fileFixture.GetPath(TargetFile.PrimaryTextFile); string secondaryFilePath = fileFixture.GetPath(TargetFile.SecondaryTextFile); using (var ewh = new AutoResetEvent(false)) using (var wcFile = WorkingCopyTextFile.Open(primaryFilePath, null)) { // Get a reference to wcFile.OpenTextFile before it is replaced. var liveTextFile = wcFile.OpenTextFile; // Register event before doing the actual replace. string previousOpenTextFilePath = null; wcFile.OpenTextFilePathChanged += (_, e) => { // This variable is later checked to assert that this code is actually called. previousOpenTextFilePath = e.PreviousOpenTextFilePath; // Assert that the OpenTextFile was replaced, and the old one disposed. Assert.NotSame(liveTextFile, wcFile.OpenTextFile); Assert.True(liveTextFile.IsDisposed); // Assert that the second file was overwritten. Assert.Equal(secondaryFilePath, wcFile.OpenTextFilePath); Assert.Equal(text1, wcFile.LoadedText); Assert.Equal(text1, wcFile.LocalCopyText); Assert.False(wcFile.ContainsChanges); }; wcFile.Replace(secondaryFilePath); // Assert that the OpenTextFilePathChanged event was indeed raised. Assert.Equal(primaryFilePath, previousOpenTextFilePath); // Verify that auto-updates work on the second file, not the first. wcFile.LoadedTextChanged += (_, __) => ewh.Set(); fileFixture.PrepareTargetFile(TargetFile.SecondaryTextFile, text2); fileFixture.PrepareTargetFile(TargetFile.PrimaryTextFile, text3); ewh.WaitOne(); Assert.Equal(text2, wcFile.LoadedText); Assert.Equal(text2, wcFile.LocalCopyText); Assert.False(wcFile.ContainsChanges); } }
public void SaveRemovesAutoSave() { string loadedText = "A"; string autoSavedText = "B"; string filePath = fileFixture.GetPath(TargetFile.PrimaryTextFile); fileFixture.PrepareTargetFile(TargetFile.PrimaryTextFile, loadedText); PrepareAutoSave(autoSavedText); using (var wcFile = WorkingCopyTextFile.Open(filePath, AutoSaveFiles())) { wcFile.Save(); wcFile.Dispose(); AssertNoAutoSaveFiles(wcFile); } }
private void TestInaccessibleFileWithAutoSaveInitialState(FileState fileState, Type exceptionType, string autoSavedText) { string filePath = fileFixture.GetPath(TargetFile.PrimaryTextFile); fileFixture.PrepareTargetFile(TargetFile.PrimaryTextFile, fileState); using (var wcFile = WorkingCopyTextFile.Open(filePath, AutoSaveFiles())) { Assert.True(wcFile.IsTextFileOwner); Assert.Equal(filePath, wcFile.OpenTextFilePath); Assert.NotNull(wcFile.AutoSaveFile); Assert.Equal(string.Empty, wcFile.LoadedText); Assert.IsType(exceptionType, wcFile.LoadException); Assert.Equal(autoSavedText, wcFile.LocalCopyText); Assert.Equal(!string.IsNullOrEmpty(autoSavedText), wcFile.ContainsChanges); } }
private PgnEditor NewPgnEditor(string normalizedPgnFileName, bool isReadOnly) { var pgnFile = WorkingCopyTextFile.Open(normalizedPgnFileName, null); var pgnEditor = new PgnEditor( isReadOnly ? SyntaxEditorCodeAccessOption.ReadOnly : SyntaxEditorCodeAccessOption.Default, PgnSyntaxDescriptor.Instance, pgnFile, SettingKeys.PgnZoom); pgnEditor.BindAction(OpenNewPlayingBoard, perform => TryOpenNewPlayingBoard(pgnEditor, perform)); pgnEditor.BindAction(OpenGame, perform => TryOpenGame(pgnEditor, perform)); pgnEditor.BindActions(pgnEditor.StandardSyntaxEditorUIActionBindings); UIMenu.AddTo(pgnEditor); pgnEditor.DoubleClick += (_, __) => TryOpenGame(pgnEditor, true); PgnStyleSelector.InitializeStyles(pgnEditor); // Don't index read-only pgn editors. if (!isReadOnly) { Program.MainForm.AddPgnEditor(normalizedPgnFileName, pgnEditor); // Re-index when pgnFile.OpenTextFilePath changes. pgnFile.OpenTextFilePathChanged += (_, e) => { Program.MainForm.RemovePgnEditor(e.PreviousOpenTextFilePath, pgnEditor); Program.MainForm.AddPgnEditor(pgnFile.OpenTextFilePath, pgnEditor); }; // Remove from index when pgnEditor is closed. pgnEditor.Disposed += (_, __) => { Program.MainForm.RemovePgnEditor(pgnFile.OpenTextFilePath, pgnEditor); }; } // Open as new tab page. DockedControl.TabPages.Add(new MdiTabPage <PgnEditor>(pgnEditor)); return(pgnEditor); }
public void DiscardAutosavedModificationsIfFileUpdatedWithSameContents() { // This asserts that there are no changes after the following transitions: // 1) Open existing file with text "A". // 2) Make local modification, change text to "B", this is auto-saved. // 3) Dispose the WorkingCopyTextFile. // 4) Update existing file with contents "B". // 5) Reload WorkingCopyTextFile from the auto-save files. // -> Should detect that the contents of the file match the auto-saved modifications. string expectedLoadedText = "A"; string expectedAutoSaveText = "B"; string filePath = fileFixture.GetPath(TargetFile.PrimaryTextFile); fileFixture.PrepareTargetFile(TargetFile.PrimaryTextFile, expectedLoadedText); PrepareAutoSave(string.Empty); using (var wcFile = WorkingCopyTextFile.Open(filePath, AutoSaveFiles())) { wcFile.UpdateLocalCopyText(expectedAutoSaveText, containsChanges: true); Assert.True(wcFile.ContainsChanges); } // Assert that the auto-save actually happened. using (var wcFile = WorkingCopyTextFile.Open(filePath, AutoSaveFiles())) { Assert.Equal(expectedAutoSaveText, wcFile.LocalCopyText); Assert.True(wcFile.ContainsChanges); } fileFixture.PrepareTargetFile(TargetFile.PrimaryTextFile, expectedAutoSaveText); using (var wcFile = WorkingCopyTextFile.Open(filePath, AutoSaveFiles())) { Assert.Equal(expectedAutoSaveText, wcFile.LocalCopyText); Assert.False(wcFile.ContainsChanges); Assert.NotNull(wcFile.AutoSaveFile); wcFile.Dispose(); AssertNoAutoSaveFiles(wcFile); } }
public void TextNotAutoUpdatedWithLocalChanges(string oldLoadedText, string newLoadedText, string autoSavedText) { string filePath = fileFixture.GetPath(TargetFile.PrimaryTextFile); fileFixture.PrepareTargetFile(TargetFile.PrimaryTextFile, oldLoadedText); PrepareAutoSave(autoSavedText); using (var ewh = new ManualResetEvent(false)) using (var wcFile = WorkingCopyTextFile.Open(filePath, AutoSaveFiles())) { wcFile.LoadedTextChanged += (_, __) => ewh.Set(); fileFixture.PrepareTargetFile(TargetFile.PrimaryTextFile, newLoadedText); ewh.WaitOne(); // Assert that LoadedText is updated but LocalCopyText is not. Assert.Equal(newLoadedText, wcFile.LoadedText); Assert.Equal(autoSavedText, wcFile.LocalCopyText); Assert.True(wcFile.ContainsChanges); } }
public void InvalidAutoSaveFiles(byte[] invalidFile) { // Small valid non-empty file, should be preferred over invalid or empty files. // UTF8 BOM "", followed by length 1, a newline character, and an 'A'. byte[] validFile = new byte[] { 0xef, 0xbb, 0xbf, 0x31, 0x0a, 0x41 }; string expectedAutoSaveText = "A"; // Both file permutations should yield the same result. fileFixture.PrepareTargetFile(TargetFile.AutoSaveFile1, invalidFile); fileFixture.PrepareTargetFile(TargetFile.AutoSaveFile2, validFile); using (var wcFile = WorkingCopyTextFile.Open(null, AutoSaveFiles())) { AssertLiveTextFileSuccessfulLoadWithAutoSave(string.Empty, expectedAutoSaveText, wcFile); } fileFixture.PrepareTargetFile(TargetFile.AutoSaveFile1, validFile); fileFixture.PrepareTargetFile(TargetFile.AutoSaveFile2, invalidFile); using (var wcFile = WorkingCopyTextFile.Open(null, AutoSaveFiles())) { AssertLiveTextFileSuccessfulLoadWithAutoSave(string.Empty, expectedAutoSaveText, wcFile); } }
public void ReplaceWithSamePath(string filePath) { string text1 = "A"; string text2 = "B"; string text3 = "C"; fileFixture.PrepareTargetFile(TargetFile.PrimaryTextFile, text1); using (var ewh = new AutoResetEvent(false)) using (var wcFile = WorkingCopyTextFile.Open(fileFixture.GetPath(TargetFile.PrimaryTextFile), null)) { var liveTextFile = wcFile.OpenTextFile; // Evaluate LoadedText so IsDirty becomes false. Assert.Equal(text1, wcFile.LoadedText); // This should have no effect other than that the local changes are saved. wcFile.UpdateLocalCopyText(text2, containsChanges: true); bool eventRaised = false; wcFile.OpenTextFilePathChanged += (_, __) => eventRaised = true; wcFile.Replace(filePath); // Assert that the OpenTextFile is unchanged. Assert.Same(liveTextFile, wcFile.OpenTextFile); Assert.False(liveTextFile.IsDisposed); Assert.Equal(text2, wcFile.LocalCopyText); Assert.False(wcFile.ContainsChanges); Assert.False(eventRaised); // Verify that auto-updates still work. wcFile.LoadedTextChanged += (_, __) => ewh.Set(); fileFixture.PrepareTargetFile(TargetFile.PrimaryTextFile, text3); ewh.WaitOne(); Assert.Equal(text3, wcFile.LoadedText); Assert.Equal(text3, wcFile.LocalCopyText); Assert.False(wcFile.ContainsChanges); } }
// Skip LockedByAnotherProcess, because then the LoadedTextChanged event isn't raised. public void FailedAutoUpdate(FileState fileState) { string loadedText = "A"; string filePath = fileFixture.GetPath(TargetFile.PrimaryTextFile); fileFixture.PrepareTargetFile(TargetFile.PrimaryTextFile, loadedText); PrepareAutoSave(string.Empty); using (var ewh = new ManualResetEvent(false)) using (var wcFile = WorkingCopyTextFile.Open(filePath, AutoSaveFiles())) { wcFile.LoadedTextChanged += (_, __) => ewh.Set(); fileFixture.PrepareTargetFile(TargetFile.PrimaryTextFile, fileState); ewh.WaitOne(); // LocalCopyText should still be intact even though LoadedText is cleared. wcFile.Dispose(); Assert.Equal(string.Empty, wcFile.LoadedText); Assert.Equal(loadedText, wcFile.LocalCopyText); Assert.True(wcFile.ContainsChanges); Assert.NotNull(wcFile.AutoSaveFile); } }