Add dedicated Wino.Mail.ViewModels.Tests coverage for WinoMailCollection (#812)

* Add WinoMailCollection tests in dedicated ViewModels test project

* Fix WinoMailCollection tests flattening without SelectMany
This commit is contained in:
Burak Kaan Köse
2026-02-17 15:45:29 +01:00
committed by GitHub
parent 05112d6a35
commit f49d276f5a
4 changed files with 190 additions and 0 deletions
@@ -0,0 +1,157 @@
using FluentAssertions;
using Wino.Core.Domain.Entities.Mail;
using Wino.Core.Domain.Interfaces;
using Wino.Mail.ViewModels.Collections;
using Wino.Mail.ViewModels.Data;
using Xunit;
namespace Wino.Mail.ViewModels.Tests.Collections;
public class WinoMailCollectionTests
{
[Fact]
public async Task AddAsync_ShouldAddSingleItemAsMailItemViewModel()
{
var sut = CreateCollection();
var mail = CreateMailCopy(threadId: "thread-1");
await sut.AddAsync(mail);
var items = FlattenItems(sut);
items.Should().ContainSingle().Which.Should().BeOfType<MailItemViewModel>();
sut.ContainsMailUniqueId(mail.UniqueId).Should().BeTrue();
}
[Fact]
public async Task AddAsync_ShouldKeepItemsSeparate_WhenThreadIdsDiffer()
{
var sut = CreateCollection();
var first = CreateMailCopy(threadId: "thread-1");
var second = CreateMailCopy(threadId: "thread-2");
await sut.AddAsync(first);
await sut.AddAsync(second);
var items = FlattenItems(sut);
items.Should().HaveCount(2);
items.Should().OnlyContain(item => item is MailItemViewModel);
}
[Fact]
public async Task AddAsync_ShouldConvertSingleItemToThread_WhenSecondItemWithSameThreadIdIsAdded()
{
var sut = CreateCollection();
var first = CreateMailCopy(threadId: "shared-thread", creationDate: DateTime.UtcNow.AddMinutes(-1));
var second = CreateMailCopy(threadId: "shared-thread", creationDate: DateTime.UtcNow);
await sut.AddAsync(first);
FlattenItems(sut).Should().ContainSingle().Which.Should().BeOfType<MailItemViewModel>();
await sut.AddAsync(second);
var items = FlattenItems(sut);
var threadItem = items.Should().ContainSingle().Which.Should().BeOfType<ThreadMailItemViewModel>().Subject;
threadItem.EmailCount.Should().Be(2);
threadItem.GetContainingIds().Should().BeEquivalentTo([first.UniqueId, second.UniqueId]);
}
[Fact]
public async Task RemoveAsync_ShouldConvertThreadToSingleItem_WhenThreadDropsToOneItem()
{
var sut = CreateCollection();
var first = CreateMailCopy(threadId: "shared-thread", creationDate: DateTime.UtcNow.AddMinutes(-1));
var second = CreateMailCopy(threadId: "shared-thread", creationDate: DateTime.UtcNow);
await sut.AddAsync(first);
await sut.AddAsync(second);
await sut.RemoveAsync(second);
var items = FlattenItems(sut);
var remainingItem = items.Should().ContainSingle().Which.Should().BeOfType<MailItemViewModel>().Subject;
remainingItem.MailCopy.UniqueId.Should().Be(first.UniqueId);
var container = sut.GetMailItemContainer(first.UniqueId);
container.Should().NotBeNull();
container.ThreadViewModel.Should().BeNull();
}
[Fact]
public async Task RemoveAsync_ShouldRemoveSingleItem()
{
var sut = CreateCollection();
var mail = CreateMailCopy(threadId: "thread-1");
await sut.AddAsync(mail);
await sut.RemoveAsync(mail);
FlattenItems(sut).Should().BeEmpty();
sut.ContainsMailUniqueId(mail.UniqueId).Should().BeFalse();
}
[Fact]
public async Task AddRangeAsync_ShouldCreateThreadsForItemsWithMatchingThreadId()
{
var sut = CreateCollection();
var threadAFirst = new MailItemViewModel(CreateMailCopy(threadId: "thread-a", creationDate: DateTime.UtcNow.AddMinutes(-10)));
var threadASecond = new MailItemViewModel(CreateMailCopy(threadId: "thread-a", creationDate: DateTime.UtcNow.AddMinutes(-9)));
var threadCFirst = new MailItemViewModel(CreateMailCopy(threadId: "thread-c", creationDate: DateTime.UtcNow.AddMinutes(-8)));
var threadCSecond = new MailItemViewModel(CreateMailCopy(threadId: "thread-c", creationDate: DateTime.UtcNow.AddMinutes(-7)));
var single = new MailItemViewModel(CreateMailCopy(threadId: "thread-b", creationDate: DateTime.UtcNow.AddMinutes(-6)));
await sut.AddRangeAsync([threadAFirst, threadASecond, threadCFirst, threadCSecond, single], clearIdCache: true);
var items = FlattenItems(sut);
items.Should().HaveCount(3);
items.Count(item => item is ThreadMailItemViewModel).Should().Be(2);
items.Count(item => item is MailItemViewModel).Should().Be(1);
var threadItems = items.OfType<ThreadMailItemViewModel>().ToList();
threadItems.Should().Contain(item => item.ThreadId == "thread-a" && item.EmailCount == 2);
threadItems.Should().Contain(item => item.ThreadId == "thread-c" && item.EmailCount == 2);
}
private static WinoMailCollection CreateCollection() => new()
{
CoreDispatcher = new ImmediateDispatcher()
};
private static List<IMailListItem> FlattenItems(WinoMailCollection collection)
{
var items = new List<IMailListItem>();
foreach (var group in collection.MailItems)
{
foreach (var item in group)
{
items.Add(item);
}
}
return items;
}
private static MailCopy CreateMailCopy(string threadId, DateTime? creationDate = null)
=> new()
{
UniqueId = Guid.NewGuid(),
ThreadId = threadId,
CreationDate = creationDate ?? DateTime.UtcNow,
FromName = "Sender",
FromAddress = "sender@wino.dev",
Subject = "Subject",
PreviewText = "Preview",
FileId = Guid.NewGuid(),
FolderId = Guid.NewGuid()
};
private sealed class ImmediateDispatcher : IDispatcher
{
public Task ExecuteOnUIThread(Action action)
{
action();
return Task.CompletedTask;
}
}
}
@@ -0,0 +1,4 @@
global using System;
global using System.Collections.Generic;
global using System.Linq;
global using System.Threading.Tasks;
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<Platforms>x86;x64;arm64</Platforms>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="FluentAssertions" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Wino.Mail.ViewModels\Wino.Mail.ViewModels.csproj" />
</ItemGroup>
</Project>
+5
View File
@@ -61,6 +61,11 @@
<Platform Solution="*|x64" Project="x64" />
<Platform Solution="*|x86" Project="x86" />
</Project>
<Project Path="Wino.Mail.ViewModels.Tests/Wino.Mail.ViewModels.Tests.csproj">
<Platform Solution="*|arm64" Project="arm64" />
<Platform Solution="*|x64" Project="x64" />
<Platform Solution="*|x86" Project="x86" />
</Project>
<Project Path="Wino.Mail.WinUI/Wino.Mail.WinUI.csproj" Id="bf340564-2cc8-486d-924d-8474cb5f3316">
<Platform Solution="*|arm64" Project="ARM64" />
<Platform Solution="*|x64" Project="x64" />