Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions ImmichFrame.Core.Tests/Logic/Pool/AlbumAssetsPoolTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,22 @@ public class AlbumAssetsPoolTests
private Mock<IApiCache> _mockApiCache;
private Mock<ImmichApi> _mockImmichApi;
private Mock<IAccountSettings> _mockAccountSettings;
private TestableAlbumAssetsPool _albumAssetsPool;

private class TestableAlbumAssetsPool(IApiCache apiCache, ImmichApi immichApi, IAccountSettings accountSettings)
: AlbumAssetsPool(apiCache, immichApi, accountSettings)
{
// Expose LoadAssets for testing
public Task<IEnumerable<AssetResponseDto>> TestLoadAssets(CancellationToken ct = default) => base.LoadAssets(ct);
}
private AlbumAssetsPool _albumAssetsPool;

[SetUp]
public void Setup()
{
_mockApiCache = new Mock<IApiCache>();

_mockApiCache
.Setup(m => m.GetOrAddAsync(
It.IsAny<string>(),
It.IsAny<Func<Task<IEnumerable<AssetResponseDto>>>>()))
.Returns<string, Func<Task<IEnumerable<AssetResponseDto>>>>((_, factory) => factory());

_mockImmichApi = new Mock<ImmichApi>("", null);
_mockAccountSettings = new Mock<IAccountSettings>();
_albumAssetsPool = new TestableAlbumAssetsPool(_mockApiCache.Object, _mockImmichApi.Object, _mockAccountSettings.Object);
_albumAssetsPool = new AlbumAssetsPool(_mockApiCache.Object, _mockImmichApi.Object, _mockAccountSettings.Object);

_mockAccountSettings.SetupGet(s => s.Albums).Returns(new List<Guid>());
_mockAccountSettings.SetupGet(s => s.ExcludedAlbums).Returns(new List<Guid>());
Expand All @@ -50,7 +50,7 @@ public async Task LoadAssets_ReturnsAssetsPresentIIncludedNotExcludedAlbums()
var assetA = CreateAsset("A"); // In album1
var assetB = CreateAsset("B"); // In album1 and excludedAlbum
var assetC = CreateAsset("C"); // In excludedAlbum only
var assetD = CreateAsset("D"); // In album1 only (but not B)
var assetD = CreateAsset("D"); // In album1 only

_mockAccountSettings.SetupGet(s => s.Albums).Returns(new List<Guid> { album1Id });
_mockAccountSettings.SetupGet(s => s.ExcludedAlbums).Returns(new List<Guid> { excludedAlbumId });
Expand All @@ -61,7 +61,7 @@ public async Task LoadAssets_ReturnsAssetsPresentIIncludedNotExcludedAlbums()
.ReturnsAsync(new AlbumResponseDto { Assets = new List<AssetResponseDto> { assetB, assetC } });

// Act
var result = (await _albumAssetsPool.TestLoadAssets()).ToList();
var result = (await _albumAssetsPool.GetAssets(25)).ToList();

// Assert
Assert.That(result.Count, Is.EqualTo(2));
Expand All @@ -80,7 +80,7 @@ public async Task LoadAssets_NoIncludedAlbums_ReturnsEmpty()
.ReturnsAsync(new AlbumResponseDto { Assets = new List<AssetResponseDto> { CreateAsset("excluded_only") } });


var result = (await _albumAssetsPool.TestLoadAssets()).ToList();
var result = (await _albumAssetsPool.GetAssets(25)).ToList();
Assert.That(result, Is.Empty);
}

Expand All @@ -94,7 +94,7 @@ public async Task LoadAssets_NoExcludedAlbums_ReturnsAlbums()
_mockImmichApi.Setup(api => api.GetAlbumInfoAsync(album1Id, null, null, It.IsAny<CancellationToken>()))
.ReturnsAsync(new AlbumResponseDto { Assets = new List<AssetResponseDto> { CreateAsset("A") } });

var result = (await _albumAssetsPool.TestLoadAssets()).ToList();
var result = (await _albumAssetsPool.GetAssets(25)).ToList();
Assert.That(result.Count, Is.EqualTo(1));
Assert.That(result.Any(a => a.Id == "A"));
}
Expand Down
98 changes: 83 additions & 15 deletions ImmichFrame.Core.Tests/Logic/Pool/AllAssetsPoolTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,36 @@ public void Setup()
It.IsAny<Func<Task<AssetStatsResponseDto>>>() // For GetAssetCount
))
.Returns<string, Func<Task<AssetStatsResponseDto>>>(async (key, factory) => await factory());

_mockApiCache.Setup(c => c.GetOrAddAsync(
It.IsAny<string>(),
It.IsAny<Func<Task<IEnumerable<AssetResponseDto>>>>()
))
.Returns<string, Func<Task<IEnumerable<AssetResponseDto>>>>(async (key, factory) => await factory());
}

private List<AssetResponseDto> CreateSampleAssets(int count, string idPrefix = "asset")
private List<AssetResponseDto> CreateSampleAssets(int count, string idPrefix, AssetTypeEnum type, int? rating = null)
{
return Enumerable.Range(0, count)
.Select(i => new AssetResponseDto { Id = $"{idPrefix}{i}", Type = AssetTypeEnum.IMAGE })
.Select(i => new AssetResponseDto { Id = $"{idPrefix}{i}", Type = type, ExifInfo = new ExifResponseDto { Rating = rating } })
.ToList();
}

private List<AssetResponseDto> CreateSampleImageAssets(int count, string idPrefix = "asset", int? rating = null)
{
return CreateSampleAssets(count, idPrefix, AssetTypeEnum.IMAGE, rating);
}

private List<AssetResponseDto> CreateSampleVideoAssets(int count, string idPrefix = "asset", int? rating = null)
{
return CreateSampleAssets(count, idPrefix, AssetTypeEnum.VIDEO, rating);
}

[Test]
public async Task GetAssetCount_CallsApiAndCache()
public async Task GetAssetCount_CallsApiAndCache_OnlyImages()
{
// Arrange
var stats = new AssetStatsResponseDto { Images = 100 };
var stats = new AssetStatsResponseDto { Images = 100, Videos = 40 };
_mockImmichApi.Setup(api => api.GetAssetStatisticsAsync(null, false, null, It.IsAny<CancellationToken>())).ReturnsAsync(stats);

// Act
Expand All @@ -67,29 +83,81 @@ public async Task GetAssetCount_CallsApiAndCache()
}

[Test]
public async Task GetAssets_CallsSearchRandomAsync_WithCorrectParameters()
public async Task GetAssetCount_CallsApiAndCache_WithVideos()
{
// Arrange
var requestedCount = 5;
var stats = new AssetStatsResponseDto { Images = 100, Videos = 40 };
_mockImmichApi.Setup(api => api.GetAssetStatisticsAsync(null, false, null, It.IsAny<CancellationToken>())).ReturnsAsync(stats);

_mockAccountSettings.SetupGet(s => s.ShowVideos).Returns(true);

// Act
var count = await _allAssetsPool.GetAssetCount();

// Assert
Assert.That(count, Is.EqualTo(140));
_mockImmichApi.Verify(api => api.GetAssetStatisticsAsync(null, false, null, It.IsAny<CancellationToken>()), Times.Once);
_mockApiCache.Verify(cache => cache.GetOrAddAsync(nameof(AllAssetsPool), It.IsAny<Func<Task<AssetStatsResponseDto>>>()), Times.Once);
}

[Test]
public async Task GetAssets_CallsSearchRandomAsync_WithCorrectParameters_OnlyImages()
{
// Arrange
var requestedImageCount = 5;
var requestedVideoCount = 8;
var rating = 3;
_mockAccountSettings.SetupGet(s => s.ShowArchived).Returns(true);
_mockAccountSettings.SetupGet(s => s.Rating).Returns(3);
var returnedAssets = CreateSampleAssets(requestedCount);
var returnedAssets = CreateSampleImageAssets(requestedImageCount, rating: rating);
returnedAssets.AddRange(CreateSampleVideoAssets(requestedVideoCount, rating: rating));
_mockImmichApi.Setup(api => api.SearchRandomAsync(It.IsAny<RandomSearchDto>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(returnedAssets);
.ReturnsAsync(returnedAssets.Where(a => a.Type == AssetTypeEnum.IMAGE).ToList());

// Act
var assets = await _allAssetsPool.GetAssets(requestedCount);
var assets = await _allAssetsPool.GetAssets(requestedImageCount);

// Assert
Assert.That(assets.Count(), Is.EqualTo(requestedCount));
Assert.That(assets.Count(), Is.EqualTo(requestedImageCount));
_mockImmichApi.Verify(api => api.SearchRandomAsync(
It.Is<RandomSearchDto>(dto =>
dto.Size == requestedCount &&
dto.Size == requestedImageCount &&
dto.Type == AssetTypeEnum.IMAGE &&
dto.WithExif == true &&
dto.WithPeople == true &&
dto.Visibility == AssetVisibility.Archive && // ShowArchived = true
dto.Rating == 3
dto.Rating == rating
), It.IsAny<CancellationToken>()), Times.Once);
}

[Test]
public async Task GetAssets_CallsSearchRandomAsync_WithCorrectParameters_ImagesAndVideos()
{
// Arrange
var requestedImageCount = 5;
var requestedVideoCount = 8;
var rating = 3;
_mockAccountSettings.SetupGet(s => s.ShowArchived).Returns(true);
_mockAccountSettings.SetupGet(s => s.ShowVideos).Returns(true);
_mockAccountSettings.SetupGet(s => s.Rating).Returns(3);
var returnedAssets = CreateSampleImageAssets(requestedImageCount, rating: rating);
returnedAssets.AddRange(CreateSampleVideoAssets(requestedVideoCount, rating: rating));
_mockImmichApi.Setup(api => api.SearchRandomAsync(It.IsAny<RandomSearchDto>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(returnedAssets.ToList());

// Act
var assets = await _allAssetsPool.GetAssets(requestedImageCount + requestedVideoCount);

// Assert
Assert.That(assets.Count(), Is.EqualTo(requestedImageCount + requestedVideoCount));
_mockImmichApi.Verify(api => api.SearchRandomAsync(
It.Is<RandomSearchDto>(dto =>
dto.Size == (requestedImageCount + requestedVideoCount) &&
dto.Type == null &&
dto.WithExif == true &&
dto.WithPeople == true &&
dto.Visibility == AssetVisibility.Archive && // ShowArchived = true
dto.Rating == rating
), It.IsAny<CancellationToken>()), Times.Once);
}

Expand All @@ -98,8 +166,8 @@ public async Task GetAssets_AppliesDateFilters_FromDays()
{
_mockAccountSettings.SetupGet(s => s.ImagesFromDays).Returns(10);
var expectedFromDate = DateTime.Today.AddDays(-10);
_mockImmichApi.Setup(api => api.SearchRandomAsync(It.IsAny<RandomSearchDto>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(new List<AssetResponseDto>());
_mockImmichApi.Setup(api => api.SearchRandomAsync(It.IsAny<RandomSearchDto>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(new List<AssetResponseDto>());

await _allAssetsPool.GetAssets(5);

Expand All @@ -112,7 +180,7 @@ public async Task GetAssets_AppliesDateFilters_FromDays()
public async Task GetAssets_ExcludesAssetsFromExcludedAlbums()
{
// Arrange
var mainAssets = CreateSampleAssets(3, "main"); // main0, main1, main2
var mainAssets = CreateSampleImageAssets(3, "main"); // main0, main1, main2
var excludedAsset = new AssetResponseDto { Id = "excluded1", Type = AssetTypeEnum.IMAGE };
var assetsToReturnFromSearch = new List<AssetResponseDto>(mainAssets) { excludedAsset };

Expand Down
Loading
Loading