Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 50 additions & 5 deletions AudioCuesheetEditor.Tests/Services/IO/ImportManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using AudioCuesheetEditor.Model.AudioCuesheet.Import;
using AudioCuesheetEditor.Model.IO;
using AudioCuesheetEditor.Model.IO.Import;
using AudioCuesheetEditor.Model.UI;
using AudioCuesheetEditor.Services.IO;
using AudioCuesheetEditor.Services.UI;
using AudioCuesheetEditor.Tests.Utility;
Expand All @@ -43,8 +44,8 @@ public async Task AnalyseImportfile_WithTextfile_SetsImportCuesheet()
{
// Arrange
var fileContent = "This is just a test";
var traceChangeManager = new TraceChangeManager(TestHelper.CreateLogger<TraceChangeManager>());
var sessionStateContainer = new SessionStateContainer(traceChangeManager);
var traceChangeManagerMock = new Mock<ITraceChangeManager>();
var sessionStateContainer = new SessionStateContainer(traceChangeManagerMock.Object);
var fileInputManagerMock = new Mock<IFileInputManager>();
var textImportServiceMock = new Mock<ITextImportService>();
var importCuesheet = new ImportCuesheet()
Expand Down Expand Up @@ -74,8 +75,7 @@ public async Task AnalyseImportfile_WithTextfile_SetsImportCuesheet()
};
textImportServiceMock.Setup(x => x.AnalyseAsync(fileContent)).ReturnsAsync(importfile);
var loggerMock = new Mock<ILogger<ImportManager>>();
var importManager = new ImportManager(sessionStateContainer, traceChangeManager, fileInputManagerMock.Object, textImportServiceMock.Object, loggerMock.Object);
var testHelper = new TestHelper();
var importManager = new ImportManager(sessionStateContainer, traceChangeManagerMock.Object, fileInputManagerMock.Object, textImportServiceMock.Object, loggerMock.Object);
sessionStateContainer.Importfile = new Importfile()
{
FileContent = "This is just a test",
Expand All @@ -101,6 +101,8 @@ public async Task AnalyseImportfile_WithTextfile_SetsImportCuesheet()
Assert.AreEqual(importCuesheet.Tracks.First().Position, sessionStateContainer.ImportCuesheet.Tracks.First().Position);
Assert.AreEqual(importCuesheet.Tracks.First().PreGap, sessionStateContainer.ImportCuesheet.Tracks.First().PreGap);
Assert.AreEqual(importCuesheet.Tracks.First().PostGap, sessionStateContainer.ImportCuesheet.Tracks.First().PostGap);
traceChangeManagerMock.Verify(x => x.TraceChanges(It.IsAny<Cuesheet>()));
traceChangeManagerMock.Verify(x => x.TraceChanges(It.IsAny<Track>()));
}

[TestMethod()]
Expand All @@ -120,7 +122,6 @@ public async Task AnalyseImportfile_WithoutAnalysedCuesheet_DoesNothing()
textImportServiceMock.Setup(x => x.AnalyseAsync(fileContent)).ReturnsAsync(importfile);
var loggerMock = new Mock<ILogger<ImportManager>>();
var importManager = new ImportManager(sessionStateContainer, traceChangeManager, fileInputManagerMock.Object, textImportServiceMock.Object, loggerMock.Object);
var testHelper = new TestHelper();
sessionStateContainer.Importfile = importfile;
// Act
await importManager.AnalyseImportfile();
Expand Down Expand Up @@ -207,6 +208,50 @@ public async Task ImportFilesAsync_TextFile_ImportsCorrectly()
Assert.AreEqual(ImportFileType.Textfile, sessionStateContainer.Importfile.FileType);
}

[TestMethod]
public void ImportCuesheet_WithImportCuesheetAvailable_ImportsCuesheetData()
{
// Arrange
var traceChangeManagerMock = new Mock<ITraceChangeManager>();
var sessionStateContainer = new SessionStateContainer(traceChangeManagerMock.Object);
var analyzedCuesheet = new Cuesheet()
{
Artist = "Artist 123",
Title = "Title 456"
};
analyzedCuesheet.AddTrack(new()
{
Artist = "Track Artist 1",
Title = "Track Title 1",
End = new TimeSpan(0, 4, 23),
});
analyzedCuesheet.AddTrack(new()
{
Artist = "Track Artist 2",
Title = "Track Title 2",
End = new TimeSpan(0, 8, 54),
});
sessionStateContainer.ImportCuesheet = analyzedCuesheet;
var fileInputManagerMock = new Mock<IFileInputManager>();
var textImportServiceMock = new Mock<ITextImportService>();
var loggerMock = new Mock<ILogger<ImportManager>>();
var importManager = new ImportManager(sessionStateContainer, traceChangeManagerMock.Object, fileInputManagerMock.Object, textImportServiceMock.Object, loggerMock.Object);
// Act
importManager.ImportCuesheet();
// Assert
Assert.AreEqual(analyzedCuesheet.Artist, sessionStateContainer.Cuesheet.Artist);
Assert.AreEqual(analyzedCuesheet.Title, sessionStateContainer.Cuesheet.Title);
Assert.AreEqual(analyzedCuesheet.Tracks.First().Artist, sessionStateContainer.Cuesheet.Tracks.First().Artist);
Assert.AreEqual(analyzedCuesheet.Tracks.First().Title, sessionStateContainer.Cuesheet.Tracks.First().Title);
Assert.AreEqual(analyzedCuesheet.Tracks.First().Begin, sessionStateContainer.Cuesheet.Tracks.First().Begin);
Assert.AreEqual(analyzedCuesheet.Tracks.First().End, sessionStateContainer.Cuesheet.Tracks.First().End);
Assert.AreEqual(analyzedCuesheet.Tracks.Last().Artist, sessionStateContainer.Cuesheet.Tracks.Last().Artist);
Assert.AreEqual(analyzedCuesheet.Tracks.Last().Title, sessionStateContainer.Cuesheet.Tracks.Last().Title);
Assert.AreEqual(analyzedCuesheet.Tracks.Last().Begin, sessionStateContainer.Cuesheet.Tracks.Last().Begin);
Assert.AreEqual(analyzedCuesheet.Tracks.Last().End, sessionStateContainer.Cuesheet.Tracks.Last().End);
traceChangeManagerMock.Verify(x => x.RemoveTracedChanges(It.IsAny<IEnumerable<ITraceable>>()));
}

private static IBrowserFile CreateBrowserFileMock(string name, string content = "TestContent")
{
var fileMock = new Mock<IBrowserFile>();
Expand Down
54 changes: 54 additions & 0 deletions AudioCuesheetEditor.Tests/Services/UI/TraceChangeManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -354,5 +354,59 @@ public void BulkEditTracksLengthTest()
Assert.IsNull(track3.End);
Assert.IsNull(track4.End);
}

[TestMethod()]
public void RemoveTracedChanges_RemovesChanges_WhenChangesAvailable()
{
// Arrange
var manager = new TraceChangeManager(TestHelper.CreateLogger<TraceChangeManager>());
var cuesheet1 = new Cuesheet();
var cuesheet2 = new Cuesheet();
manager.TraceChanges(cuesheet1);
manager.TraceChanges(cuesheet2);
cuesheet1.Artist = "Test Artist Cuesheet 1";
cuesheet1.Title = "Test Title Cuesheet 1";
cuesheet2.CDTextfile = new("CD Testfile.cdt");
cuesheet2.AddSection();
var tracedObjectHistoryChangedFired = false;
manager.TracedObjectHistoryChanged += delegate
{
tracedObjectHistoryChangedFired = true;
};
// Act
manager.RemoveTracedChanges([cuesheet1]);
// Assert
Assert.IsTrue(tracedObjectHistoryChangedFired);
Assert.IsTrue(manager.CanUndo);
manager.Undo();
manager.Undo();
Assert.IsFalse(manager.CanUndo);
}

[TestMethod()]
public void RemoveTracedChanges_RemovesNoChanges_WhenNoChangesAvailable()
{
// Arrange
var manager = new TraceChangeManager(TestHelper.CreateLogger<TraceChangeManager>());
var cuesheet1 = new Cuesheet();
var cuesheet2 = new Cuesheet();
manager.TraceChanges(cuesheet1);
manager.TraceChanges(cuesheet2);
cuesheet2.CDTextfile = new("CD Testfile.cdt");
cuesheet2.AddSection();
var tracedObjectHistoryChangedFired = false;
manager.TracedObjectHistoryChanged += delegate
{
tracedObjectHistoryChangedFired = true;
};
// Act
manager.RemoveTracedChanges([cuesheet1]);
// Assert
Assert.IsTrue(tracedObjectHistoryChangedFired);
Assert.IsTrue(manager.CanUndo);
manager.Undo();
manager.Undo();
Assert.IsFalse(manager.CanUndo);
}
}
}
28 changes: 26 additions & 2 deletions AudioCuesheetEditor/Services/IO/ImportManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using AudioCuesheetEditor.Model.IO;
using AudioCuesheetEditor.Model.IO.Audio;
using AudioCuesheetEditor.Model.IO.Import;
using AudioCuesheetEditor.Model.UI;
using AudioCuesheetEditor.Services.UI;
using Microsoft.AspNetCore.Components.Forms;
using System.Diagnostics;
Expand Down Expand Up @@ -88,9 +89,10 @@ public async Task ImportFilesAsync(IEnumerable<IBrowserFile> files)
stopwatch.Stop();
_logger.LogDebug("ImportFilesAsync duration: {stopwatch.Elapsed}", stopwatch.Elapsed);
}

public async Task AnalyseImportfile()
{
ResetTracing();
var stopwatch = Stopwatch.StartNew();
var fileContent = _sessionStateContainer.Importfile?.FileContent;
if (String.IsNullOrEmpty(fileContent) == false)
Expand All @@ -116,6 +118,7 @@ public async Task AnalyseImportfile()
var importCuesheet = new Cuesheet();
CopyCuesheet(importCuesheet, _sessionStateContainer.Importfile.AnalyzedCuesheet);
_sessionStateContainer.ImportCuesheet = importCuesheet;
StartTracing();
break;
case ImportFileType.Cuesheet:
_traceChangeManager.BulkEdit = true;
Expand All @@ -127,10 +130,11 @@ public async Task AnalyseImportfile()
stopwatch.Stop();
_logger.LogDebug("ImportTextAsync duration: {stopwatch.Elapsed}", stopwatch.Elapsed);
}

public void ImportCuesheet()
{
var stopwatch = Stopwatch.StartNew();
ResetTracing();
if (_sessionStateContainer.ImportCuesheet != null)
{
_traceChangeManager.BulkEdit = true;
Expand Down Expand Up @@ -217,5 +221,25 @@ private static void CopyCuesheet(Cuesheet target, ICuesheet cuesheetToCopy)
}
target.IsImporting = false;
}

private void StartTracing()
{
if (_sessionStateContainer.ImportCuesheet != null)
{
_traceChangeManager.TraceChanges(_sessionStateContainer.ImportCuesheet);
foreach (var track in _sessionStateContainer.ImportCuesheet.Tracks)
{
_traceChangeManager.TraceChanges(track);
}
}
}

private void ResetTracing()
{
if (_sessionStateContainer.ImportCuesheet != null)
{
_traceChangeManager.RemoveTracedChanges([_sessionStateContainer.ImportCuesheet, .. _sessionStateContainer.ImportCuesheet.Tracks]);
}
}
}
}
1 change: 1 addition & 0 deletions AudioCuesheetEditor/Services/UI/ITraceChangeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ public interface ITraceChangeManager
public void Undo();
public void Redo();
public void MergeLastEditWithEdit(Func<TracedChanges, bool> targetEdit);
public void RemoveTracedChanges(IEnumerable<ITraceable> traceables);
}
}
39 changes: 26 additions & 13 deletions AudioCuesheetEditor/Services/UI/TraceChangeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ public class TraceChangeManager(ILogger<TraceChangeManager> logger) : ITraceChan
{
private readonly ILogger<TraceChangeManager> _logger = logger;

private readonly Stack<TracedChanges> undoStack = new();
private readonly Stack<TracedChanges> redoStack = new();
private readonly List<TracedChanges> undoStack = [];
private readonly List<TracedChanges> redoStack = [];

private List<TracedChange>? bulkEditTracedChanges;

Expand Down Expand Up @@ -84,8 +84,8 @@ public void TraceChanges(ITraceable traceable)

public void Reset()
{
ResetStack(redoStack);
ResetStack(undoStack);
Reset(redoStack);
Reset(undoStack);
}

public void Undo()
Expand All @@ -97,7 +97,8 @@ public void Undo()
TracedChanges? changes = null;
while (undoStack.Count > 0 && changes == null)
{
changes = undoStack.Pop();
changes = undoStack[^1];
undoStack.Remove(changes);
if (changes.HasTraceableObject == false)
{
changes = null;
Expand Down Expand Up @@ -133,7 +134,7 @@ public void Undo()
}
}
//Push the old value to redo stack
redoStack.Push(new TracedChanges(redoChanges));
redoStack.Add(new TracedChanges(redoChanges));
}
CurrentlyHandlingRedoOrUndoChanges = false;
UndoDone?.Invoke(this, EventArgs.Empty);
Expand All @@ -149,7 +150,8 @@ public void Redo()
TracedChanges? changes = null;
while (redoStack.Count > 0 && changes == null)
{
changes = redoStack.Pop();
changes = redoStack[^1];
redoStack.Remove(changes);
if (changes.HasTraceableObject == false)
{
changes = null;
Expand Down Expand Up @@ -185,7 +187,7 @@ public void Redo()
}
}
//Push the old value to redo stack
undoStack.Push(new TracedChanges(undoChanges));
undoStack.Add(new TracedChanges(undoChanges));
}
CurrentlyHandlingRedoOrUndoChanges = false;
RedoDone?.Invoke(this, EventArgs.Empty);
Expand All @@ -206,7 +208,7 @@ public bool BulkEdit
{
if (bulkEditTracedChanges != null)
{
undoStack.Push(new TracedChanges(bulkEditTracedChanges));
undoStack.Add(new TracedChanges(bulkEditTracedChanges));
TracedObjectHistoryChanged?.Invoke(this, EventArgs.Empty);
bulkEditTracedChanges = null;
}
Expand All @@ -219,17 +221,28 @@ public void MergeLastEditWithEdit(Func<TracedChanges, bool> targetEdit)
var edit = undoStack.FirstOrDefault(targetEdit);
if ((edit != null) && (undoStack.Count > 0))
{
var lastEdits = undoStack.Pop();
var lastEdits = undoStack[^1];
undoStack.Remove(lastEdits);
edit.Changes.AddRange(lastEdits.Changes);
UndoDone?.Invoke(this, EventArgs.Empty);
}
}

private void ResetStack(Stack<TracedChanges> stack)
public void RemoveTracedChanges(IEnumerable<ITraceable> traceables)
{
undoStack.RemoveAll(x => x.HasTraceableObject == false);
undoStack.RemoveAll(x => x.Changes.Any(y => traceables.Contains(y.TraceableObject)));
redoStack.RemoveAll(x => x.HasTraceableObject == false);
redoStack.RemoveAll(x => x.Changes.Any(y => traceables.Contains(y.TraceableObject)));
TracedObjectHistoryChanged?.Invoke(this, EventArgs.Empty);
}

private void Reset(List<TracedChanges> stack)
{
while (stack.Count > 0)
{
var tracedChange = stack.Pop();
var tracedChange = stack[^1];
stack.Remove(tracedChange);
foreach (var change in tracedChange.Changes)
{
if (change.TraceableObject != null)
Expand All @@ -254,7 +267,7 @@ private void Traceable_TraceablePropertyChanged(object? sender, TraceablePropert
{
//Single change
var changes = new TracedChanges([new((ITraceable)sender, e.TraceableChange)]);
undoStack.Push(changes);
undoStack.Add(changes);
redoStack.Clear();
TracedObjectHistoryChanged?.Invoke(this, EventArgs.Empty);
}
Expand Down