156 lines
5.6 KiB
C#
156 lines
5.6 KiB
C#
using Omika.App.Local.Abstractions;
|
|
using Omika.Core.Constants;
|
|
using Omika.Core.Interfaces;
|
|
|
|
namespace Omika.Tests.Mobile.Local;
|
|
|
|
/// <summary>
|
|
/// Double de test de <see cref="IImageOptimizer"/>.
|
|
///
|
|
/// Par défaut il reproduit le comportement « aucune optimisation » : le fichier
|
|
/// source est copié à l'identique vers la destination et le résultat indique que
|
|
/// rien n'a été modifié. C'est le comportement attendu pour une image déjà sous
|
|
/// la limite, et cela permet aux tests existants de rester valides.
|
|
///
|
|
/// Le test peut demander une optimisation simulée via <see cref="OptimizedBytes"/>.
|
|
/// </summary>
|
|
public sealed class FakeImageOptimizer : IImageOptimizer
|
|
{
|
|
/// <summary>Nombre d'appels reçus.</summary>
|
|
public int Calls { get; private set; }
|
|
|
|
/// <summary>Dernière limite reçue, en kilo-octets.</summary>
|
|
public int LastMaxSizeKb { get; private set; } = -1;
|
|
|
|
/// <summary>
|
|
/// Contenu à écrire lorsque l'optimisation est simulée. <see langword="null"/>
|
|
/// signifie « copier la source telle quelle ».
|
|
/// </summary>
|
|
public byte[]? OptimizedBytes { get; set; }
|
|
|
|
/// <summary>Qualité à reporter lorsque l'optimisation est simulée.</summary>
|
|
public int? ReportedQuality { get; set; } = 78;
|
|
|
|
/// <inheritdoc />
|
|
public Task<ImageOptimizationResult> OptimizeFileAsync(
|
|
string sourcePath,
|
|
string destinationPath,
|
|
string? fileName,
|
|
string? mimeType,
|
|
int maxSizeKb,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
Calls++;
|
|
LastMaxSizeKb = maxSizeKb;
|
|
|
|
long originalBytes = new FileInfo(sourcePath).Length;
|
|
|
|
if (OptimizedBytes is not null)
|
|
{
|
|
File.WriteAllBytes(destinationPath, OptimizedBytes);
|
|
return Task.FromResult(new ImageOptimizationResult
|
|
{
|
|
DestinationPath = destinationPath,
|
|
WasOptimized = true,
|
|
OriginalBytes = originalBytes,
|
|
FinalBytes = OptimizedBytes.LongLength,
|
|
OriginalWidth = 4000,
|
|
OriginalHeight = 3000,
|
|
FinalWidth = 2000,
|
|
FinalHeight = 1500,
|
|
Quality = ReportedQuality
|
|
});
|
|
}
|
|
|
|
File.Copy(sourcePath, destinationPath, overwrite: true);
|
|
return Task.FromResult(new ImageOptimizationResult
|
|
{
|
|
DestinationPath = destinationPath,
|
|
WasOptimized = false,
|
|
OriginalBytes = originalBytes,
|
|
FinalBytes = originalBytes
|
|
});
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Double de test de <see cref="IPhotoPolicyProvider"/> : retourne une limite
|
|
/// fixe, configurable par le test.
|
|
/// </summary>
|
|
public sealed class FakePhotoPolicyProvider : IPhotoPolicyProvider
|
|
{
|
|
/// <summary>Limite retournée, en kilo-octets (0 = aucune limite).</summary>
|
|
public int MaxSizeKb { get; set; } = 500;
|
|
|
|
/// <summary>Origine retournée.</summary>
|
|
public PhotoLimitSource Source { get; set; } = PhotoLimitSource.ApplicationParameter;
|
|
|
|
/// <inheritdoc />
|
|
public Task<PhotoLimitResolution> GetResolutionAsync(CancellationToken cancellationToken = default)
|
|
=> Task.FromResult(new PhotoLimitResolution(MaxSizeKb, Source));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Double de test de <see cref="IApplicationParameterRepository"/> adossé à un
|
|
/// dictionnaire en mémoire.
|
|
/// </summary>
|
|
public sealed class FakeApplicationParameterRepository : IApplicationParameterRepository
|
|
{
|
|
/// <summary>Valeurs des paramètres applicatifs, indexées par code.</summary>
|
|
public Dictionary<string, string?> Values { get; } = new(StringComparer.Ordinal);
|
|
|
|
/// <inheritdoc />
|
|
public Task<string?> GetValueAsync(string code, CancellationToken cancellationToken = default)
|
|
{
|
|
Values.TryGetValue(code, out string? value);
|
|
return Task.FromResult(value);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Double de test de <see cref="IDocumentDateResolver"/>.
|
|
///
|
|
/// Par défaut il reproduit le cas « aucune métadonnée fiable » : la date système
|
|
/// est retournée avec la source <see cref="DocumentDateSource.SystemFallback"/>,
|
|
/// ce qui correspond au comportement des tests existants (aucun fichier réel
|
|
/// porteur d'EXIF). Le test peut fixer une date explicite avec
|
|
/// <see cref="ResolvedDate"/>, ou simuler un lecteur en échec avec
|
|
/// <see cref="ThrowOnResolve"/>.
|
|
/// </summary>
|
|
public sealed class FakeDocumentDateResolver : IDocumentDateResolver
|
|
{
|
|
/// <summary>Nombre d'appels reçus.</summary>
|
|
public int Calls { get; private set; }
|
|
|
|
/// <summary>Dernier chemin reçu.</summary>
|
|
public string? LastPath { get; private set; }
|
|
|
|
/// <summary>Date retournée lorsque la propriété est fixée.</summary>
|
|
public DateTime? ResolvedDate { get; set; }
|
|
|
|
/// <summary>Origine retournée (utilisée seulement si <see cref="ResolvedDate"/> est fixée).</summary>
|
|
public DocumentDateSource Source { get; set; } = DocumentDateSource.ExifDateTimeOriginal;
|
|
|
|
/// <summary>Simule un lecteur en échec : la résolution lève une exception.</summary>
|
|
public bool ThrowOnResolve { get; set; }
|
|
|
|
/// <inheritdoc />
|
|
public Task<DocumentDateResolution> ResolveAsync(
|
|
string filePath,
|
|
string? fileName,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
Calls++;
|
|
LastPath = filePath;
|
|
|
|
if (ThrowOnResolve)
|
|
{
|
|
throw new IOException("Métadonnées illisibles (simulation de test).");
|
|
}
|
|
|
|
return Task.FromResult(ResolvedDate is { } value
|
|
? new DocumentDateResolution(value, Source)
|
|
: new DocumentDateResolution(DateTime.Now, DocumentDateSource.SystemFallback));
|
|
}
|
|
}
|