Skip to content

Commit ceb40e7

Browse files
committed
Add SaveToFileAsync(fs) convenience overload to WavFile and AiffFile
TDD: Added tests first, then implemented the missing overload that saves back to SourcePath. This aligns WavFile and AiffFile with FlacFile and other format types that have the same pattern. The overload returns failure with 'source path' message when the file was parsed from bytes rather than read from disk.
1 parent f65a35d commit ceb40e7

File tree

4 files changed

+108
-0
lines changed

4 files changed

+108
-0
lines changed

src/TagLibSharp2/Aiff/AiffFile.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,27 @@ public Task<FileWriteResult> SaveToFileAsync (
388388
var data = Render ();
389389
return AtomicFileWriter.WriteAsync (path, data.Memory, fileSystem, cancellationToken);
390390
}
391+
392+
/// <summary>
393+
/// Saves the AIFF file back to its source path asynchronously.
394+
/// </summary>
395+
/// <remarks>
396+
/// This convenience method saves the file back to the path it was read from.
397+
/// Requires that the file was read using <see cref="ReadFromFile"/> or
398+
/// <see cref="ReadFromFileAsync"/>.
399+
/// </remarks>
400+
/// <param name="fileSystem">Optional file system abstraction.</param>
401+
/// <param name="cancellationToken">Cancellation token.</param>
402+
/// <returns>The write result.</returns>
403+
public Task<FileWriteResult> SaveToFileAsync (
404+
IFileSystem? fileSystem = null,
405+
CancellationToken cancellationToken = default)
406+
{
407+
if (string.IsNullOrEmpty (SourcePath))
408+
return Task.FromResult (FileWriteResult.Failure ("No source path available. File was not read from disk."));
409+
410+
return SaveToFileAsync (SourcePath!, fileSystem, cancellationToken);
411+
}
391412
}
392413

393414
/// <summary>

src/TagLibSharp2/Riff/WavFile.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,27 @@ public Task<FileWriteResult> SaveToFileAsync (
386386
var data = Render ();
387387
return AtomicFileWriter.WriteAsync (path, data.Memory, fileSystem, cancellationToken);
388388
}
389+
390+
/// <summary>
391+
/// Saves the WAV file back to its source path asynchronously.
392+
/// </summary>
393+
/// <remarks>
394+
/// This convenience method saves the file back to the path it was read from.
395+
/// Requires that the file was read using <see cref="ReadFromFile"/> or
396+
/// <see cref="ReadFromFileAsync"/>.
397+
/// </remarks>
398+
/// <param name="fileSystem">Optional file system abstraction.</param>
399+
/// <param name="cancellationToken">Cancellation token.</param>
400+
/// <returns>The write result.</returns>
401+
public Task<FileWriteResult> SaveToFileAsync (
402+
IFileSystem? fileSystem = null,
403+
CancellationToken cancellationToken = default)
404+
{
405+
if (string.IsNullOrEmpty (SourcePath))
406+
return Task.FromResult (FileWriteResult.Failure ("No source path available. File was not read from disk."));
407+
408+
return SaveToFileAsync (SourcePath!, fileSystem, cancellationToken);
409+
}
389410
}
390411

391412
/// <summary>

tests/TagLibSharp2.Tests/Aiff/AiffFileAsyncTests.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,37 @@ public async Task SaveToFileAsync_PreservesStructure ()
9393
Assert.AreEqual ("Test", verifyResult.File!.Tag?.Title);
9494
Assert.AreEqual ("Artist", verifyResult.File.Tag?.Artist);
9595
}
96+
97+
[TestMethod]
98+
public async Task SaveToFileAsync_BackToSource_Succeeds ()
99+
{
100+
var mockFs = new MockFileSystem ();
101+
var originalData = TestBuilders.Aiff.CreateMinimal ();
102+
mockFs.AddFile ("/test.aiff", originalData);
103+
104+
var readResult = await AiffFile.ReadFromFileAsync ("/test.aiff", mockFs);
105+
var file = readResult.File!;
106+
file.Tag = new Id3v2Tag { Title = "Overwritten Title" };
107+
108+
var saveResult = await file.SaveToFileAsync (mockFs);
109+
110+
Assert.IsTrue (saveResult.IsSuccess);
111+
112+
var verifyResult = await AiffFile.ReadFromFileAsync ("/test.aiff", mockFs);
113+
Assert.AreEqual ("Overwritten Title", verifyResult.File!.Tag?.Title);
114+
}
115+
116+
[TestMethod]
117+
public async Task SaveToFileAsync_NoSourcePath_ReturnsFailure ()
118+
{
119+
var data = TestBuilders.Aiff.CreateMinimal ();
120+
var result = AiffFile.Read (data);
121+
var file = result.File!;
122+
123+
var mockFs = new MockFileSystem ();
124+
var saveResult = await file.SaveToFileAsync (mockFs);
125+
126+
Assert.IsFalse (saveResult.IsSuccess);
127+
Assert.IsTrue (saveResult.Error!.Contains ("source path", StringComparison.OrdinalIgnoreCase));
128+
}
96129
}

tests/TagLibSharp2.Tests/Riff/WavFileAsyncTests.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,37 @@ public async Task SaveToFileAsync_PreservesStructure ()
9393
Assert.AreEqual ("Test", verifyResult.File!.Id3v2Tag?.Title);
9494
Assert.AreEqual ("Artist", verifyResult.File.Id3v2Tag?.Artist);
9595
}
96+
97+
[TestMethod]
98+
public async Task SaveToFileAsync_BackToSource_Succeeds ()
99+
{
100+
var mockFs = new MockFileSystem ();
101+
var originalData = TestBuilders.Wav.CreateMinimal ();
102+
mockFs.AddFile ("/test.wav", originalData);
103+
104+
var readResult = await WavFile.ReadFromFileAsync ("/test.wav", mockFs);
105+
var file = readResult.File!;
106+
file.Id3v2Tag = new Id3v2Tag { Title = "Overwritten Title" };
107+
108+
var saveResult = await file.SaveToFileAsync (mockFs);
109+
110+
Assert.IsTrue (saveResult.IsSuccess);
111+
112+
var verifyResult = await WavFile.ReadFromFileAsync ("/test.wav", mockFs);
113+
Assert.AreEqual ("Overwritten Title", verifyResult.File!.Id3v2Tag?.Title);
114+
}
115+
116+
[TestMethod]
117+
public async Task SaveToFileAsync_NoSourcePath_ReturnsFailure ()
118+
{
119+
var data = TestBuilders.Wav.CreateMinimal ();
120+
var result = WavFile.Read (data);
121+
var file = result.File!;
122+
123+
var mockFs = new MockFileSystem ();
124+
var saveResult = await file.SaveToFileAsync (mockFs);
125+
126+
Assert.IsFalse (saveResult.IsSuccess);
127+
Assert.IsTrue (saveResult.Error!.Contains ("source path", StringComparison.OrdinalIgnoreCase));
128+
}
96129
}

0 commit comments

Comments
 (0)