AccountingNext/Schaad.Accounting.Tests/AccountRepositoryTestShould.cs
Claudio Schaad 3a770af016 PR J: log repository save failures via ILogger
BaseRepository takes an ILogger via its constructor and logs the
failing file path and exception in Save's catch block before
rethrowing. Every concrete repository takes ILogger<ThisRepo> and
passes it up so failures are categorised by repository type.

Pulls Microsoft.Extensions.Logging.Abstractions into the Db project.
TransactionRepositoryTestShould and AccountRepositoryTestShould pass
NullLogger<T>.Instance.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-02 21:47:55 +02:00

113 lines
3.8 KiB
C#

using Microsoft.Extensions.Logging.Abstractions;
using NSubstitute;
using Schaad.Accounting.Interfaces;
using Schaad.Accounting.Models;
using Schaad.Accounting.Repositories;
using Shouldly;
namespace Schaad.Accounting.Tests;
public class AccountRepositoryTestShould : IDisposable
{
private readonly string dbDir;
private readonly ISettingsService settingsService;
private readonly AccountRepository sut;
public AccountRepositoryTestShould()
{
dbDir = Path.Combine(Path.GetTempPath(), "AccountingNext-tests-" + Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(dbDir);
settingsService = Substitute.For<ISettingsService>();
settingsService.GetDbPath().Returns(dbDir);
settingsService.GetLastYearDbPath().Returns(Path.Combine(dbDir, "no-such-dir"));
sut = new AccountRepository(settingsService, new RepositoryCache(), NullLogger<AccountRepository>.Instance);
}
public void Dispose()
{
if (Directory.Exists(dbDir))
{
Directory.Delete(dbDir, recursive: true);
}
}
[Fact]
public void AssignNewIdWhenSavingAccountWithoutId()
{
var account = new Account { Number = 1000, Name = "Cash", Currency = "CHF" };
sut.SaveAccount(account);
var stored = sut.GetAccountList().Single();
stored.Id.ShouldNotBeNullOrEmpty();
stored.Name.ShouldBe("Cash");
}
[Fact]
public void UpdateInPlaceWhenSavingAccountWithExistingId()
{
sut.SaveAccount(new Account { Number = 1000, Name = "Cash", Currency = "CHF" });
var id = sut.GetAccountList().Single().Id;
sut.SaveAccount(new Account { Id = id, Number = 1000, Name = "Cash renamed", Currency = "CHF" });
var accounts = sut.GetAccountList();
accounts.Count.ShouldBe(1);
accounts[0].Name.ShouldBe("Cash renamed");
}
[Fact]
public void DefaultCurrencyToChfWhenSavingAccountWithoutCurrency()
{
sut.SaveAccount(new Account { Number = 1000, Name = "Cash", Currency = null! });
sut.GetAccountList().Single().Currency.ShouldBe("CHF");
}
[Fact]
public void RemoveAccountWhenDeletingById()
{
sut.SaveAccount(new Account { Number = 1000, Name = "Cash", Currency = "CHF" });
var id = sut.GetAccountList().Single().Id;
sut.DeleteAccount(id);
sut.GetAccountList().ShouldBeEmpty();
}
[Fact]
public void ReturnAccountWhenLookingUpByBankAccountNumber()
{
sut.SaveAccount(new Account { Number = 1010, Name = "Checking", Currency = "CHF", BankAccountNumber = "CH01" });
sut.SaveAccount(new Account { Number = 1020, Name = "Savings", Currency = "CHF", BankAccountNumber = "CH02" });
sut.GetAccountForBankAccountNumber("CH01").Name.ShouldBe("Checking");
sut.GetAccountForBankAccountNumber("CH02").Name.ShouldBe("Savings");
sut.GetAccountForBankAccountNumber("CH99").ShouldBeNull();
}
[Fact]
public void UpdateLastBankBalanceWhenSavingBankBalance()
{
sut.SaveAccount(new Account { Number = 1010, Name = "Checking", Currency = "CHF", BankAccountNumber = "CH01" });
sut.SaveBankAccountBalance("CH01", 1234.56m);
sut.GetAccountForBankAccountNumber("CH01").LastBankBalance.ShouldBe(1234.56m);
}
[Fact]
public void SurviveConstructorReRunWhenAccountsFileAlreadyExists()
{
sut.SaveAccount(new Account { Number = 1000, Name = "Cash", Currency = "CHF" });
// Re-construct with the same directory: existing file, no year rollover, no data loss.
var fresh = new AccountRepository(settingsService, new RepositoryCache(), NullLogger<AccountRepository>.Instance);
var accounts = fresh.GetAccountList();
accounts.Count.ShouldBe(1);
accounts[0].Name.ShouldBe("Cash");
}
}