sync full source from private myoffice
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
using MyOffice.Data.Models.Accounts;
|
||||
using MyOffice.Services.Account;
|
||||
using AccountEntity = MyOffice.Data.Models.Accounts.Account;
|
||||
|
||||
namespace MyOffice.Tests.Accounts;
|
||||
|
||||
public class AccountAclTests
|
||||
{
|
||||
private static AccountEntity CreateAccount(Guid userId, bool write, bool manage)
|
||||
{
|
||||
return new AccountEntity
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Name = "Cash",
|
||||
AccessRights =
|
||||
[
|
||||
new AccountAccess
|
||||
{
|
||||
UserId = userId,
|
||||
IsAllowRead = true,
|
||||
IsAllowWrite = write,
|
||||
IsAllowManage = manage,
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanWrite_true_when_flag_set()
|
||||
{
|
||||
var userId = Guid.NewGuid();
|
||||
var account = CreateAccount(userId, write: true, manage: false);
|
||||
|
||||
Assert.True(AccountAcl.CanWrite(account, userId));
|
||||
Assert.False(AccountAcl.CanManage(account, userId));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanManage_true_when_flag_set()
|
||||
{
|
||||
var userId = Guid.NewGuid();
|
||||
var account = CreateAccount(userId, write: false, manage: true);
|
||||
|
||||
Assert.False(AccountAcl.CanWrite(account, userId));
|
||||
Assert.True(AccountAcl.CanManage(account, userId));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanWrite_false_for_other_user()
|
||||
{
|
||||
var account = CreateAccount(Guid.NewGuid(), write: true, manage: true);
|
||||
|
||||
Assert.False(AccountAcl.CanWrite(account, Guid.NewGuid()));
|
||||
Assert.False(AccountAcl.CanManage(account, Guid.NewGuid()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanWrite_false_when_access_rights_null()
|
||||
{
|
||||
var account = new AccountEntity { Id = Guid.NewGuid(), Name = "X", AccessRights = null };
|
||||
|
||||
Assert.False(AccountAcl.CanWrite(account, Guid.NewGuid()));
|
||||
Assert.False(AccountAcl.CanManage(account, Guid.NewGuid()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using MyOffice.Services.Account;
|
||||
|
||||
namespace MyOffice.Tests.Accounts;
|
||||
|
||||
public class AccountMotionBalancingTests
|
||||
{
|
||||
[Fact]
|
||||
public void ResolveAmounts_income_primary_creates_expense_on_balancing()
|
||||
{
|
||||
var (plus, minus) = AccountMotionBalancing.ResolveAmounts(primaryPlus: 100m, amountBalancing: 100m);
|
||||
|
||||
Assert.Equal(0m, plus);
|
||||
Assert.Equal(100m, minus);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResolveAmounts_expense_primary_creates_income_on_balancing()
|
||||
{
|
||||
var (plus, minus) = AccountMotionBalancing.ResolveAmounts(primaryPlus: 0m, amountBalancing: 50m);
|
||||
|
||||
Assert.Equal(50m, plus);
|
||||
Assert.Equal(0m, minus);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BalancingItemName_prefixes_account_name()
|
||||
{
|
||||
Assert.Equal("+Wallet", AccountMotionBalancing.BalancingItemName("Wallet"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
using AutoMapper;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Moq;
|
||||
using MyOffice.Data.Models.Accounts;
|
||||
using MyOffice.Data.Models.Items;
|
||||
using MyOffice.Data.Repositories.Account;
|
||||
using MyOffice.Data.Repositories.Currency;
|
||||
using MyOffice.Data.Repositories.Item;
|
||||
using MyOffice.Services.Account;
|
||||
using MyOffice.Services.Account.Domain;
|
||||
using MyOffice.Services.Identity;
|
||||
using MyOffice.Services.Item;
|
||||
|
||||
using AccountEntity = MyOffice.Data.Models.Accounts.Account;
|
||||
|
||||
namespace MyOffice.Tests.Accounts;
|
||||
|
||||
public class MotionAddAclTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task MotionAddAsync_returns_forbidden_without_write_access()
|
||||
{
|
||||
var userId = Guid.NewGuid();
|
||||
var accountId = Guid.NewGuid();
|
||||
var account = new AccountEntity
|
||||
{
|
||||
Id = accountId,
|
||||
Name = "Cash",
|
||||
AccessRights =
|
||||
[
|
||||
new AccountAccess
|
||||
{
|
||||
UserId = userId,
|
||||
IsAllowRead = true,
|
||||
IsAllowWrite = false,
|
||||
IsAllowManage = false,
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var accountRepo = new Mock<IAccountRepository>();
|
||||
accountRepo
|
||||
.Setup(x => x.GetAsync(userId, accountId, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(account);
|
||||
|
||||
var service = CreateService(accountRepo.Object);
|
||||
|
||||
var exec = await service.MotionAddAsync(
|
||||
userId,
|
||||
accountId,
|
||||
new MotionAddUpdate
|
||||
{
|
||||
Date = DateTime.UtcNow,
|
||||
Item = "Coffee",
|
||||
Plus = 0,
|
||||
Minus = 10,
|
||||
});
|
||||
|
||||
Assert.Equal(MotionAddStatus.forbidden, exec.Status);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MotionAddAsync_skips_balancing_when_counterparty_not_writable()
|
||||
{
|
||||
var userId = Guid.NewGuid();
|
||||
var primaryId = Guid.NewGuid();
|
||||
var balancingId = Guid.NewGuid();
|
||||
|
||||
var primary = new AccountEntity
|
||||
{
|
||||
Id = primaryId,
|
||||
Name = "Cash",
|
||||
AccessRights =
|
||||
[
|
||||
new AccountAccess { UserId = userId, IsAllowRead = true, IsAllowWrite = true }
|
||||
]
|
||||
};
|
||||
var balancing = new AccountEntity
|
||||
{
|
||||
Id = balancingId,
|
||||
Name = "Bank",
|
||||
AccessRights =
|
||||
[
|
||||
new AccountAccess { UserId = userId, IsAllowRead = true, IsAllowWrite = false }
|
||||
]
|
||||
};
|
||||
|
||||
var accountRepo = new Mock<IAccountRepository>();
|
||||
accountRepo
|
||||
.Setup(x => x.GetAsync(userId, primaryId, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(primary);
|
||||
accountRepo
|
||||
.Setup(x => x.GetAsync(userId, balancingId, It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(balancing);
|
||||
|
||||
var motionRepo = new Mock<IMotionRepository>();
|
||||
motionRepo
|
||||
.Setup(x => x.AddAsync(It.IsAny<Motion>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(true);
|
||||
|
||||
var service = CreateService(accountRepo.Object, motionRepo.Object);
|
||||
|
||||
var exec = await service.MotionAddAsync(
|
||||
userId,
|
||||
primaryId,
|
||||
new MotionAddUpdate
|
||||
{
|
||||
Date = DateTime.UtcNow,
|
||||
Item = "Transfer",
|
||||
Plus = 0,
|
||||
Minus = 25,
|
||||
AccountId = balancingId.ToString("N"),
|
||||
AmountBalancing = 25,
|
||||
});
|
||||
|
||||
Assert.Equal(MotionAddStatus.success, exec.Status);
|
||||
Assert.NotNull(exec.Result);
|
||||
Assert.Single(exec.Result!);
|
||||
motionRepo.Verify(x => x.AddAsync(It.IsAny<Motion>(), It.IsAny<CancellationToken>()), Times.Once);
|
||||
}
|
||||
|
||||
private static ItemService CreateItemServiceStub()
|
||||
{
|
||||
var nextId = 1;
|
||||
var itemRepo = new Mock<IItemRepository>();
|
||||
var itemGlobalRepo = new Mock<IItemGlobalRepository>();
|
||||
|
||||
itemGlobalRepo
|
||||
.Setup(x => x.GetByNameAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync((ItemGlobal?)null);
|
||||
itemGlobalRepo
|
||||
.Setup(x => x.AddAsync(It.IsAny<ItemGlobal>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(true);
|
||||
itemRepo
|
||||
.Setup(x => x.GetByGlobalAsync(It.IsAny<Guid>(), It.IsAny<Guid>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync((Item?)null);
|
||||
itemRepo
|
||||
.Setup(x => x.AddAsync(It.IsAny<Item>(), It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(true)
|
||||
.Callback<Item, CancellationToken>((i, _) => i.Id = nextId++);
|
||||
|
||||
return new ItemService(
|
||||
Mock.Of<IItemCategoryRepository>(),
|
||||
itemRepo.Object,
|
||||
itemGlobalRepo.Object,
|
||||
new MapperConfiguration(_ => { }, NullLoggerFactory.Instance).CreateMapper());
|
||||
}
|
||||
|
||||
private static AccountService CreateService(
|
||||
IAccountRepository accountRepository,
|
||||
IMotionRepository? motionRepository = null)
|
||||
{
|
||||
var mapper = new MapperConfiguration(
|
||||
cfg => cfg.AddProfile<MotionDtoProfile>(),
|
||||
NullLoggerFactory.Instance).CreateMapper();
|
||||
|
||||
return new AccountService(
|
||||
Mock.Of<ILogger<AccountService>>(),
|
||||
mapper,
|
||||
Mock.Of<IAccountCategoryRepository>(),
|
||||
Mock.Of<IAccountAccessRepository>(),
|
||||
Mock.Of<IAccountAccessInviteRepository>(),
|
||||
accountRepository,
|
||||
Mock.Of<ICurrencyRepository>(),
|
||||
Mock.Of<IAccountAccountCategoryRepository>(),
|
||||
motionRepository ?? Mock.Of<IMotionRepository>(),
|
||||
Mock.Of<IItemRepository>(),
|
||||
Mock.Of<IItemGlobalRepository>(),
|
||||
CreateItemServiceStub(),
|
||||
Mock.Of<IContextProvider>());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user