2026-04-15 15:39:25 -03:00
|
|
|
using Dapper;
|
|
|
|
|
using Microsoft.Data.SqlClient;
|
|
|
|
|
using SIGCM2.Infrastructure.Persistence;
|
|
|
|
|
|
|
|
|
|
namespace SIGCM2.Application.Tests.Integration;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Integration tests for PermisoRepository against SIGCM2_Test.
|
|
|
|
|
/// RED: written before the repository implementation exists.
|
|
|
|
|
/// </summary>
|
|
|
|
|
[Collection("Database")]
|
|
|
|
|
public class PermisoRepositoryTests : IAsyncLifetime
|
|
|
|
|
{
|
|
|
|
|
private const string ConnectionString =
|
|
|
|
|
"Server=TECNICA3;Database=SIGCM2_Test;User Id=desarrollo;Password=desarrollo2026;TrustServerCertificate=True;";
|
|
|
|
|
|
|
|
|
|
private SqlConnection _connection = null!;
|
|
|
|
|
private PermisoRepository _repository = null!;
|
|
|
|
|
|
|
|
|
|
public async Task InitializeAsync()
|
|
|
|
|
{
|
|
|
|
|
_connection = new SqlConnection(ConnectionString);
|
|
|
|
|
await _connection.OpenAsync();
|
|
|
|
|
|
|
|
|
|
// Ensure the 18 canonical permisos are present — idempotent MERGE.
|
|
|
|
|
// Needed because other test classes (RefreshTokenRepositoryTests, UsuarioRepositoryTests)
|
|
|
|
|
// may call Respawn.ResetAsync before us, which would clear Permiso even if listed in
|
|
|
|
|
// TablesToIgnore of the central SqlTestFixture (each class configures its own Respawner).
|
|
|
|
|
await SeedPermisosCanonicalAsync();
|
|
|
|
|
|
|
|
|
|
var factory = new SqlConnectionFactory(ConnectionString);
|
|
|
|
|
_repository = new PermisoRepository(factory);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task SeedPermisosCanonicalAsync()
|
|
|
|
|
{
|
|
|
|
|
const string sql = """
|
|
|
|
|
SET QUOTED_IDENTIFIER ON;
|
|
|
|
|
MERGE dbo.Permiso AS t
|
|
|
|
|
USING (VALUES
|
|
|
|
|
('ventas:contado:crear', N'Cargar orden contado', NULL, 'ventas'),
|
|
|
|
|
('ventas:contado:modificar', N'Modificar orden contado', NULL, 'ventas'),
|
|
|
|
|
('ventas:contado:cobrar', N'Cobrar orden contado', NULL, 'ventas'),
|
|
|
|
|
('ventas:contado:facturar', N'Facturar orden contado', NULL, 'ventas'),
|
|
|
|
|
('ventas:ctacte:crear', N'Cargar orden cuenta corriente', NULL, 'ventas'),
|
|
|
|
|
('ventas:ctacte:facturar', N'Facturar lote cuenta corriente', NULL, 'ventas'),
|
|
|
|
|
('textos:editar', N'Editar textos', NULL, 'textos'),
|
|
|
|
|
('textos:reclamos:ver', N'Ver reclamos de textos', NULL, 'textos'),
|
|
|
|
|
('pauta:azanu:ver', N'Ver AZANU en pauta', NULL, 'pauta'),
|
|
|
|
|
('pauta:limpiar', N'Limpieza de pauta', NULL, 'pauta'),
|
|
|
|
|
('pauta:recursos:fueradehora', N'Recursos fuera de hora', NULL, 'pauta'),
|
|
|
|
|
('productores:deuda:ver', N'Ver deuda propia de productores', NULL, 'productores'),
|
|
|
|
|
('productores:pendientes:crear', N'Cargar pendientes de productores', NULL, 'productores'),
|
|
|
|
|
('productores:deuda:bypass', N'Bypass de deuda de productores', NULL, 'productores'),
|
|
|
|
|
('administracion:usuarios:gestionar', N'Gestionar usuarios del sistema', N'Crear, editar y desactivar usuarios', 'administracion'),
|
|
|
|
|
('administracion:tarifarios:gestionar', N'Gestionar tarifarios', N'Crear y modificar tarifarios de publicidad', 'administracion'),
|
|
|
|
|
('administracion:medios:gestionar', N'Gestionar medios publicitarios', N'Alta y configuracion de medios', 'administracion'),
|
|
|
|
|
('administracion:auditoria:ver', N'Ver logs de auditoria', N'Acceso al dashboard de auditoria', 'administracion')
|
|
|
|
|
) AS s (Codigo, Nombre, Descripcion, Modulo)
|
|
|
|
|
ON t.Codigo = s.Codigo
|
|
|
|
|
WHEN NOT MATCHED BY TARGET THEN
|
|
|
|
|
INSERT (Codigo, Nombre, Descripcion, Modulo)
|
|
|
|
|
VALUES (s.Codigo, s.Nombre, s.Descripcion, s.Modulo);
|
|
|
|
|
""";
|
|
|
|
|
await _connection.ExecuteAsync(sql);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task DisposeAsync()
|
|
|
|
|
{
|
|
|
|
|
await _connection.CloseAsync();
|
|
|
|
|
await _connection.DisposeAsync();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── ListAsync ────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
[Fact]
|
2026-04-15 16:34:32 -03:00
|
|
|
public async Task ListAsync_Returns21CanonicalSeeds()
|
2026-04-15 15:39:25 -03:00
|
|
|
{
|
|
|
|
|
var list = await _repository.ListAsync();
|
|
|
|
|
|
2026-04-15 16:34:32 -03:00
|
|
|
// V005 seeds 18 canonical permisos + V007 (UDT-006) adds 3 admin permisos = 21 total
|
|
|
|
|
Assert.Equal(21, list.Count);
|
2026-04-15 15:39:25 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public async Task ListAsync_ContainsExpectedCodigos()
|
|
|
|
|
{
|
|
|
|
|
var list = await _repository.ListAsync();
|
|
|
|
|
var codigos = list.Select(p => p.Codigo).ToHashSet();
|
|
|
|
|
|
|
|
|
|
Assert.Contains("ventas:contado:crear", codigos);
|
|
|
|
|
Assert.Contains("ventas:contado:facturar", codigos);
|
|
|
|
|
Assert.Contains("administracion:usuarios:gestionar", codigos);
|
|
|
|
|
Assert.Contains("administracion:auditoria:ver", codigos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public async Task ListAsync_AllItemsHaveNonEmptyCodigoAndNombre()
|
|
|
|
|
{
|
|
|
|
|
var list = await _repository.ListAsync();
|
|
|
|
|
|
|
|
|
|
foreach (var p in list)
|
|
|
|
|
{
|
|
|
|
|
Assert.False(string.IsNullOrWhiteSpace(p.Codigo));
|
|
|
|
|
Assert.False(string.IsNullOrWhiteSpace(p.Nombre));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── GetByCodigoAsync ─────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public async Task GetByCodigoAsync_ExistingCodigo_ReturnsPermiso()
|
|
|
|
|
{
|
|
|
|
|
var permiso = await _repository.GetByCodigoAsync("ventas:contado:crear");
|
|
|
|
|
|
|
|
|
|
Assert.NotNull(permiso);
|
|
|
|
|
Assert.Equal("ventas:contado:crear", permiso!.Codigo);
|
|
|
|
|
Assert.False(string.IsNullOrWhiteSpace(permiso.Nombre));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public async Task GetByCodigoAsync_AnotherExistingCodigo_ReturnsCorrectPermiso()
|
|
|
|
|
{
|
|
|
|
|
var permiso = await _repository.GetByCodigoAsync("administracion:usuarios:gestionar");
|
|
|
|
|
|
|
|
|
|
Assert.NotNull(permiso);
|
|
|
|
|
Assert.Equal("administracion:usuarios:gestionar", permiso!.Codigo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public async Task GetByCodigoAsync_NonExistentCodigo_ReturnsNull()
|
|
|
|
|
{
|
|
|
|
|
var permiso = await _repository.GetByCodigoAsync("permiso:inexistente:xyz");
|
|
|
|
|
|
|
|
|
|
Assert.Null(permiso);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── GetByCodigosAsync ────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public async Task GetByCodigosAsync_ThreeValidCodigos_ReturnsThreeEntities()
|
|
|
|
|
{
|
|
|
|
|
var codigos = new[]
|
|
|
|
|
{
|
|
|
|
|
"ventas:contado:crear",
|
|
|
|
|
"ventas:contado:facturar",
|
|
|
|
|
"textos:editar"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var result = await _repository.GetByCodigosAsync(codigos);
|
|
|
|
|
|
|
|
|
|
Assert.Equal(3, result.Count);
|
|
|
|
|
var returnedCodigos = result.Select(p => p.Codigo).ToHashSet();
|
|
|
|
|
foreach (var c in codigos)
|
|
|
|
|
Assert.Contains(c, returnedCodigos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public async Task GetByCodigosAsync_MixedExistingAndNonExisting_ReturnsOnlyExisting()
|
|
|
|
|
{
|
|
|
|
|
var codigos = new[]
|
|
|
|
|
{
|
|
|
|
|
"ventas:contado:crear",
|
|
|
|
|
"permiso:no:existe",
|
|
|
|
|
"textos:editar"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var result = await _repository.GetByCodigosAsync(codigos);
|
|
|
|
|
|
|
|
|
|
// Only 2 of 3 exist
|
|
|
|
|
Assert.Equal(2, result.Count);
|
|
|
|
|
var returnedCodigos = result.Select(p => p.Codigo).ToHashSet();
|
|
|
|
|
Assert.Contains("ventas:contado:crear", returnedCodigos);
|
|
|
|
|
Assert.Contains("textos:editar", returnedCodigos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public async Task GetByCodigosAsync_EmptyList_ReturnsEmpty()
|
|
|
|
|
{
|
|
|
|
|
var result = await _repository.GetByCodigosAsync(Array.Empty<string>());
|
|
|
|
|
|
|
|
|
|
Assert.Empty(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public async Task GetByCodigosAsync_AllNonExisting_ReturnsEmpty()
|
|
|
|
|
{
|
|
|
|
|
var codigos = new[] { "no:existe:uno", "no:existe:dos" };
|
|
|
|
|
|
|
|
|
|
var result = await _repository.GetByCodigosAsync(codigos);
|
|
|
|
|
|
|
|
|
|
Assert.Empty(result);
|
|
|
|
|
}
|
|
|
|
|
}
|