mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-18 22:46:38 +08:00
204 lines
6.5 KiB
C#
204 lines
6.5 KiB
C#
using AtomUI.Controls;
|
|
using Avalonia;
|
|
using Avalonia.Platform;
|
|
using Avalonia.Platform.Storage;
|
|
using System.Reflection;
|
|
using Shouldly;
|
|
using Xunit;
|
|
|
|
namespace AtomUI.Controls.Shared.Tests.ImageLoading;
|
|
|
|
public class ImageSourceReaderReloadTests
|
|
{
|
|
[Fact]
|
|
public async Task File_Reload_Reads_The_Source_Instead_Of_Reusing_Stale_Content()
|
|
{
|
|
var path = Path.Combine(Path.GetTempPath(), $"atomui-image-reload-{Guid.NewGuid():N}.bin");
|
|
var fresh = new byte[] { 4, 5, 6 };
|
|
await File.WriteAllBytesAsync(path, fresh, TestContext.Current.CancellationToken);
|
|
try
|
|
{
|
|
var options = ImageLoadingTestSupport.CreateOptions();
|
|
var request = NormalizeReload(new FileImageSource(path), options);
|
|
var stale = ImageLoadingTestSupport.CreateContent([1, 2, 3]) with
|
|
{
|
|
SourceVersion = $"{fresh.Length}:{File.GetLastWriteTimeUtc(path).Ticks}"
|
|
};
|
|
|
|
var result = await new FileImageSourceReader(options).ReadAsync(
|
|
request,
|
|
stale,
|
|
null,
|
|
TestContext.Current.CancellationToken);
|
|
|
|
result.EncodedContent.ShouldNotBeNull().Bytes.ShouldBe(fresh);
|
|
}
|
|
finally
|
|
{
|
|
File.Delete(path);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Asset_Reload_Reads_The_Resource_Instead_Of_Reusing_Stale_Content()
|
|
{
|
|
var fresh = "fresh-asset"u8.ToArray();
|
|
AvaloniaLocator.CurrentMutable.Bind<IAssetLoader>().ToConstant(new TestAssetLoader(fresh));
|
|
var options = ImageLoadingTestSupport.CreateOptions();
|
|
var request = NormalizeReload(
|
|
new AssetImageSource(new Uri(
|
|
"avares://AtomUI.Controls.Shared.Tests/Resources/reload-source.bin")),
|
|
options);
|
|
var stale = ImageLoadingTestSupport.CreateContent([1, 2, 3]) with
|
|
{
|
|
SourceVersion = "application-resource-v1"
|
|
};
|
|
|
|
var result = await new AssetImageSourceReader(options).ReadAsync(
|
|
request,
|
|
stale,
|
|
null,
|
|
TestContext.Current.CancellationToken);
|
|
|
|
result.EncodedContent.ShouldNotBeNull().Bytes.ShouldNotBe(stale.Bytes);
|
|
result.EncodedContent.Bytes.ShouldBe(fresh);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task StorageFile_Reload_Opens_The_File_Even_When_The_Version_Is_Unchanged()
|
|
{
|
|
var options = ImageLoadingTestSupport.CreateOptions();
|
|
var file = new TestStorageFile([4, 5, 6]);
|
|
var request = NormalizeReload(
|
|
new StorageFileImageSource(file, "v1"),
|
|
options);
|
|
var stale = ImageLoadingTestSupport.CreateContent([1, 2, 3]) with { SourceVersion = "v1" };
|
|
|
|
var result = await new StorageFileImageSourceReader(options).ReadAsync(
|
|
request,
|
|
stale,
|
|
null,
|
|
TestContext.Current.CancellationToken);
|
|
|
|
file.OpenReadCount.ShouldBe(1);
|
|
result.EncodedContent.ShouldNotBeNull().Bytes.ShouldBe(new byte[] { 4, 5, 6 });
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Stream_Reload_Invokes_The_Factory_Even_When_The_Version_Is_Unchanged()
|
|
{
|
|
var options = ImageLoadingTestSupport.CreateOptions();
|
|
var openCount = 0;
|
|
var source = new StreamImageSource(
|
|
_ =>
|
|
{
|
|
Interlocked.Increment(ref openCount);
|
|
return ValueTask.FromResult<Stream>(new MemoryStream([4, 5, 6]));
|
|
},
|
|
"stream",
|
|
"v1");
|
|
var request = NormalizeReload(source, options);
|
|
var stale = ImageLoadingTestSupport.CreateContent([1, 2, 3]) with { SourceVersion = "v1" };
|
|
|
|
var result = await new StreamImageSourceReader(options).ReadAsync(
|
|
request,
|
|
stale,
|
|
null,
|
|
TestContext.Current.CancellationToken);
|
|
|
|
openCount.ShouldBe(1);
|
|
result.EncodedContent.ShouldNotBeNull().Bytes.ShouldBe(new byte[] { 4, 5, 6 });
|
|
}
|
|
|
|
private static NormalizedImageRequest NormalizeReload(
|
|
ImageSource source,
|
|
ImageLoadingOptions options)
|
|
{
|
|
return ImageCacheKey.Normalize(
|
|
new ImageLoadRequest(source)
|
|
{
|
|
Options = new ImageRequestOptions { CacheRead = ImageCacheReadPolicy.RefreshSource }
|
|
},
|
|
options,
|
|
forceReload: false);
|
|
}
|
|
|
|
private sealed class TestStorageFile : IStorageFile
|
|
{
|
|
private readonly byte[] _bytes;
|
|
|
|
internal TestStorageFile(byte[] bytes)
|
|
{
|
|
_bytes = bytes;
|
|
}
|
|
|
|
public string Name => "reload.bin";
|
|
|
|
public Uri Path => new("file:///reload.bin");
|
|
|
|
public bool CanBookmark => false;
|
|
|
|
internal int OpenReadCount { get; private set; }
|
|
|
|
public Task<StorageItemProperties> GetBasicPropertiesAsync() =>
|
|
Task.FromResult(new StorageItemProperties((ulong)_bytes.Length));
|
|
|
|
public Task<Stream> OpenReadAsync()
|
|
{
|
|
OpenReadCount++;
|
|
return Task.FromResult<Stream>(new MemoryStream(_bytes, writable: false));
|
|
}
|
|
|
|
public Task<Stream> OpenWriteAsync() =>
|
|
Task.FromResult<Stream>(new MemoryStream());
|
|
|
|
public Task<string?> SaveBookmarkAsync() => Task.FromResult<string?>(null);
|
|
|
|
public Task<IStorageFolder?> GetParentAsync() => Task.FromResult<IStorageFolder?>(null);
|
|
|
|
public Task DeleteAsync() => Task.CompletedTask;
|
|
|
|
public Task<IStorageItem?> MoveAsync(IStorageFolder destination) =>
|
|
Task.FromResult<IStorageItem?>(null);
|
|
|
|
public void Dispose()
|
|
{
|
|
}
|
|
}
|
|
|
|
private sealed class TestAssetLoader : IAssetLoader
|
|
{
|
|
private readonly byte[] _bytes;
|
|
|
|
internal TestAssetLoader(byte[] bytes)
|
|
{
|
|
_bytes = bytes;
|
|
}
|
|
|
|
public void SetDefaultAssembly(Assembly assembly)
|
|
{
|
|
}
|
|
|
|
public bool Exists(Uri uri, Uri? baseUri = null) => true;
|
|
|
|
public Stream Open(Uri uri, Uri? baseUri = null) =>
|
|
new MemoryStream(_bytes, writable: false);
|
|
|
|
public (Stream stream, Assembly assembly) OpenAndGetAssembly(Uri uri, Uri? baseUri = null) =>
|
|
(Open(uri, baseUri), typeof(TestAssetLoader).Assembly);
|
|
|
|
public Assembly? GetAssembly(Uri uri, Uri? baseUri = null) =>
|
|
typeof(TestAssetLoader).Assembly;
|
|
|
|
public IEnumerable<Uri> GetAssets(Uri uri, Uri? baseUri) => [uri];
|
|
|
|
public void InvalidateAssemblyCache(string name)
|
|
{
|
|
}
|
|
|
|
public void InvalidateAssemblyCache()
|
|
{
|
|
}
|
|
}
|
|
}
|