From a7eb2e9796af30ee5b294847728c06136ca2e2d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Gonz=C3=A1lez=20Hern=C3=A1ndez?= Date: Mon, 11 May 2026 11:17:00 -0600 Subject: [PATCH 1/5] Se ajusta suma de enteros --- src/FinancialUtils/Calculator.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/FinancialUtils/Calculator.cs b/src/FinancialUtils/Calculator.cs index 09f6202..38323fe 100644 --- a/src/FinancialUtils/Calculator.cs +++ b/src/FinancialUtils/Calculator.cs @@ -10,6 +10,8 @@ public static class Calculator /// public static decimal Add(decimal a, decimal b) => a + b; + public static int Add(int a, int b) => a + b; + /// /// Resta b de a. /// From 2baa0399df8e789a5c84f7281a49d11995ee35f5 Mon Sep 17 00:00:00 2001 From: GONZALEZ HERNANDEZ ALEJANDRO Date: Mon, 11 May 2026 11:46:21 -0600 Subject: [PATCH 2/5] Ajuste de pruebas --- src/FinancialUtils/Calculator.cs | 20 +++++++++++++++++++- src/FinancialUtils/Formatter.cs | 8 ++++++++ tests/FinancialUtils.Tests/GlobalUsings.cs | 2 +- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/FinancialUtils/Calculator.cs b/src/FinancialUtils/Calculator.cs index 38323fe..40fdeeb 100644 --- a/src/FinancialUtils/Calculator.cs +++ b/src/FinancialUtils/Calculator.cs @@ -10,7 +10,7 @@ public static class Calculator /// public static decimal Add(decimal a, decimal b) => a + b; - public static int Add(int a, int b) => a + b; + ///public static int Add(int a, int b) => a + b; /// /// Resta b de a. @@ -29,7 +29,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; } @@ -46,13 +48,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); } @@ -69,16 +77,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); @@ -103,7 +119,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 83361a367d2e8533a48e03ab7fed89931900e0fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Gonz=C3=A1lez=20Hern=C3=A1ndez?= Date: Tue, 25 Aug 2026 15:45:14 +0000 Subject: [PATCH 3/5] Ajuste de pruebas --- scripts/verificar-entorno.sh | 38 +++++++++++++++++++ tests/FinancialUtils.Tests/CalculatorTests.cs | 4 +- 2 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 scripts/verificar-entorno.sh diff --git a/scripts/verificar-entorno.sh b/scripts/verificar-entorno.sh new file mode 100644 index 0000000..ebbf26a --- /dev/null +++ b/scripts/verificar-entorno.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# Verificación previa al workshop. Ejecuta esto ANTES de la sesión. +# Si algo falla aquí, resuélvelo antes y no en los primeros diez minutos +# del laboratorio. + +set -u +fallas=0 + +check() { + local nombre="$1"; shift + if "$@" > /dev/null 2>&1; then + printf ' OK %s\n' "$nombre" + else + printf ' FALLA %s\n' "$nombre" + fallas=$((fallas + 1)) + fi +} + +echo "Verificando herramientas" +check "git instalado" git --version +check "dotnet instalado" dotnet --version +check "gh (GitHub CLI) instalado" gh --version +check "gh autenticado" gh auth status + +echo +echo "Verificando el proyecto" +check "restore" dotnet restore +check "build" dotnet build --configuration Release --no-restore +check "test" dotnet test --configuration Release --no-build + +echo +if [ "$fallas" -eq 0 ]; then + echo "Todo listo. Puedes empezar el laboratorio 00." + exit 0 +fi + +echo "$fallas verificación(es) fallaron. Revisa laboratorio/00-preparacion.md." +exit 1 \ No newline at end of file diff --git a/tests/FinancialUtils.Tests/CalculatorTests.cs b/tests/FinancialUtils.Tests/CalculatorTests.cs index 6bab0b2..97dfa17 100644 --- a/tests/FinancialUtils.Tests/CalculatorTests.cs +++ b/tests/FinancialUtils.Tests/CalculatorTests.cs @@ -148,10 +148,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 130aa8880781eab7a7e8017d6ec5bddb353d4a61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Gonz=C3=A1lez=20Hern=C3=A1ndez?= Date: Tue, 25 Aug 2026 16:00:24 +0000 Subject: [PATCH 4/5] Se crea 01-ci.yml --- .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 977bd98bf96d21d2a1a03109d879205ecb0aed96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Gonz=C3=A1lez=20Hern=C3=A1ndez?= Date: Tue, 25 Aug 2026 10:44:48 -0600 Subject: [PATCH 5/5] Se agrega comentario --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e183a4c..949f921 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # ⚙️ Workshop: GitHub Intermedio +Hola + ## Pipelines, Políticas y Productividad con .NET 9 ![GitHub Actions](https://img.shields.io/badge/GitHub%20Actions-Workflows-2088FF?logo=githubactions&logoColor=white)