using System.Reflection; using FluentAssertions; using SIGCM2.Domain.Fiscal; using IibbDomain = SIGCM2.Domain.Entities.IngresosBrutos; namespace SIGCM2.Application.Tests.Domain.Fiscal; public class IngresosBrutosTests { private static readonly DateOnly Desde2020 = new(2020, 1, 1); private static readonly DateOnly Desde2026 = new(2026, 6, 1); private static IibbDomain MakeIIBB( int id = 1, ProvinciaArgentina provincia = ProvinciaArgentina.BuenosAires, string descripcion = "IIBB Buenos Aires", decimal alicuota = 3.5m, bool activo = true, DateOnly? vigenciaDesde = null, DateOnly? vigenciaHasta = null, int? predecesorId = null) => IibbDomain.FromDb( id: id, provincia: provincia, descripcion: descripcion, alicuota: alicuota, activo: activo, vigenciaDesde: vigenciaDesde ?? Desde2020, vigenciaHasta: vigenciaHasta, predecesorId: predecesorId, fechaCreacion: DateTime.UtcNow, fechaModificacion: null); // ── T200.20: ForCreation validations ────────────────────────────────────── [Fact] public void ForCreation_ValidArgs_ReturnsEntity() { var iibb = IibbDomain.ForCreation(ProvinciaArgentina.Cordoba, "IIBB Córdoba", 2.5m, Desde2020); iibb.Provincia.Should().Be(ProvinciaArgentina.Cordoba); iibb.Descripcion.Should().Be("IIBB Córdoba"); iibb.Alicuota.Should().Be(2.5m); iibb.Activo.Should().BeTrue(); iibb.Id.Should().Be(0); iibb.PredecesorId.Should().BeNull(); iibb.VigenciaHasta.Should().BeNull(); } [Fact] public void ForCreation_AlicuotaNegativa_ThrowsArgumentException() { var act = () => IibbDomain.ForCreation(ProvinciaArgentina.BuenosAires, "desc", -1m, Desde2020); act.Should().Throw() .WithParameterName("alicuota"); } [Fact] public void ForCreation_AlicuotaMayorA100_ThrowsArgumentException() { var act = () => IibbDomain.ForCreation(ProvinciaArgentina.BuenosAires, "desc", 101m, Desde2020); act.Should().Throw() .WithParameterName("alicuota"); } [Theory] [InlineData(0)] [InlineData(2.5)] [InlineData(100)] public void ForCreation_AlicuotaEnRango_NoLanza(double alicuota) { var act = () => IibbDomain.ForCreation(ProvinciaArgentina.Salta, "desc", (decimal)alicuota, Desde2020); act.Should().NotThrow(); } [Fact] public void ForCreation_VigenciaHastaMenorQueDesde_ThrowsArgumentException() { var desde = new DateOnly(2026, 6, 1); var hasta = new DateOnly(2026, 1, 1); var act = () => IibbDomain.ForCreation(ProvinciaArgentina.SantaFe, "desc", 3m, desde, hasta); act.Should().Throw() .WithParameterName("vigenciaHasta"); } // ── T200.22: With* methods ──────────────────────────────────────────────── [Fact] public void WithDescripcion_ReturnsNewInstanceWithUpdatedDescripcion() { var original = MakeIIBB(descripcion: "Original"); var updated = original.WithDescripcion("Actualizado"); updated.Should().NotBeSameAs(original); updated.Descripcion.Should().Be("Actualizado"); updated.Alicuota.Should().Be(original.Alicuota, "Alicuota es inmutable"); } [Fact] public void Deactivate_ReturnsNewInstanceWithActivoFalse() { var original = MakeIIBB(activo: true); var deactivated = original.Deactivate(); deactivated.Activo.Should().BeFalse(); deactivated.Alicuota.Should().Be(original.Alicuota); deactivated.Id.Should().Be(original.Id); } [Fact] public void Reactivate_ReturnsNewInstanceWithActivoTrue() { var original = MakeIIBB(activo: false); var reactivated = original.Reactivate(); reactivated.Activo.Should().BeTrue(); } [Fact] public void CerrarVigencia_SetsVigenciaHasta() { var original = MakeIIBB(vigenciaHasta: null); var hasta = new DateOnly(2026, 5, 31); var cerrado = original.CerrarVigencia(hasta); cerrado.VigenciaHasta.Should().Be(hasta); cerrado.Alicuota.Should().Be(original.Alicuota); } // ── T200.24: NuevaVersion tuple ─────────────────────────────────────────── [Fact] public void NuevaVersion_ReturnsPredecesoraCerradaYNuevaVersion() { var predecesora = MakeIIBB(id: 5, alicuota: 2.5m, vigenciaDesde: Desde2020, vigenciaHasta: null); var (cerrada, nueva) = predecesora.NuevaVersion(3.0m, Desde2026); cerrada.Id.Should().Be(5); cerrada.VigenciaHasta.Should().Be(Desde2026.AddDays(-1)); cerrada.Alicuota.Should().Be(2.5m, "alicuota predecesora no cambia"); nueva.Id.Should().Be(0); nueva.PredecesorId.Should().Be(5); nueva.Alicuota.Should().Be(3.0m); nueva.VigenciaDesde.Should().Be(Desde2026); nueva.VigenciaHasta.Should().BeNull(); nueva.Provincia.Should().Be(predecesora.Provincia, "hereda la provincia"); nueva.Descripcion.Should().Be(predecesora.Descripcion, "hereda la descripción"); nueva.Activo.Should().BeTrue(); } [Fact] public void NuevaVersion_PredecesoraConVigenciaHasta_ThrowsInvalidOperationException() { var predecesora = MakeIIBB( vigenciaDesde: Desde2020, vigenciaHasta: new DateOnly(2025, 12, 31)); var act = () => predecesora.NuevaVersion(4.0m, Desde2026); act.Should().Throw(); } [Fact] public void NuevaVersion_VigenciaDesdeIgualAPredecesora_ThrowsArgumentException() { var predecesora = MakeIIBB(vigenciaDesde: Desde2020, vigenciaHasta: null); var act = () => predecesora.NuevaVersion(4.0m, Desde2020); act.Should().Throw() .WithParameterName("vigenciaDesde"); } [Fact] public void NuevaVersion_NuevaAlicuotaNegativa_ThrowsArgumentException() { var predecesora = MakeIIBB(vigenciaDesde: Desde2020, vigenciaHasta: null); var act = () => predecesora.NuevaVersion(-1m, Desde2026); act.Should().Throw() .WithParameterName("nuevaAlicuota"); } [Fact] public void NuevaVersion_NuevaAlicuotaMayorA100_ThrowsArgumentException() { var predecesora = MakeIIBB(vigenciaDesde: Desde2020, vigenciaHasta: null); var act = () => predecesora.NuevaVersion(101m, Desde2026); act.Should().Throw() .WithParameterName("nuevaAlicuota"); } // ── T200.25: reflection — NO debe existir WithAlicuota ni WithProvincia ─── [Fact] public void IngresosBrutos_No_Debe_Exponer_WithAlicuota() { var method = typeof(IibbDomain).GetMethod("WithAlicuota", BindingFlags.Public | BindingFlags.Instance); method.Should().BeNull("Alicuota es inmutable — usar NuevaVersion"); } [Fact] public void IngresosBrutos_No_Debe_Exponer_WithProvincia() { var method = typeof(IibbDomain).GetMethod("WithProvincia", BindingFlags.Public | BindingFlags.Instance); method.Should().BeNull("Provincia es inmutable en IngresosBrutos"); } // ── FromDb sets all properties ──────────────────────────────────────────── [Fact] public void FromDb_SetsAllProperties() { var fechaCreacion = DateTime.UtcNow; var iibb = IibbDomain.FromDb( id: 10, provincia: ProvinciaArgentina.Tucuman, descripcion: "IIBB Tucuman", alicuota: 1.5m, activo: true, vigenciaDesde: Desde2020, vigenciaHasta: null, predecesorId: null, fechaCreacion: fechaCreacion, fechaModificacion: null); iibb.Id.Should().Be(10); iibb.Provincia.Should().Be(ProvinciaArgentina.Tucuman); iibb.Alicuota.Should().Be(1.5m); iibb.FechaCreacion.Should().Be(fechaCreacion); } }