From 672fc958233247bf44732ea1213a423f96fe0b13 Mon Sep 17 00:00:00 2001 From: Artemy <109195690+stalcker2288969@users.noreply.github.com> Date: Tue, 24 Jun 2025 15:14:45 +0700 Subject: [PATCH] Admins Repository + tests --- .../EF/Repositories/AdminsRepositoryTests.cs | 131 +++++++++++++++++- .../Validators/AdminValidator.cs | 34 +++++ Govor.Data/Repositories/AdminsRepository.cs | 83 +++++++++-- Govor.Data/Repositories/UsersRepository.cs | 7 +- 4 files changed, 239 insertions(+), 16 deletions(-) create mode 100644 Govor.Core/Infrastructure/Validators/AdminValidator.cs diff --git a/Govor.API.Tests/IntegrationTests/EF/Repositories/AdminsRepositoryTests.cs b/Govor.API.Tests/IntegrationTests/EF/Repositories/AdminsRepositoryTests.cs index ee367da..ddb9337 100644 --- a/Govor.API.Tests/IntegrationTests/EF/Repositories/AdminsRepositoryTests.cs +++ b/Govor.API.Tests/IntegrationTests/EF/Repositories/AdminsRepositoryTests.cs @@ -1,7 +1,9 @@ using AutoFixture; +using Govor.Core.Infrastructure.Validators; using Govor.Core.Models; using Govor.Data; using Govor.Data.Repositories; +using Govor.Data.Repositories.Exceptions; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -12,6 +14,8 @@ public class AdminsRepositoryTests { private Fixture _fixture; private DbContextOptions _options; + private IObjectValidator _validator = new AdminValidator(); + private int _testIteration = 0; [SetUp] @@ -19,9 +23,17 @@ public class AdminsRepositoryTests { _fixture = new Fixture(); + _fixture.Behaviors + .OfType() + .ToList() + .ForEach(b => _fixture.Behaviors.Remove(b)); + + _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); + _options = new DbContextOptionsBuilder() .UseInMemoryDatabase(databaseName: $"DbGovor_{nameof(AdminsRepositoryTests)}_{_testIteration}") .Options; + _testIteration += 1; } [Test] @@ -32,7 +44,7 @@ public class AdminsRepositoryTests var admins = _fixture.CreateMany(random.Next(3, 10)).ToList(); await using var context = new GovorDbContext(_options); - var repository = new AdminsRepository(context); + var repository = new AdminsRepository(context, _validator); context.AddRange(admins); await context.SaveChangesAsync(); @@ -45,4 +57,119 @@ public class AdminsRepositoryTests Assert.That(result.Count(), Is.EqualTo(admins.Count())); Assert.That(result.Select(r => r.UserId), Is.EquivalentTo(admins.Select(r => r.UserId))); } -} \ No newline at end of file + + [Test] + public async Task Given_EmptyDbSet_When_GetAllAsync_Should_Throw_NotFoundException() + { + // Arrange + await using var context = new GovorDbContext(_options); + var repository = new AdminsRepository(context, _validator); + + // Act & Assert + Assert.ThrowsAsync(async () => await repository.GetAllAsync()); + } + + [Test] + public async Task Given_ValidUserId_When_GetByIdAsync_Then_Admin_Should_Return_Admin() + { + // Arrange + var admin = _fixture.Create(); + await using var context = new GovorDbContext(_options); + var repository = new AdminsRepository(context, _validator); + + context.Add(admin); + await context.SaveChangesAsync(); + + // Act + var result = await repository.GetByIdAsync(admin.UserId); + + // Assert + Assert.That(result, Is.Not.Null); + Assert.That(result.UserId, Is.EqualTo(admin.UserId)); + } + + [Test] + public async Task Given_InvalidUserId_When_GetByIdAsync_Should_Throw_NotFoundByKeyException() + { + await using var context = new GovorDbContext(_options); + var repository = new AdminsRepository(context, _validator); + + // Act & Assert + Assert.ThrowsAsync>(async () => await repository.GetByIdAsync(Guid.Empty)); + } + + [Test] + public async Task Given_ValidAdmin_When_AddAsync_Then_Added() + { + // Arrange + var admin = _fixture.Create(); + + await using var context = new GovorDbContext(_options); + var repository = new AdminsRepository(context, _validator); + + // Act + await repository.AddAsync(admin); + + // Assert + Assert.That(context.Admins.Count, Is.EqualTo(1)); + Assert.That(context.Admins.First(), Is.EqualTo(admin)); + } + + [Test] + public async Task Given_InvalidAdmin_When_AddAsync_Should_Throw_AdditionException() + { + // Arrange + await using var context = new GovorDbContext(_options); + var repository = new AdminsRepository(context, _validator); + + // Act & Assert + Assert.ThrowsAsync(async () => await repository.AddAsync(default)); + } + + [Test] + public void Given_ValidAdmin_When_Exist_Then_Returns_True() + { + // Arrange + var admin = _fixture.Create(); + using var context = new GovorDbContext(_options); + var repository = new AdminsRepository(context, _validator); + + context.Add(admin); + context.SaveChanges(); + // Act + var result = repository.Exist(admin.UserId); + var result2 = repository.Exist(admin); + + // Assert + Assert.That(result, Is.True); + Assert.That(result2, Is.True); + } + + [Test] + public void Given_ExistAdmin_When_Exist_Then_Returns_False() + { + // Arrange + var admin = _fixture.Create(); + using var context = new GovorDbContext(_options); + var repository = new AdminsRepository(context, _validator); + + // Act + var result = repository.Exist(admin.UserId); + var result2 = repository.Exist(admin); + + // Assert + Assert.That(result, Is.False); + Assert.That(result2, Is.False); + } + + [Test] + public void Given_NullAdmin_When_Exist_Should_Throw_InvalidObjectException() + { + // Arrange + using var context = new GovorDbContext(_options); + var repository = new AdminsRepository(context, _validator); + + // Act & Assert + Assert.Throws>(() => repository.Exist(default(Admin))); + } +} diff --git a/Govor.Core/Infrastructure/Validators/AdminValidator.cs b/Govor.Core/Infrastructure/Validators/AdminValidator.cs new file mode 100644 index 0000000..4c5acc5 --- /dev/null +++ b/Govor.Core/Infrastructure/Validators/AdminValidator.cs @@ -0,0 +1,34 @@ +using Govor.Core.Models; + +namespace Govor.Core.Infrastructure.Validators; + +public class AdminValidator : IObjectValidator +{ + public void Validate(Admin admin) + { + try + { + if(admin is null) + throw new ArgumentNullException(nameof(admin)); + if(admin.UserId == Guid.Empty) + throw new ArgumentException("User ID cannot be empty", nameof(admin.UserId)); + } + catch (Exception e) + { + throw new InvalidObjectException(e); + } + } + + public bool TryValidate(Admin admin) + { + try + { + Validate(admin); + return true; + } + catch (Exception e) + { + return false; + } + } +} \ No newline at end of file diff --git a/Govor.Data/Repositories/AdminsRepository.cs b/Govor.Data/Repositories/AdminsRepository.cs index 7a1f7d6..0482504 100644 --- a/Govor.Data/Repositories/AdminsRepository.cs +++ b/Govor.Data/Repositories/AdminsRepository.cs @@ -1,4 +1,5 @@ using Govor.Core.Infrastructure.Extensions; +using Govor.Core.Infrastructure.Validators; using Govor.Core.Models; using Govor.Core.Repositories.Admins; using Govor.Data.Repositories.Exceptions; @@ -6,10 +7,10 @@ using Microsoft.EntityFrameworkCore; namespace Govor.Data.Repositories; -public class AdminsRepository(GovorDbContext context) : IAdminsRepository +public class AdminsRepository(GovorDbContext context, IObjectValidator validator) : IAdminsRepository { private GovorDbContext _context = context; - + private IObjectValidator _validator = validator; public async Task> GetAllAsync() { return await _context.Admins @@ -18,33 +19,89 @@ public class AdminsRepository(GovorDbContext context) : IAdminsRepository .ToListOrThrowIfEmpty(new NotFoundException("Database is empty")); } - public Task GetByIdAsync(Guid id) + public async Task GetByIdAsync(Guid id) { - throw new NotImplementedException(); + return await _context.Admins + .AsNoTracking() + .Include(a => a.User) + .FirstOrDefaultAsync(u => u.UserId == id) + ?? throw new NotFoundByKeyException(id, "User with given id does not exist"); } - public Task AddAsync(Admin admin) + public async Task AddAsync(Admin admin) { - throw new NotImplementedException(); + try + { + _validator.Validate(admin); + + _context.Admins.Add(admin); + await _context.SaveChangesAsync(); + } + catch (InvalidObjectException ex) + { + throw new AdditionException("Admin with given data invalid", ex); + } + catch (Exception ex) + { + throw new AdditionException("Cannot add admin", ex); + } } - public Task UpdateAsync(Admin admin) + public async Task UpdateAsync(Admin admin) { - throw new NotImplementedException(); + try + { + _validator.Validate(admin); + + var rowsAffected = await _context.Admins + .Where(a => a.UserId == admin.UserId) + .ExecuteUpdateAsync(u => u + .SetProperty(a => a.UserId, admin.UserId) + ); + + if (rowsAffected == 0) + throw new NotFoundByKeyException(admin.UserId); + } + catch (NotFoundByKeyException ex) + { + throw new UpdateException($"Not found admin by given id {admin.UserId}", ex); + } + catch (Exception ex) + { + throw new UpdateException($"Error when updating the admin {admin.UserId}", ex); + } } - public Task DeleteAsync(Guid admin) + public async Task DeleteAsync(Guid admin) { - throw new NotImplementedException(); + try + { + var result = await GetByIdAsync(admin); + + _context.Admins.Remove(result); + await _context.SaveChangesAsync(); + } + catch (NotFoundByKeyException ex) + { + throw new RemoveException($"Not found admin by given id {admin}", ex); + } + catch (Exception ex) + { + throw new RemoveException("Error when removing the admin", ex); + } } - public bool Exist(Guid guid) + public bool Exist(Guid id) { - throw new NotImplementedException(); + return _context.Users.Any(u => u.Id == id); } public bool Exist(Admin admin) { - throw new NotImplementedException(); + _validator.Validate(admin); + + return _context.Admins.Any(u => + u.UserId == admin.UserId + ); } } \ No newline at end of file diff --git a/Govor.Data/Repositories/UsersRepository.cs b/Govor.Data/Repositories/UsersRepository.cs index dde1f4e..e346d0a 100644 --- a/Govor.Data/Repositories/UsersRepository.cs +++ b/Govor.Data/Repositories/UsersRepository.cs @@ -32,6 +32,7 @@ public class UsersRepository : IUsersRepository return await _context.Users .AsNoTracking() + .Include(u => u.Invite) .FirstOrDefaultAsync(x => x.Id == id) ?? throw new NotFoundByKeyException(id, "User with given id does not exist"); } @@ -44,6 +45,7 @@ public class UsersRepository : IUsersRepository return await _context.Users .AsNoTracking() .Where(x => ids.Contains(x.Id)) + .Include(u => u.Invite) .ToListOrThrowIfEmpty(new NotFoundByKeyException>(ids,"Users with given ids not found")); } @@ -54,7 +56,8 @@ public class UsersRepository : IUsersRepository return await _context.Users .AsNoTracking() - .FirstOrDefaultAsync(x => x.Username == username) + .Include(u => u.Invite) + .FirstOrDefaultAsync(x => x.Username == username) ?? throw new NotFoundByKeyException(username, "User with given username does not exist"); } @@ -66,6 +69,7 @@ public class UsersRepository : IUsersRepository return await _context.Users .AsNoTracking() .Where(x => usernames.Contains(x.Username)) + .Include(u => u.Invite) .ToListOrThrowIfEmpty(new NotFoundByKeyException>(usernames, "Users with given usernames not found")); } @@ -77,6 +81,7 @@ public class UsersRepository : IUsersRepository return await _context.Users .AsNoTracking() .Where(u => createdDate == u.CreatedOn) + .Include(u => u.Invite) .ToListOrThrowIfEmpty(new NotFoundByKeyException(createdDate, "Users with given created date do not exist")); }