From 4f094350b03c6c476171083fb3400d83b6212279 Mon Sep 17 00:00:00 2001 From: leopansa Date: Tue, 19 May 2026 17:25:00 -0600 Subject: [PATCH 1/6] Se agrega metodo suma float adicional a Calculator --- src/FinancialUtils/Calculator.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/FinancialUtils/Calculator.cs b/src/FinancialUtils/Calculator.cs index 38323fe..9ef927e 100644 --- a/src/FinancialUtils/Calculator.cs +++ b/src/FinancialUtils/Calculator.cs @@ -12,6 +12,8 @@ public static class Calculator public static int Add(int a, int b) => a + b; + public static float Add(float a, float b) => a + b; + /// /// Resta b de a. /// From e97526384ee3824b12a2cd5df8a225d0680e11df Mon Sep 17 00:00:00 2001 From: Leonardo Paniagua Sanabria Date: Tue, 19 May 2026 17:44:06 -0600 Subject: [PATCH 2/6] =?UTF-8?q?Se=20aplic=C3=B3=20el=20format?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/FinancialUtils/Calculator.cs | 18 ++++++++++++++++++ src/FinancialUtils/Formatter.cs | 8 ++++++++ tests/FinancialUtils.Tests/GlobalUsings.cs | 2 +- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/FinancialUtils/Calculator.cs b/src/FinancialUtils/Calculator.cs index 9ef927e..c307709 100644 --- a/src/FinancialUtils/Calculator.cs +++ b/src/FinancialUtils/Calculator.cs @@ -31,7 +31,9 @@ public static class Calculator public static decimal Divide(decimal a, decimal b) { if (b == 0) + { throw new DivideByZeroException("El divisor no puede ser cero."); + } return a / b; } @@ -48,13 +50,19 @@ public static decimal Divide(decimal a, decimal b) public static decimal CompoundInterest(decimal principal, decimal rate, int periods) { if (principal < 0) + { throw new ArgumentException("El capital no puede ser negativo.", nameof(principal)); + } if (rate < 0) + { throw new ArgumentException("La tasa no puede ser negativa.", nameof(rate)); + } if (periods < 1) + { throw new ArgumentException("Los periodos deben ser un entero positivo.", nameof(periods)); + } return principal * (decimal)Math.Pow((double)(1 + rate), periods); } @@ -71,16 +79,24 @@ public static decimal CompoundInterest(decimal principal, decimal rate, int peri public static decimal LoanPayment(decimal principal, decimal annualRate, int months) { if (principal <= 0) + { throw new ArgumentException("El préstamo debe ser mayor a cero.", nameof(principal)); + } if (annualRate < 0) + { throw new ArgumentException("La tasa no puede ser negativa.", nameof(annualRate)); + } if (months < 1) + { throw new ArgumentException("El plazo debe ser un entero positivo.", nameof(months)); + } if (annualRate == 0) + { return Math.Round(principal / months, 2, MidpointRounding.AwayFromZero); + } var monthlyRate = annualRate / 12; var factor = (decimal)Math.Pow((double)(1 + monthlyRate), months); @@ -105,7 +121,9 @@ public static decimal NetPresentValue(decimal discountRate, IEnumerable ?? throw new ArgumentNullException(nameof(cashFlows)); if (flows.Count == 0) + { throw new ArgumentException("Se requiere al menos un flujo de caja.", nameof(cashFlows)); + } decimal npv = 0; for (int t = 0; t < flows.Count; t++) diff --git a/src/FinancialUtils/Formatter.cs b/src/FinancialUtils/Formatter.cs index 25a942f..aa7e617 100644 --- a/src/FinancialUtils/Formatter.cs +++ b/src/FinancialUtils/Formatter.cs @@ -17,7 +17,9 @@ public static class Formatter public static string FormatCurrency(decimal amount, string currencyCode = "USD", string cultureName = "es-MX") { if (string.IsNullOrWhiteSpace(currencyCode)) + { throw new ArgumentException("El código de moneda no puede estar vacío.", nameof(currencyCode)); + } var culture = new CultureInfo(cultureName); var regionInfo = new RegionInfo(cultureName); @@ -36,7 +38,9 @@ public static string FormatCurrency(decimal amount, string currencyCode = "USD", public static string FormatPercentage(decimal value, int decimalPlaces = 2) { if (decimalPlaces < 0) + { throw new ArgumentException("Los decimales no pueden ser negativos.", nameof(decimalPlaces)); + } return $"{(value * 100).ToString($"F{decimalPlaces}")}%"; } @@ -50,7 +54,9 @@ public static string FormatPercentage(decimal value, int decimalPlaces = 2) public static string FormatNumber(decimal value, int decimalPlaces = 0, string cultureName = "es-MX") { if (decimalPlaces < 0) + { throw new ArgumentException("Los decimales no pueden ser negativos.", nameof(decimalPlaces)); + } var culture = new CultureInfo(cultureName); return value.ToString($"N{decimalPlaces}", culture); @@ -64,7 +70,9 @@ public static string FormatNumber(decimal value, int decimalPlaces = 0, string c public static decimal TruncateDecimals(decimal value, int decimalPlaces) { if (decimalPlaces < 0) + { throw new ArgumentException("Los decimales no pueden ser negativos.", nameof(decimalPlaces)); + } var factor = (decimal)Math.Pow(10, decimalPlaces); return Math.Truncate(value * factor) / factor; diff --git a/tests/FinancialUtils.Tests/GlobalUsings.cs b/tests/FinancialUtils.Tests/GlobalUsings.cs index 8c927eb..c802f44 100644 --- a/tests/FinancialUtils.Tests/GlobalUsings.cs +++ b/tests/FinancialUtils.Tests/GlobalUsings.cs @@ -1 +1 @@ -global using Xunit; \ No newline at end of file +global using Xunit; From 0eeabada1009c15fa7bd4cbc22f48784cc15f301 Mon Sep 17 00:00:00 2001 From: Leonardo Paniagua Sanabria Date: Tue, 19 May 2026 17:58:51 -0600 Subject: [PATCH 3/6] Se ajustan las pruebas para int y float --- tests/FinancialUtils.Tests/CalculatorTests.cs | 44 ++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/tests/FinancialUtils.Tests/CalculatorTests.cs b/tests/FinancialUtils.Tests/CalculatorTests.cs index 6bab0b2..9d6ca78 100644 --- a/tests/FinancialUtils.Tests/CalculatorTests.cs +++ b/tests/FinancialUtils.Tests/CalculatorTests.cs @@ -26,6 +26,46 @@ public void Add_WithZero_ReturnsSameValue() Assert.Equal(7m, Calculator.Add(0m, 7m)); } + // --- Add (int) --- + + [Fact] + public void Add_Int_TwoPositives_ReturnsCorrectSum() + { + Assert.Equal(7, Calculator.Add(3, 4)); + } + + [Fact] + public void Add_Int_WithNegative_ReturnsCorrectSum() + { + Assert.Equal(1, Calculator.Add(-2, 3)); + } + + [Fact] + public void Add_Int_WithZero_ReturnsSameValue() + { + Assert.Equal(5, Calculator.Add(0, 5)); + } + + // --- Add (float) --- + + [Fact] + public void Add_Float_TwoPositives_ReturnsCorrectSum() + { + Assert.Equal(5.5f, Calculator.Add(2.5f, 3.0f)); + } + + [Fact] + public void Add_Float_WithNegative_ReturnsCorrectSum() + { + Assert.Equal(1.5f, Calculator.Add(-1.0f, 2.5f)); + } + + [Fact] + public void Add_Float_WithZero_ReturnsSameValue() + { + Assert.Equal(4.2f, Calculator.Add(0f, 4.2f)); + } + // --- Subtract --- [Fact] @@ -148,10 +188,10 @@ public void LoanPayment_InvalidMonths_ThrowsArgumentException(int months) public void NetPresentValue_CalculatesCorrectly() { // Inversión inicial -1000, flujos futuros de 400 por 3 periodos a tasa 10% - // NPV = -1000 + 400/1.1 + 400/1.21 + 400/1.331 ≈ -0.64 + // NPV = -1000 + 400/1.1 + 400/1.21 + 400/1.331 ≈ -5.26 var cashFlows = new[] { -1000m, 400m, 400m, 400m }; var result = Calculator.NetPresentValue(0.10m, cashFlows); - Assert.Equal(-0.64m, result); + Assert.Equal(-5.26m, result); } [Fact] From 1934f241b0c4a80af265cf4cd4060c1bb0ebfbe5 Mon Sep 17 00:00:00 2001 From: Leonardo Paniagua Sanabria Date: Tue, 19 May 2026 18:07:17 -0600 Subject: [PATCH 4/6] Se ajusta el comando para realizar las pruebas --- .github/workflows/matrix.yml | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/.github/workflows/matrix.yml b/.github/workflows/matrix.yml index 2468a2c..ced22cb 100644 --- a/.github/workflows/matrix.yml +++ b/.github/workflows/matrix.yml @@ -43,15 +43,18 @@ jobs: - name: Compilar run: dotnet build --configuration Release --no-restore - + - name: Ejecutar pruebas - run: | - dotnet test \ - --configuration Release \ - --no-restore \ - --collect:"XPlat Code Coverage" \ - --results-directory ./coverage \ - --logger "trx;LogFileName=test-results.trx" + run: dotnet test --configuration Release --no-restore --collect:"XPlat Code Coverage" --results-directory ./coverage --logger "trx;LogFileName=test-results.trx" + + #- name: Ejecutar pruebas + # run: | + # dotnet test \ + # --configuration Release \ + # --no-restore \ + # --collect:"XPlat Code Coverage" \ + # --results-directory ./coverage \ + # --logger "trx;LogFileName=test-results.trx" - name: Subir resultado por combinación uses: actions/upload-artifact@v4 From 4be923d6e640fb4880da915cb5454de747d537ea Mon Sep 17 00:00:00 2001 From: Leonardo Paniagua Sanabria Date: Tue, 25 Aug 2026 10:02:09 -0600 Subject: [PATCH 5/6] se modifica el archivo ci paralelismo --- .github/workflows/01-ci.yml | 123 ++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 .github/workflows/01-ci.yml diff --git a/.github/workflows/01-ci.yml b/.github/workflows/01-ci.yml new file mode 100644 index 0000000..a713bfd --- /dev/null +++ b/.github/workflows/01-ci.yml @@ -0,0 +1,123 @@ +# Estado esperado de .github/workflows/01-ci.yml al terminar el laboratorio 04. +# Cambios respecto al 03: el trabajo se parte en dos jobs unidos con `needs`, +# y los binarios viajan de un job a otro como artefacto. +# +# Ojo con el costo: dos jobs significan dos runners, dos checkouts y dos +# restores. Partir jobs se justifica cuando ganas paralelismo o cuando +# necesitas condiciones distintas, no por estética. + +name: 01 - CI + +on: + push: + branches: + - main + - 'lab/**' + pull_request: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + +env: + DOTNET_VERSION: '9.0.x' + DOTNET_NOLOGO: 'true' + DOTNET_CLI_TELEMETRY_OPTOUT: 'true' + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + name: Build + runs-on: ubuntu-latest + outputs: + version-sdk: ${{ steps.sdk.outputs.dotnet-version }} + steps: + - name: Descargar el código al runner + uses: actions/checkout@v7 + + - name: Instalar el SDK de .NET + id: sdk + uses: actions/setup-dotnet@v6 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + - name: Restaurar dependencias + run: dotnet restore + + - name: Compilar en Release + run: dotnet build --configuration Release --no-restore + + - name: Publicar los binarios compilados + uses: actions/upload-artifact@v7 + with: + name: binarios + path: | + src/**/bin/Release/ + tests/**/bin/Release/ + retention-days: 1 + if-no-files-found: error + + test: + name: Test + runs-on: ubuntu-latest + needs: build + steps: + - name: Descargar el código al runner + uses: actions/checkout@v7 + + - name: Instalar el SDK de .NET + uses: actions/setup-dotnet@v6 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + - name: Bajar los binarios del job anterior + uses: actions/download-artifact@v7 + with: + name: binarios + + # El artefacto trae bin/, pero no obj/. `dotnet test --no-build` necesita + # el archivo obj/project.assets.json para resolver rutas de salida, así que + # hay que restaurar de nuevo. Es rápido porque no vuelve a compilar. + - name: Restaurar dependencias + run: dotnet restore + + - name: Ejecutar pruebas + run: | + dotnet test \ + --configuration Release \ + --no-build \ + --logger "trx;LogFileName=resultados.trx" \ + --results-directory ./resultados + + - name: Publicar resultados de pruebas + if: always() + uses: actions/upload-artifact@v7 + with: + name: resultados-de-pruebas + path: ./resultados + retention-days: 5 + if-no-files-found: error + + - name: Escribir el resumen del run + if: always() + run: | + TRX=$(find ./resultados -name '*.trx' | head -1) + TOTAL=$(grep -o 'total="[0-9]*"' "$TRX" | head -1 | grep -o '[0-9]*') + PASADAS=$(grep -o 'passed="[0-9]*"' "$TRX" | head -1 | grep -o '[0-9]*') + FALLIDAS=$(grep -o 'failed="[0-9]*"' "$TRX" | head -1 | grep -o '[0-9]*') + { + echo "### Resultado de las pruebas" + echo "" + echo "| Métrica | Valor |" + echo "|---------|-------|" + echo "| Total | ${TOTAL:-0} |" + echo "| Pasadas | ${PASADAS:-0} |" + echo "| Fallidas | ${FALLIDAS:-0} |" + echo "" + echo "SDK usado en build: \`${{ needs.build.outputs.version-sdk }}\`" + } >> "$GITHUB_STEP_SUMMARY" \ No newline at end of file From 29497779a3f0845e3449fa503477c422817a36fb Mon Sep 17 00:00:00 2001 From: Leonardo Paniagua Sanabria Date: Tue, 25 Aug 2026 10:49:48 -0600 Subject: [PATCH 6/6] =?UTF-8?q?se=20agrega=20archivo=20CODEOWNERS=20y=20se?= =?UTF-8?q?=20crea=20workflow=20de=20pruebas=20para=20verificar=20formato?= =?UTF-8?q?=20de=20c=C3=B3digo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/CODEOWNERS | 41 +------------------------------------ .github/code_OWNERS_back.aa | 40 ++++++++++++++++++++++++++++++++++++ .github/workflows/Test.yml | 38 ++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 40 deletions(-) create mode 100644 .github/code_OWNERS_back.aa create mode 100644 .github/workflows/Test.yml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index b90d68d..1114f1e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,40 +1 @@ -# CODEOWNERS -# -# Define quién debe revisar cambios en partes específicas del repositorio. -# GitHub solicita automáticamente la revisión de los owners cuando un PR -# modifica archivos que coinciden con algún patrón. -# -# Sintaxis: patrón @usuario-o-equipo -# -# Las reglas se evalúan de arriba hacia abajo. -# La última regla que coincida con un archivo gana. -# Los patrones siguen la misma sintaxis que .gitignore. - -# --- Owner global --- -# Aplica a todo lo que no tenga una regla más específica abajo. -* @TU_USUARIO - -# --- Librería principal --- -# Cualquier cambio en el código fuente requiere revisión de los maintainers. -/src/ @TU_USUARIO - -# --- Tests --- -# Los tests pueden revisarlos los mismos developers, no solo maintainers. -# En un equipo real aquí irían @equipo/developers o usuarios individuales. -/tests/ @TU_USUARIO - -# --- Workflows de CI/CD --- -# Los cambios en pipelines tienen un impacto alto: pueden exponer secrets, -# modificar qué checks son requeridos, o cambiar tiempos de build. -# Requieren revisión explícita de quien administra la infraestructura. -/.github/workflows/ @TU_USUARIO - -# --- Configuración de seguridad y políticas --- -# CODEOWNERS mismo, editorconfig y configuración del repo. -/.github/CODEOWNERS @TU_USUARIO -/.editorconfig @TU_USUARIO - -# --- Documentación --- -# El README puede actualizarlo cualquier contributor. -# Si quisieras restricción, agregarías un owner específico aquí. -*.md @TU_USUARIO +* @leopansa \ No newline at end of file diff --git a/.github/code_OWNERS_back.aa b/.github/code_OWNERS_back.aa new file mode 100644 index 0000000..b90d68d --- /dev/null +++ b/.github/code_OWNERS_back.aa @@ -0,0 +1,40 @@ +# CODEOWNERS +# +# Define quién debe revisar cambios en partes específicas del repositorio. +# GitHub solicita automáticamente la revisión de los owners cuando un PR +# modifica archivos que coinciden con algún patrón. +# +# Sintaxis: patrón @usuario-o-equipo +# +# Las reglas se evalúan de arriba hacia abajo. +# La última regla que coincida con un archivo gana. +# Los patrones siguen la misma sintaxis que .gitignore. + +# --- Owner global --- +# Aplica a todo lo que no tenga una regla más específica abajo. +* @TU_USUARIO + +# --- Librería principal --- +# Cualquier cambio en el código fuente requiere revisión de los maintainers. +/src/ @TU_USUARIO + +# --- Tests --- +# Los tests pueden revisarlos los mismos developers, no solo maintainers. +# En un equipo real aquí irían @equipo/developers o usuarios individuales. +/tests/ @TU_USUARIO + +# --- Workflows de CI/CD --- +# Los cambios en pipelines tienen un impacto alto: pueden exponer secrets, +# modificar qué checks son requeridos, o cambiar tiempos de build. +# Requieren revisión explícita de quien administra la infraestructura. +/.github/workflows/ @TU_USUARIO + +# --- Configuración de seguridad y políticas --- +# CODEOWNERS mismo, editorconfig y configuración del repo. +/.github/CODEOWNERS @TU_USUARIO +/.editorconfig @TU_USUARIO + +# --- Documentación --- +# El README puede actualizarlo cualquier contributor. +# Si quisieras restricción, agregarías un owner específico aquí. +*.md @TU_USUARIO diff --git a/.github/workflows/Test.yml b/.github/workflows/Test.yml new file mode 100644 index 0000000..fc17534 --- /dev/null +++ b/.github/workflows/Test.yml @@ -0,0 +1,38 @@ +name: Test + +on: + push: + branches: + - main + - 'feature/**' + - 'fix/**' + pull_request: + branches: + - main + +env: + DOTNET_VERSION: '9.0.x' + DOTNET_NOLOGO: true + DOTNET_CLI_TELEMETRY_OPTOUT: true + +jobs: + format: + name: Format check + runs-on: ubuntu-latest + outputs: + dotnet-version: ${{ steps.setup-dotnet.outputs.dotnet-version }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup .NET + id: setup-dotnet + uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + - name: Restore dependencias + run: dotnet restore + + - name: Verificar formato de código + run: dotnet format --verify-no-changes --verbosity diagnostic \ No newline at end of file