Files
duplicati/Duplicati/UnitTest/DiskImage/Fat32/Fat32ZeroStreamTests.cs
T
Kenneth Skovhede 179d1ceb47 Make controller Async
This PR has a large blast radius because it takes the final step and bumps up the Controller to be fully async.

We have historically done a piece-by-piece update, so all operations were already async but the controller interface was kept synchronous.

With this update, the controller is now fully async and all tests are updated.

Most places where the new C# compiler warns about function names not ending in `Async` were also adressed, giving a massive refactor change.

Functionally, no changes are done.
2026-05-13 15:04:13 +02:00

264 lines
8.8 KiB
C#

// Copyright (c) 2026 Duplicati Inc. All rights reserved.
using System;
using System.IO;
using System.Threading.Tasks;
using Duplicati.Proprietary.DiskImage.Filesystem.Fat32;
using NUnit.Framework;
using NUnit.Framework.Legacy;
using Assert = NUnit.Framework.Legacy.ClassicAssert;
#nullable enable
namespace Duplicati.UnitTest.DiskImage.Fat32;
/// <summary>
/// Unit tests for the <see cref="Fat32Filesystem.Fat32ZeroStream"/> class.
/// </summary>
[TestFixture]
[Category("DiskImageUnit")]
public class Fat32ZeroStreamTests
{
[Test]
public void Test_Fat32ZeroStream_Read_ReturnsZeros()
{
const int blockSize = 1024 * 1024; // 1MB
using var stream = new Fat32Filesystem.Fat32ZeroStream(blockSize);
var buffer = new byte[1024];
int bytesRead = stream.Read(buffer, 0, buffer.Length);
Assert.AreEqual(1024, bytesRead, "Should read requested number of bytes");
// Verify all bytes are zero
for (int i = 0; i < buffer.Length; i++)
{
Assert.AreEqual(0, buffer[i], $"Byte at position {i} should be zero");
}
}
[Test]
public async Task Test_Fat32ZeroStream_ReadAsync_ReturnsZeros_Async()
{
const int blockSize = 1024 * 1024; // 1MB
using var stream = new Fat32Filesystem.Fat32ZeroStream(blockSize);
var buffer = new byte[1024];
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
Assert.AreEqual(1024, bytesRead, "Should read requested number of bytes");
// Verify all bytes are zero
for (int i = 0; i < buffer.Length; i++)
{
Assert.AreEqual(0, buffer[i], $"Byte at position {i} should be zero");
}
}
[Test]
public void Test_Fat32ZeroStream_Length_MatchesBlockSize()
{
const int blockSize = 1024 * 1024; // 1MB
using var stream = new Fat32Filesystem.Fat32ZeroStream(blockSize);
Assert.AreEqual(blockSize, stream.Length, "Stream length should match block size");
}
[Test]
public void Test_Fat32ZeroStream_Seek_Works()
{
const int blockSize = 1024 * 1024; // 1MB
using var stream = new Fat32Filesystem.Fat32ZeroStream(blockSize);
// Seek to beginning
var position = stream.Seek(0, SeekOrigin.Begin);
Assert.AreEqual(0, position, "Should be at position 0");
// Seek to middle
position = stream.Seek(blockSize / 2, SeekOrigin.Begin);
Assert.AreEqual(blockSize / 2, position, "Should be at middle position");
// Seek relative to current
position = stream.Seek(1024, SeekOrigin.Current);
Assert.AreEqual(blockSize / 2 + 1024, position, "Should be at relative position");
// Seek from end
position = stream.Seek(-1024, SeekOrigin.End);
Assert.AreEqual(blockSize - 1024, position, "Should be at position from end");
}
[Test]
public void Test_Fat32ZeroStream_Write_ThrowsNotSupported()
{
const int blockSize = 1024 * 1024; // 1MB
using var stream = new Fat32Filesystem.Fat32ZeroStream(blockSize);
var buffer = new byte[1024];
Assert.Throws<NotSupportedException>(() => stream.Write(buffer, 0, buffer.Length));
}
[Test]
public void Test_Fat32ZeroStream_MultipleInstances_ShareBuffer()
{
const int blockSize = 1024 * 1024; // 1MB
// Create two streams with the same block size
using var stream1 = new Fat32Filesystem.Fat32ZeroStream(blockSize);
using var stream2 = new Fat32Filesystem.Fat32ZeroStream(blockSize);
// Both should read zeros
var buffer1 = new byte[1024];
var buffer2 = new byte[1024];
stream1.ReadExactly(buffer1);
stream2.ReadExactly(buffer2);
// Verify both have zeros
for (int i = 0; i < buffer1.Length; i++)
{
Assert.AreEqual(0, buffer1[i], $"Buffer1 byte at position {i} should be zero");
Assert.AreEqual(0, buffer2[i], $"Buffer2 byte at position {i} should be zero");
}
}
[Test]
public void Test_Fat32ZeroStream_ReadPartial_ReturnsCorrectCount()
{
const int blockSize = 1024 * 1024; // 1MB
using var stream = new Fat32Filesystem.Fat32ZeroStream(blockSize);
// Seek to near the end
stream.Seek(blockSize - 100, SeekOrigin.Begin);
var buffer = new byte[1024];
int bytesRead = stream.Read(buffer, 0, buffer.Length);
Assert.AreEqual(100, bytesRead, "Should only read remaining bytes");
}
[Test]
public void Test_Fat32ZeroStream_ReadPastEnd_ReturnsZero()
{
const int blockSize = 1024 * 1024; // 1MB
using var stream = new Fat32Filesystem.Fat32ZeroStream(blockSize);
// Seek to end
stream.Seek(0, SeekOrigin.End);
var buffer = new byte[1024];
int bytesRead = stream.Read(buffer, 0, buffer.Length);
Assert.AreEqual(0, bytesRead, "Should return 0 when reading past end");
}
[Test]
public void Test_Fat32ZeroStream_CanRead_CanWrite_CanSeek()
{
const int blockSize = 1024 * 1024; // 1MB
using var stream = new Fat32Filesystem.Fat32ZeroStream(blockSize);
Assert.IsTrue(stream.CanRead, "CanRead should be true");
Assert.IsFalse(stream.CanWrite, "CanWrite should be false");
Assert.IsTrue(stream.CanSeek, "CanSeek should be true");
}
[Test]
public void Test_Fat32ZeroStream_InvalidBlockSize_Throws()
{
Assert.Throws<ArgumentException>(() => new Fat32Filesystem.Fat32ZeroStream(0));
Assert.Throws<ArgumentException>(() => new Fat32Filesystem.Fat32ZeroStream(-1));
}
[Test]
public void Test_Fat32ZeroStream_SetLength_ThrowsNotSupported()
{
const int blockSize = 1024 * 1024; // 1MB
using var stream = new Fat32Filesystem.Fat32ZeroStream(blockSize);
Assert.Throws<NotSupportedException>(() => stream.SetLength(1024));
}
[Test]
public void Test_Fat32ZeroStream_Flush_DoesNotThrow()
{
const int blockSize = 1024 * 1024; // 1MB
using var stream = new Fat32Filesystem.Fat32ZeroStream(blockSize);
Assert.DoesNotThrow(() => stream.Flush());
}
[Test]
public void Test_Fat32ZeroStream_Position_Property()
{
const int blockSize = 1024 * 1024; // 1MB
using var stream = new Fat32Filesystem.Fat32ZeroStream(blockSize);
Assert.AreEqual(0, stream.Position, "Initial position should be 0");
stream.Position = 1024;
Assert.AreEqual(1024, stream.Position, "Position should be settable");
}
[Test]
public void Test_Fat32ZeroStream_Position_InvalidValue_Throws()
{
const int blockSize = 1024 * 1024; // 1MB
using var stream = new Fat32Filesystem.Fat32ZeroStream(blockSize);
Assert.Throws<ArgumentOutOfRangeException>(() => stream.Position = -1);
Assert.Throws<ArgumentOutOfRangeException>(() => stream.Position = blockSize + 1);
}
[Test]
public void Test_Fat32ZeroStream_Seek_InvalidOrigin_Throws()
{
const int blockSize = 1024 * 1024; // 1MB
using var stream = new Fat32Filesystem.Fat32ZeroStream(blockSize);
Assert.Throws<ArgumentException>(() => stream.Seek(0, (SeekOrigin)999));
}
[Test]
public void Test_Fat32ZeroStream_Seek_OutOfRange_Throws()
{
const int blockSize = 1024 * 1024; // 1MB
using var stream = new Fat32Filesystem.Fat32ZeroStream(blockSize);
Assert.Throws<ArgumentOutOfRangeException>(() => stream.Seek(-1, SeekOrigin.Begin));
Assert.Throws<ArgumentOutOfRangeException>(() => stream.Seek(blockSize + 1, SeekOrigin.Begin));
}
[Test]
public void Test_Fat32ZeroStream_Read_NullBuffer_Throws()
{
const int blockSize = 1024 * 1024; // 1MB
using var stream = new Fat32Filesystem.Fat32ZeroStream(blockSize);
#pragma warning disable CS8600, CS8625
Assert.Throws<ArgumentNullException>(() => stream.ReadExactly(null, 0, 1024));
#pragma warning restore CS8600, CS8625
}
[Test]
public void Test_Fat32ZeroStream_Read_InvalidOffset_Throws()
{
const int blockSize = 1024 * 1024; // 1MB
using var stream = new Fat32Filesystem.Fat32ZeroStream(blockSize);
var buffer = new byte[1024];
Assert.Throws<ArgumentOutOfRangeException>(() => stream.ReadExactly(buffer, -1, 1024));
Assert.Throws<ArgumentOutOfRangeException>(() => stream.ReadExactly(buffer, buffer.Length + 1, 1024));
}
[Test]
public void Test_Fat32ZeroStream_Read_InvalidCount_Throws()
{
const int blockSize = 1024 * 1024; // 1MB
using var stream = new Fat32Filesystem.Fat32ZeroStream(blockSize);
var buffer = new byte[1024];
Assert.Throws<ArgumentOutOfRangeException>(() => stream.ReadExactly(buffer, 0, -1));
Assert.Throws<ArgumentOutOfRangeException>(() => stream.ReadExactly(buffer, 512, 1024)); // Exceeds buffer length
}
}