276 lines
9.5 KiB
C#
276 lines
9.5 KiB
C#
using BudgetApp.Data.Entities;
|
|
using BudgetApp.Data.Repositories;
|
|
using BudgetApp.Tests.Helpers;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Xunit;
|
|
|
|
namespace BudgetApp.Tests.Services;
|
|
|
|
public class CategoryServiceTests
|
|
{
|
|
[Fact]
|
|
public async Task GetCategoriesAsync_ReturnsOnlyUserCategories()
|
|
{
|
|
using var factory = new TestDbContextFactory();
|
|
using (var ctx = factory.CreateContext())
|
|
{
|
|
ctx.Categories.AddRange(
|
|
new Category { Name = "Mine", UserId = TestDbContextFactory.TestUserId },
|
|
new Category { Name = "Theirs", UserId = TestDbContextFactory.OtherUserId });
|
|
await ctx.SaveChangesAsync();
|
|
}
|
|
|
|
using var context = factory.CreateContext();
|
|
var service = new CategoryRepository(context);
|
|
|
|
var result = await service.GetCategoriesAsync(TestDbContextFactory.TestUserId);
|
|
|
|
Assert.Single(result);
|
|
Assert.Equal("Mine", result[0].Name);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetCategoriesAsync_OrderedByName()
|
|
{
|
|
using var factory = new TestDbContextFactory();
|
|
using (var ctx = factory.CreateContext())
|
|
{
|
|
ctx.Categories.AddRange(
|
|
new Category { Name = "Zebra", UserId = TestDbContextFactory.TestUserId },
|
|
new Category { Name = "Alpha", UserId = TestDbContextFactory.TestUserId });
|
|
await ctx.SaveChangesAsync();
|
|
}
|
|
|
|
using var context = factory.CreateContext();
|
|
var service = new CategoryRepository(context);
|
|
|
|
var result = await service.GetCategoriesAsync(TestDbContextFactory.TestUserId);
|
|
|
|
Assert.Equal("Alpha", result[0].Name);
|
|
Assert.Equal("Zebra", result[1].Name);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task EnsureDefaultCategoriesAsync_CreatesDefaults_WhenEmpty()
|
|
{
|
|
using var factory = new TestDbContextFactory();
|
|
using var context = factory.CreateContext();
|
|
var service = new CategoryRepository(context);
|
|
|
|
await service.EnsureDefaultCategoriesAsync(TestDbContextFactory.TestUserId);
|
|
|
|
using var verifyCtx = factory.CreateContext();
|
|
var categories = await verifyCtx.Categories
|
|
.Where(c => c.UserId == TestDbContextFactory.TestUserId)
|
|
.ToListAsync();
|
|
|
|
Assert.Equal(18, categories.Count);
|
|
Assert.Contains(categories, c => c.Name == "Groceries" && c.Icon == "🛒");
|
|
Assert.Contains(categories, c => c.Name == "Transport" && c.Icon == "🚗");
|
|
Assert.Contains(categories, c => c.Name == "Salary" && c.Icon == "💰");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task EnsureDefaultCategoriesAsync_DoesNotDuplicate_WhenCalledAgain()
|
|
{
|
|
using var factory = new TestDbContextFactory();
|
|
|
|
using (var ctx = factory.CreateContext())
|
|
{
|
|
var service = new CategoryRepository(ctx);
|
|
await service.EnsureDefaultCategoriesAsync(TestDbContextFactory.TestUserId);
|
|
}
|
|
|
|
using (var ctx = factory.CreateContext())
|
|
{
|
|
var service = new CategoryRepository(ctx);
|
|
await service.EnsureDefaultCategoriesAsync(TestDbContextFactory.TestUserId);
|
|
}
|
|
|
|
using var verifyCtx = factory.CreateContext();
|
|
var count = await verifyCtx.Categories
|
|
.Where(c => c.UserId == TestDbContextFactory.TestUserId)
|
|
.CountAsync();
|
|
|
|
Assert.Equal(18, count);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task EnsureDefaultCategoriesAsync_BackfillsIcons_WhenMissing()
|
|
{
|
|
using var factory = new TestDbContextFactory();
|
|
using (var ctx = factory.CreateContext())
|
|
{
|
|
ctx.Categories.Add(new Category
|
|
{
|
|
Name = "Groceries",
|
|
Icon = "",
|
|
UserId = TestDbContextFactory.TestUserId
|
|
});
|
|
await ctx.SaveChangesAsync();
|
|
}
|
|
|
|
using var context = factory.CreateContext();
|
|
var service = new CategoryRepository(context);
|
|
await service.EnsureDefaultCategoriesAsync(TestDbContextFactory.TestUserId);
|
|
|
|
using var verifyCtx = factory.CreateContext();
|
|
var category = await verifyCtx.Categories
|
|
.SingleAsync(c => c.Name == "Groceries" && c.UserId == TestDbContextFactory.TestUserId);
|
|
|
|
Assert.Equal("🛒", category.Icon);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task EnsureDefaultCategoriesAsync_DoesNotOverwrite_ExistingIcons()
|
|
{
|
|
using var factory = new TestDbContextFactory();
|
|
using (var ctx = factory.CreateContext())
|
|
{
|
|
ctx.Categories.Add(new Category
|
|
{
|
|
Name = "Groceries",
|
|
Icon = "🥕",
|
|
UserId = TestDbContextFactory.TestUserId
|
|
});
|
|
await ctx.SaveChangesAsync();
|
|
}
|
|
|
|
using var context = factory.CreateContext();
|
|
var service = new CategoryRepository(context);
|
|
await service.EnsureDefaultCategoriesAsync(TestDbContextFactory.TestUserId);
|
|
|
|
using var verifyCtx = factory.CreateContext();
|
|
var category = await verifyCtx.Categories
|
|
.SingleAsync(c => c.Name == "Groceries" && c.UserId == TestDbContextFactory.TestUserId);
|
|
|
|
Assert.Equal("🥕", category.Icon);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task EnsureDefaultCategoriesAsync_IsolatedPerUser()
|
|
{
|
|
using var factory = new TestDbContextFactory();
|
|
|
|
using (var ctx = factory.CreateContext())
|
|
{
|
|
var service = new CategoryRepository(ctx);
|
|
await service.EnsureDefaultCategoriesAsync(TestDbContextFactory.TestUserId);
|
|
}
|
|
|
|
using (var ctx = factory.CreateContext())
|
|
{
|
|
var service = new CategoryRepository(ctx);
|
|
await service.EnsureDefaultCategoriesAsync(TestDbContextFactory.OtherUserId);
|
|
}
|
|
|
|
using var verifyCtx = factory.CreateContext();
|
|
var totalCount = await verifyCtx.Categories.CountAsync();
|
|
Assert.Equal(36, totalCount);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CreateCategoryAsync_AddsToDatabase()
|
|
{
|
|
using var factory = new TestDbContextFactory();
|
|
using var context = factory.CreateContext();
|
|
var service = new CategoryRepository(context);
|
|
|
|
await service.CreateCategoryAsync(new Category
|
|
{
|
|
Name = "Custom",
|
|
Icon = "🎯",
|
|
UserId = TestDbContextFactory.TestUserId
|
|
});
|
|
|
|
using var verifyCtx = factory.CreateContext();
|
|
Assert.Single(verifyCtx.Categories);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task UpdateCategoryAsync_UpdatesNameAndIcon()
|
|
{
|
|
using var factory = new TestDbContextFactory();
|
|
int categoryId;
|
|
using (var ctx = factory.CreateContext())
|
|
{
|
|
var category = new Category { Name = "Old", Icon = "📁", UserId = TestDbContextFactory.TestUserId };
|
|
ctx.Categories.Add(category);
|
|
await ctx.SaveChangesAsync();
|
|
categoryId = category.Id;
|
|
}
|
|
|
|
using var context = factory.CreateContext();
|
|
var service = new CategoryRepository(context);
|
|
await service.UpdateCategoryAsync(categoryId, TestDbContextFactory.TestUserId, "New", "🎯");
|
|
|
|
using var verifyCtx = factory.CreateContext();
|
|
var updated = verifyCtx.Categories.Single();
|
|
Assert.Equal("New", updated.Name);
|
|
Assert.Equal("🎯", updated.Icon);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task UpdateCategoryAsync_WrongUser_DoesNothing()
|
|
{
|
|
using var factory = new TestDbContextFactory();
|
|
int categoryId;
|
|
using (var ctx = factory.CreateContext())
|
|
{
|
|
var category = new Category { Name = "Original", Icon = "📁", UserId = TestDbContextFactory.TestUserId };
|
|
ctx.Categories.Add(category);
|
|
await ctx.SaveChangesAsync();
|
|
categoryId = category.Id;
|
|
}
|
|
|
|
using var context = factory.CreateContext();
|
|
var service = new CategoryRepository(context);
|
|
await service.UpdateCategoryAsync(categoryId, TestDbContextFactory.OtherUserId, "Hacked", "💀");
|
|
|
|
using var verifyCtx = factory.CreateContext();
|
|
Assert.Equal("Original", verifyCtx.Categories.Single().Name);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task DeleteCategoryAsync_RemovesCategory()
|
|
{
|
|
using var factory = new TestDbContextFactory();
|
|
int categoryId;
|
|
using (var ctx = factory.CreateContext())
|
|
{
|
|
var category = new Category { Name = "ToDelete", UserId = TestDbContextFactory.TestUserId };
|
|
ctx.Categories.Add(category);
|
|
await ctx.SaveChangesAsync();
|
|
categoryId = category.Id;
|
|
}
|
|
|
|
using var context = factory.CreateContext();
|
|
var service = new CategoryRepository(context);
|
|
await service.DeleteCategoryAsync(categoryId, TestDbContextFactory.TestUserId);
|
|
|
|
using var verifyCtx = factory.CreateContext();
|
|
Assert.Empty(verifyCtx.Categories);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task DeleteCategoryAsync_WrongUser_DoesNothing()
|
|
{
|
|
using var factory = new TestDbContextFactory();
|
|
int categoryId;
|
|
using (var ctx = factory.CreateContext())
|
|
{
|
|
var category = new Category { Name = "Protected", UserId = TestDbContextFactory.TestUserId };
|
|
ctx.Categories.Add(category);
|
|
await ctx.SaveChangesAsync();
|
|
categoryId = category.Id;
|
|
}
|
|
|
|
using var context = factory.CreateContext();
|
|
var service = new CategoryRepository(context);
|
|
await service.DeleteCategoryAsync(categoryId, TestDbContextFactory.OtherUserId);
|
|
|
|
using var verifyCtx = factory.CreateContext();
|
|
Assert.Single(verifyCtx.Categories);
|
|
}
|
|
}
|