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(); settingsService.GetDbPath().Returns(dbDir); settingsService.GetLastYearDbPath().Returns(Path.Combine(dbDir, "no-such-dir")); sut = new AccountRepository(settingsService, new RepositoryCache(), NullLogger.Instance); } public void Dispose() { if (Directory.Exists(dbDir)) { Directory.Delete(dbDir, recursive: true); } } [Fact] public async Task AssignNewIdWhenSavingAccountWithoutId() { var account = new Account { Number = 1000, Name = "Cash", Currency = "CHF" }; await sut.SaveAccountAsync(account); var stored = (await sut.GetAccountListAsync()).Single(); stored.Id.ShouldNotBeNullOrEmpty(); stored.Name.ShouldBe("Cash"); } [Fact] public async Task UpdateInPlaceWhenSavingAccountWithExistingId() { await sut.SaveAccountAsync(new Account { Number = 1000, Name = "Cash", Currency = "CHF" }); var id = (await sut.GetAccountListAsync()).Single().Id; await sut.SaveAccountAsync(new Account { Id = id, Number = 1000, Name = "Cash renamed", Currency = "CHF" }); var accounts = await sut.GetAccountListAsync(); accounts.Count.ShouldBe(1); accounts[0].Name.ShouldBe("Cash renamed"); } [Fact] public async Task DefaultCurrencyToChfWhenSavingAccountWithoutCurrency() { await sut.SaveAccountAsync(new Account { Number = 1000, Name = "Cash", Currency = null! }); (await sut.GetAccountListAsync()).Single().Currency.ShouldBe("CHF"); } [Fact] public async Task RemoveAccountWhenDeletingById() { await sut.SaveAccountAsync(new Account { Number = 1000, Name = "Cash", Currency = "CHF" }); var id = (await sut.GetAccountListAsync()).Single().Id; await sut.DeleteAccountAsync(id); (await sut.GetAccountListAsync()).ShouldBeEmpty(); } [Fact] public async Task ReturnAccountWhenLookingUpByBankAccountNumber() { await sut.SaveAccountAsync(new Account { Number = 1010, Name = "Checking", Currency = "CHF", BankAccountNumber = "CH01" }); await sut.SaveAccountAsync(new Account { Number = 1020, Name = "Savings", Currency = "CHF", BankAccountNumber = "CH02" }); (await sut.GetAccountForBankAccountNumberAsync("CH01")).Name.ShouldBe("Checking"); (await sut.GetAccountForBankAccountNumberAsync("CH02")).Name.ShouldBe("Savings"); (await sut.GetAccountForBankAccountNumberAsync("CH99")).ShouldBeNull(); } [Fact] public async Task UpdateLastBankBalanceWhenSavingBankBalance() { await sut.SaveAccountAsync(new Account { Number = 1010, Name = "Checking", Currency = "CHF", BankAccountNumber = "CH01" }); await sut.SaveBankAccountBalanceAsync("CH01", 1234.56m); (await sut.GetAccountForBankAccountNumberAsync("CH01")).LastBankBalance.ShouldBe(1234.56m); } [Fact] public async Task SurviveConstructorReRunWhenAccountsFileAlreadyExists() { await sut.SaveAccountAsync(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.Instance); var accounts = await fresh.GetAccountListAsync(); accounts.Count.ShouldBe(1); accounts[0].Name.ShouldBe("Cash"); } }