Files
deepdrft/DeepDrftTests/SimpleMediaTypeRegistryTests.cs
T
daniel-c-harvey fa57861dbf Add server-side waveform loudness profiling on track upload
ILoudnessAlgorithm strategy (RmsLoudnessAlgorithm first impl), WaveformProfileService
stores quantized byte[] sidecar in new MediaFileVault (profiles vault), wired into
UnifiedTrackService.UploadAsync; failure is logged and swallowed. WaveformProfileDto
and WaveformProfileOptions in shared projects.
2026-06-05 16:38:02 -04:00

621 lines
26 KiB
C#

using DeepDrftContent.FileDatabase.Models;
using DeepDrftContent.FileDatabase.Services;
namespace DeepDrftTests;
/// <summary>
/// SOLID, DRY tests for SimpleMediaTypeRegistry
/// Follows Single Responsibility: Each test class tests one registry concern
/// Follows Open/Closed: Tests extensibility patterns and type safety
/// Follows Interface Segregation: Tests focused interface methods
/// </summary>
[TestFixture]
public class SimpleMediaTypeRegistryTests
{
/// <summary>
/// Base class for registry tests - DRY principle
/// </summary>
public abstract class RegistryTestBase
{
protected SimpleMediaTypeRegistry Registry { get; private set; } = null!;
protected string TestDirectory { get; private set; } = null!;
[SetUp]
public virtual void SetUp()
{
Registry = new SimpleMediaTypeRegistry();
TestDirectory = Path.Combine(Path.GetTempPath(), "DeepDrftTests", "Registry", Guid.NewGuid().ToString());
Directory.CreateDirectory(TestDirectory);
}
[TearDown]
public virtual void TearDown()
{
if (Directory.Exists(TestDirectory))
{
try { Directory.Delete(TestDirectory, true); } catch { /* Ignore cleanup errors */ }
}
}
/// <summary>
/// Helper method to create test binary objects using existing factories - DRY principle
/// </summary>
protected T CreateTestBinary<T>(MediaVaultType vaultType) where T : FileBinary
{
var parameters = CreateTestParams(vaultType);
return (T)Registry.CreateBinary(vaultType, parameters);
}
/// <summary>
/// Helper method to create test parameters using TestData - DRY principle
/// </summary>
protected object CreateTestParams(MediaVaultType vaultType)
{
return vaultType switch
{
MediaVaultType.Media => new MediaBinaryParams(TestData.TestPngBytes, TestData.TestPngBytes.Length, ".dat"),
MediaVaultType.Image => new ImageBinaryParams(TestData.TestPngBytes, TestData.TestPngBytes.Length, ".png", 1.0),
MediaVaultType.Audio => new AudioBinaryParams(TestData.TestPngBytes, TestData.TestPngBytes.Length, ".mp3", 120.0, 320),
_ => throw new ArgumentException($"Unsupported vault type: {vaultType}")
};
}
/// <summary>
/// Helper method to create test DTOs - DRY principle
/// </summary>
protected object CreateTestDto(MediaVaultType vaultType)
{
var base64Data = Convert.ToBase64String(TestData.TestPngBytes);
return vaultType switch
{
MediaVaultType.Media => new MediaBinaryDto(base64Data, TestData.TestPngBytes.Length, "application/octet-stream"),
MediaVaultType.Image => new ImageBinaryDto(base64Data, TestData.TestPngBytes.Length, "image/png", 1.0),
MediaVaultType.Audio => new AudioBinaryDto(base64Data, TestData.TestPngBytes.Length, "audio/mpeg", 120.0, 320),
_ => throw new ArgumentException($"Unsupported vault type: {vaultType}")
};
}
/// <summary>
/// Helper method to create test metadata using existing factories - DRY principle
/// </summary>
protected MetaData CreateTestMetaData(MediaVaultType vaultType, string key = "test", string extension = ".png")
{
// Use the registry's metadata creation for consistency
var binary = CreateTestBinary<FileBinary>(vaultType);
return Registry.CreateMetaDataFromMedia(vaultType, key, extension, binary);
}
}
/// <summary>
/// Tests for binary creation functionality - Single Responsibility
/// </summary>
[TestFixture]
public class BinaryCreationTests : RegistryTestBase
{
[Test]
public void CreateBinary_MediaVaultType_CreatesMediaBinary()
{
// Arrange
var parameters = CreateTestParams(MediaVaultType.Media);
// Act
var binary = Registry.CreateBinary(MediaVaultType.Media, parameters);
// Assert
Assert.That(binary, Is.Not.Null, "Binary should be created");
Assert.That(binary, Is.TypeOf<MediaBinary>(), "Should create MediaBinary");
var mediaBinary = (MediaBinary)binary;
Assert.That(mediaBinary.Buffer.Length, Is.EqualTo(TestData.TestPngBytes.Length), "Buffer should match");
Assert.That(mediaBinary.Extension, Is.EqualTo(".dat"), "Extension should match");
}
[Test]
public void CreateBinary_ImageVaultType_CreatesImageBinary()
{
// Arrange
var parameters = CreateTestParams(MediaVaultType.Image);
// Act
var binary = Registry.CreateBinary(MediaVaultType.Image, parameters);
// Assert
Assert.That(binary, Is.Not.Null, "Binary should be created");
Assert.That(binary, Is.TypeOf<ImageBinary>(), "Should create ImageBinary");
var imageBinary = (ImageBinary)binary;
Assert.That(imageBinary.Buffer.Length, Is.EqualTo(TestData.TestPngBytes.Length), "Buffer should match");
Assert.That(imageBinary.Extension, Is.EqualTo(".png"), "Extension should match");
Assert.That(imageBinary.AspectRatio, Is.EqualTo(1.0), "Aspect ratio should match");
}
[Test]
public void CreateBinary_AudioVaultType_CreatesAudioBinary()
{
// Arrange
var parameters = CreateTestParams(MediaVaultType.Audio);
// Act
var binary = Registry.CreateBinary(MediaVaultType.Audio, parameters);
// Assert
Assert.That(binary, Is.Not.Null, "Binary should be created");
Assert.That(binary, Is.TypeOf<AudioBinary>(), "Should create AudioBinary");
var audioBinary = (AudioBinary)binary;
Assert.That(audioBinary.Buffer.Length, Is.EqualTo(TestData.TestPngBytes.Length), "Buffer should match");
Assert.That(audioBinary.Extension, Is.EqualTo(".mp3"), "Extension should match");
Assert.That(audioBinary.Duration, Is.EqualTo(120.0), "Duration should match");
Assert.That(audioBinary.Bitrate, Is.EqualTo(320), "Bitrate should match");
}
[Test]
public void CreateBinary_InvalidVaultType_ThrowsArgumentException()
{
// Arrange
var invalidType = (MediaVaultType)999;
var parameters = CreateTestParams(MediaVaultType.Media);
// Act & Assert
Assert.Throws<ArgumentException>(() =>
Registry.CreateBinary(invalidType, parameters),
"Should throw for invalid vault type");
}
[Test]
public void CreateBinary_WrongParameterType_ThrowsException()
{
// Arrange - Use Image parameters for Media vault type
var imageParameters = CreateTestParams(MediaVaultType.Image);
// Act & Assert - The registry is flexible and may handle type mismatches gracefully
// depending on the parameter compatibility
try
{
var result = Registry.CreateBinary(MediaVaultType.Media, imageParameters);
// If it succeeds, verify it created something reasonable
Assert.That(result, Is.Not.Null, "Should create some binary even with mismatched parameters");
Assert.That(result, Is.TypeOf<MediaBinary>(), "Should create MediaBinary for Media vault type");
}
catch (InvalidCastException)
{
Assert.Pass("Registry correctly threw InvalidCastException for parameter mismatch");
}
catch (ArgumentException)
{
Assert.Pass("Registry correctly threw ArgumentException for parameter mismatch");
}
}
}
/// <summary>
/// Tests for DTO creation and conversion - Single Responsibility
/// </summary>
[TestFixture]
public class DtoCreationTests : RegistryTestBase
{
[Test]
public void CreateBinaryFromDto_MediaVaultType_CreatesMediaBinary()
{
// Arrange
var dto = CreateTestDto(MediaVaultType.Media);
// Act
var binary = Registry.CreateBinaryFromDto(MediaVaultType.Media, dto);
// Assert
Assert.That(binary, Is.Not.Null, "Binary should be created from DTO");
Assert.That(binary, Is.TypeOf<MediaBinary>(), "Should create MediaBinary");
var mediaBinary = (MediaBinary)binary;
Assert.That(mediaBinary.Buffer, Is.EqualTo(TestData.TestPngBytes), "Buffer should match original");
}
[Test]
public void CreateBinaryFromDto_ImageVaultType_CreatesImageBinary()
{
// Arrange
var dto = CreateTestDto(MediaVaultType.Image);
// Act
var binary = Registry.CreateBinaryFromDto(MediaVaultType.Image, dto);
// Assert
Assert.That(binary, Is.Not.Null, "Binary should be created from DTO");
Assert.That(binary, Is.TypeOf<ImageBinary>(), "Should create ImageBinary");
var imageBinary = (ImageBinary)binary;
Assert.That(imageBinary.Buffer, Is.EqualTo(TestData.TestPngBytes), "Buffer should match original");
Assert.That(imageBinary.AspectRatio, Is.EqualTo(1.0), "Aspect ratio should be preserved");
}
[Test]
public void CreateBinaryFromDto_AudioVaultType_CreatesAudioBinary()
{
// Arrange
var dto = CreateTestDto(MediaVaultType.Audio);
// Act
var binary = Registry.CreateBinaryFromDto(MediaVaultType.Audio, dto);
// Assert
Assert.That(binary, Is.Not.Null, "Binary should be created from DTO");
Assert.That(binary, Is.TypeOf<AudioBinary>(), "Should create AudioBinary");
var audioBinary = (AudioBinary)binary;
Assert.That(audioBinary.Buffer, Is.EqualTo(TestData.TestPngBytes), "Buffer should match original");
Assert.That(audioBinary.Duration, Is.EqualTo(120.0), "Duration should be preserved");
Assert.That(audioBinary.Bitrate, Is.EqualTo(320), "Bitrate should be preserved");
}
[Test]
public void CreateDto_MediaBinary_CreatesMediaBinaryDto()
{
// Arrange
var binary = CreateTestBinary<MediaBinary>(MediaVaultType.Media);
// Act
var dto = Registry.CreateDto(MediaVaultType.Media, binary);
// Assert
Assert.That(dto, Is.Not.Null, "DTO should be created");
Assert.That(dto, Is.TypeOf<MediaBinaryDto>(), "Should create MediaBinaryDto");
var mediaDto = (MediaBinaryDto)dto;
Assert.That(mediaDto.Size, Is.EqualTo(binary.Size), "Size should match");
var decodedBuffer = Convert.FromBase64String(mediaDto.Base64);
Assert.That(decodedBuffer, Is.EqualTo(binary.Buffer), "Decoded buffer should match original");
}
[Test]
public void CreateDto_ImageBinary_CreatesImageBinaryDto()
{
// Arrange
var binary = CreateTestBinary<ImageBinary>(MediaVaultType.Image);
// Act
var dto = Registry.CreateDto(MediaVaultType.Image, binary);
// Assert
Assert.That(dto, Is.Not.Null, "DTO should be created");
Assert.That(dto, Is.TypeOf<ImageBinaryDto>(), "Should create ImageBinaryDto");
var imageDto = (ImageBinaryDto)dto;
Assert.That(imageDto.Size, Is.EqualTo(binary.Size), "Size should match");
Assert.That(imageDto.AspectRatio, Is.EqualTo(binary.AspectRatio), "Aspect ratio should match");
}
[Test]
public void CreateDto_AudioBinary_CreatesAudioBinaryDto()
{
// Arrange
var binary = CreateTestBinary<AudioBinary>(MediaVaultType.Audio);
// Act
var dto = Registry.CreateDto(MediaVaultType.Audio, binary);
// Assert
Assert.That(dto, Is.Not.Null, "DTO should be created");
Assert.That(dto, Is.TypeOf<AudioBinaryDto>(), "Should create AudioBinaryDto");
var audioDto = (AudioBinaryDto)dto;
Assert.That(audioDto.Size, Is.EqualTo(binary.Size), "Size should match");
Assert.That(audioDto.Duration, Is.EqualTo(binary.Duration), "Duration should match");
Assert.That(audioDto.Bitrate, Is.EqualTo(binary.Bitrate), "Bitrate should match");
}
}
/// <summary>
/// Tests for metadata creation - Single Responsibility
/// </summary>
[TestFixture]
public class MetaDataCreationTests : RegistryTestBase
{
[Test]
public void CreateMetaDataFromMedia_ImageBinary_CreatesImageMetaData()
{
// Arrange
var imageBinary = CreateTestBinary<ImageBinary>(MediaVaultType.Image);
const string key = "test-image";
const string extension = ".png";
// Act
var metaData = Registry.CreateMetaDataFromMedia(MediaVaultType.Image, key, extension, imageBinary);
// Assert
Assert.That(metaData, Is.Not.Null, "MetaData should be created");
Assert.That(metaData, Is.TypeOf<ImageMetaData>(), "Should create ImageMetaData");
var imageMetaData = (ImageMetaData)metaData;
Assert.That(imageMetaData.MediaKey, Is.EqualTo(key), "Key should match");
Assert.That(imageMetaData.Extension, Is.EqualTo(extension), "Extension should match");
Assert.That(imageMetaData.AspectRatio, Is.EqualTo(imageBinary.AspectRatio), "Should extract aspect ratio");
}
[Test]
public void CreateMetaDataFromMedia_AudioBinary_CreatesAudioMetaData()
{
// Arrange
var audioBinary = CreateTestBinary<AudioBinary>(MediaVaultType.Audio);
const string key = "test-audio";
const string extension = ".mp3";
// Act
var metaData = Registry.CreateMetaDataFromMedia(MediaVaultType.Audio, key, extension, audioBinary);
// Assert
Assert.That(metaData, Is.Not.Null, "MetaData should be created");
Assert.That(metaData, Is.TypeOf<AudioMetaData>(), "Should create AudioMetaData");
var audioMetaData = (AudioMetaData)metaData;
Assert.That(audioMetaData.MediaKey, Is.EqualTo(key), "Key should match");
Assert.That(audioMetaData.Extension, Is.EqualTo(extension), "Extension should match");
Assert.That(audioMetaData.Duration, Is.EqualTo(audioBinary.Duration), "Should extract duration");
Assert.That(audioMetaData.Bitrate, Is.EqualTo(audioBinary.Bitrate), "Should extract bitrate");
}
[Test]
public void CreateMetaDataFromMedia_MediaBinary_CreatesBaseMetaData()
{
// Arrange
var mediaBinary = CreateTestBinary<MediaBinary>(MediaVaultType.Media);
const string key = "test-media";
const string extension = ".dat";
// Act
var metaData = Registry.CreateMetaDataFromMedia(MediaVaultType.Media, key, extension, mediaBinary);
// Assert
Assert.That(metaData, Is.Not.Null, "MetaData should be created");
Assert.That(metaData, Is.TypeOf<MetaData>(), "Should create base MetaData");
Assert.That(metaData.MediaKey, Is.EqualTo(key), "Key should match");
Assert.That(metaData.Extension, Is.EqualTo(extension), "Extension should match");
}
[Test]
public void CreateMetaDataFromMedia_WrongMediaType_CreatesBaseMetaData()
{
// Arrange - Pass MediaBinary to Image vault type
var mediaBinary = CreateTestBinary<MediaBinary>(MediaVaultType.Media);
const string key = "test-wrong";
const string extension = ".dat";
// Act
var metaData = Registry.CreateMetaDataFromMedia(MediaVaultType.Image, key, extension, mediaBinary);
// Assert - Should fallback to base MetaData when media type doesn't match vault type
Assert.That(metaData, Is.Not.Null, "MetaData should be created");
Assert.That(metaData, Is.TypeOf<MetaData>(), "Should create base MetaData as fallback");
}
}
/// <summary>
/// Tests for parameter creation - Interface Segregation
/// </summary>
[TestFixture]
public class ParameterCreationTests : RegistryTestBase
{
[Test]
public void CreateParams_ImageBinaryWithImageMetaData_CreatesImageBinaryParams()
{
// Arrange
var fileBinary = new FileBinary(new FileBinaryParams(TestData.TestPngBytes, TestData.TestPngBytes.Length));
var imageMetaData = new ImageMetaData("test", ".png", 1.5);
// Act
var parameters = Registry.CreateParams(MediaVaultType.Image, fileBinary, imageMetaData);
// Assert
Assert.That(parameters, Is.Not.Null, "Parameters should be created");
Assert.That(parameters, Is.TypeOf<ImageBinaryParams>(), "Should create ImageBinaryParams");
var imageParams = (ImageBinaryParams)parameters;
Assert.That(imageParams.Buffer, Is.EqualTo(fileBinary.Buffer), "Buffer should match");
Assert.That(imageParams.Size, Is.EqualTo(fileBinary.Size), "Size should match");
Assert.That(imageParams.Extension, Is.EqualTo(imageMetaData.Extension), "Extension should match");
Assert.That(imageParams.AspectRatio, Is.EqualTo(imageMetaData.AspectRatio), "Aspect ratio should match");
}
[Test]
public void CreateParams_AudioBinaryWithAudioMetaData_CreatesAudioBinaryParams()
{
// Arrange
var fileBinary = new FileBinary(new FileBinaryParams(TestData.TestPngBytes, TestData.TestPngBytes.Length));
var audioMetaData = new AudioMetaData("test", ".mp3", 180.0, 256);
// Act
var parameters = Registry.CreateParams(MediaVaultType.Audio, fileBinary, audioMetaData);
// Assert
Assert.That(parameters, Is.Not.Null, "Parameters should be created");
Assert.That(parameters, Is.TypeOf<AudioBinaryParams>(), "Should create AudioBinaryParams");
var audioParams = (AudioBinaryParams)parameters;
Assert.That(audioParams.Buffer, Is.EqualTo(fileBinary.Buffer), "Buffer should match");
Assert.That(audioParams.Size, Is.EqualTo(fileBinary.Size), "Size should match");
Assert.That(audioParams.Extension, Is.EqualTo(audioMetaData.Extension), "Extension should match");
Assert.That(audioParams.Duration, Is.EqualTo(audioMetaData.Duration), "Duration should match");
Assert.That(audioParams.Bitrate, Is.EqualTo(audioMetaData.Bitrate), "Bitrate should match");
}
[Test]
public void CreateParams_WrongMetaDataType_ThrowsArgumentException()
{
// Arrange
var fileBinary = new FileBinary(new FileBinaryParams(TestData.TestPngBytes, TestData.TestPngBytes.Length));
var baseMetaData = new MetaData("test", ".png"); // Wrong metadata type for Image vault
// Act & Assert
Assert.Throws<ArgumentException>(() =>
Registry.CreateParams(MediaVaultType.Image, fileBinary, baseMetaData),
"Should throw when metadata type doesn't match vault type requirements");
}
}
/// <summary>
/// Tests for vault creation - Dependency Inversion
/// </summary>
[TestFixture]
public class VaultCreationTests : RegistryTestBase
{
[Test]
public async Task CreateVaultAsync_ImageVaultType_CreatesImageVault()
{
// Act
var vault = await Registry.CreateVaultAsync(MediaVaultType.Image, TestDirectory);
// Assert
Assert.That(vault, Is.Not.Null, "Vault should be created");
Assert.That(vault, Is.TypeOf<ImageVault>(), "Should create ImageVault");
Assert.That(vault!.RootPath, Is.EqualTo(TestDirectory), "Should use provided path");
}
[Test]
public async Task CreateVaultAsync_AudioVaultType_CreatesAudioVault()
{
// Act
var vault = await Registry.CreateVaultAsync(MediaVaultType.Audio, TestDirectory);
// Assert
Assert.That(vault, Is.Not.Null, "Vault should be created");
Assert.That(vault, Is.TypeOf<AudioVault>(), "Should create AudioVault");
Assert.That(vault!.RootPath, Is.EqualTo(TestDirectory), "Should use provided path");
}
[Test]
public async Task CreateVaultAsync_MediaVaultType_CreatesMediaFileVault()
{
// Act
var vault = await Registry.CreateVaultAsync(MediaVaultType.Media, TestDirectory);
// Assert — Media now has a concrete vault (MediaFileVault) for plain MediaBinary
// sidecars such as waveform loudness profiles.
Assert.That(vault, Is.Not.Null);
Assert.That(vault, Is.InstanceOf<MediaFileVault>());
}
}
/// <summary>
/// Tests for type information retrieval - Interface Segregation
/// </summary>
[TestFixture]
public class TypeInformationTests : RegistryTestBase
{
[Test]
public void GetBinaryType_AllSupportedTypes_ReturnsCorrectTypes()
{
// Test all supported vault types
var expectedTypes = new Dictionary<MediaVaultType, Type>
{
{ MediaVaultType.Media, typeof(MediaBinary) },
{ MediaVaultType.Image, typeof(ImageBinary) },
{ MediaVaultType.Audio, typeof(AudioBinary) }
};
foreach (var (vaultType, expectedType) in expectedTypes)
{
// Act
var actualType = Registry.GetBinaryType(vaultType);
// Assert
Assert.That(actualType, Is.EqualTo(expectedType), $"Binary type for {vaultType} should be {expectedType.Name}");
}
}
[Test]
public void GetDtoType_AllSupportedTypes_ReturnsCorrectTypes()
{
// Test all supported vault types
var expectedTypes = new Dictionary<MediaVaultType, Type>
{
{ MediaVaultType.Media, typeof(MediaBinaryDto) },
{ MediaVaultType.Image, typeof(ImageBinaryDto) },
{ MediaVaultType.Audio, typeof(AudioBinaryDto) }
};
foreach (var (vaultType, expectedType) in expectedTypes)
{
// Act
var actualType = Registry.GetDtoType(vaultType);
// Assert
Assert.That(actualType, Is.EqualTo(expectedType), $"DTO type for {vaultType} should be {expectedType.Name}");
}
}
[Test]
public void GetParamsType_AllSupportedTypes_ReturnsCorrectTypes()
{
// Test all supported vault types
var expectedTypes = new Dictionary<MediaVaultType, Type>
{
{ MediaVaultType.Media, typeof(MediaBinaryParams) },
{ MediaVaultType.Image, typeof(ImageBinaryParams) },
{ MediaVaultType.Audio, typeof(AudioBinaryParams) }
};
foreach (var (vaultType, expectedType) in expectedTypes)
{
// Act
var actualType = Registry.GetParamsType(vaultType);
// Assert
Assert.That(actualType, Is.EqualTo(expectedType), $"Params type for {vaultType} should be {expectedType.Name}");
}
}
[Test]
public void GetMetaDataType_AllSupportedTypes_ReturnsCorrectTypes()
{
// Test all supported vault types
var expectedTypes = new Dictionary<MediaVaultType, Type>
{
{ MediaVaultType.Media, typeof(MetaData) },
{ MediaVaultType.Image, typeof(ImageMetaData) },
{ MediaVaultType.Audio, typeof(AudioMetaData) }
};
foreach (var (vaultType, expectedType) in expectedTypes)
{
// Act
var actualType = Registry.GetMetaDataType(vaultType);
// Assert
Assert.That(actualType, Is.EqualTo(expectedType), $"MetaData type for {vaultType} should be {expectedType.Name}");
}
}
[Test]
public void GetBinaryType_InvalidVaultType_ThrowsArgumentException()
{
// Arrange
var invalidType = (MediaVaultType)999;
// Act & Assert
Assert.Throws<ArgumentException>(() =>
Registry.GetBinaryType(invalidType),
"Should throw for invalid vault type");
}
}
/// <summary>
/// Tests for external registration (currently not implemented) - Open/Closed Principle
/// </summary>
[TestFixture]
public class ExternalRegistrationTests : RegistryTestBase
{
[Test]
public void RegisterMediaType_ExternalRegistration_ThrowsNotImplementedException()
{
// This test documents the current limitation and ensures we know when it changes
// Act & Assert
Assert.Throws<NotImplementedException>(() =>
Registry.RegisterMediaType<MediaBinary, MediaBinaryParams, MediaBinaryDto, MetaData, ImageVault>(MediaVaultType.Media),
"External registration should throw NotImplementedException until implemented");
}
}
}