From f76761b0278d68dda965d72dd0d594031473bd29 Mon Sep 17 00:00:00 2001 From: javgarbor2 Date: Mon, 5 May 2025 17:30:49 +0200 Subject: [PATCH 1/8] Test RemoteEnquirer Test para la clase ExtraccionMetricas que implementa la interfaz RemoteEnquirer --- .../test/model/remote/RemoteEnquirerTest.java | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 src/test/java/us/muit/fs/a4i/test/model/remote/RemoteEnquirerTest.java diff --git a/src/test/java/us/muit/fs/a4i/test/model/remote/RemoteEnquirerTest.java b/src/test/java/us/muit/fs/a4i/test/model/remote/RemoteEnquirerTest.java new file mode 100644 index 00000000..5deb82da --- /dev/null +++ b/src/test/java/us/muit/fs/a4i/test/model/remote/RemoteEnquirerTest.java @@ -0,0 +1,85 @@ +package us.muit.fs.a4i.test.model.remote; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.List; +import java.util.logging.Logger; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import us.muit.fs.a4i.exceptions.MetricException; +import us.muit.fs.a4i.model.entities.ReportItem; +import us.muit.fs.a4i.model.entities.ReportItemI; +import us.muit.fs.a4i.model.remote.GitHubRepositoryEnquirer; +import us.muit.fs.a4i.model.remote.RemoteEnquirer; + +class RemoteEnquirerTest { + + private static Logger log = Logger.getLogger(RemoteEnquirerTest.class.getName()); + + private RemoteEnquirer enquirer = new ExtraccionMetricas(); // Asegúrate que esta clase existe y está implementada + + + // Test que certifica que se puede obtener la métrica "totalIssues" (el resultado no es nulo, + // el nombre de la métrica coincide al completo y el valor es de tipo numérico). + + @Test + void testGetTotalIssuesMetric() throws MetricException { + String repoId = "Isabel-Roman"; // Reemplazar con un repositorio válido de prueba + + ReportItemI metric = enquirer.getMetric("totalIssues", repoId); + assertNotNull(metric, "La métrica 'totalIssues' no debe ser null"); + assertEquals("totalIssues", metric.getName()); + assertTrue(metric.getValue() instanceof Number, "El valor debe ser numérico"); + + log.info("Total Issues: " + metric.getValue()); + } + + // Test que certifica que se puede obtener la métrica "labeledIssues" (el resultado no es nulo, + // el nombre de la métrica coincide al completo y el valor es de tipo numérico). + + @Test + void testGetLabeledIssuesMetric() throws MetricException { + String repoId = "Isabel-Roman"; // Reemplazar con un repositorio válido de prueba + + ReportItemI metric = enquirer.getMetric("labeledIssues", repoId); + assertNotNull(metric, "La métrica 'labeledIssues' no debe ser null"); + assertEquals("labeledIssues", metric.getName()); + assertTrue(metric.getValue() instanceof Number, "El valor debe ser numérico"); + + log.info("Issues con etiquetas: " + metric.getValue()); + } + + + // Test que verifica que el objeto informa correctamente de las métricas que soporta (que + // la lista no es nula y que dentro de las posibilidades están "totalIssues" y "labeledIssues") + + @Test + void testGetAvailableMetrics() { + List metrics = enquirer.getAvailableMetrics(); + assertNotNull(metrics); + assertTrue(metrics.contains("totalIssues"), "Debe contener la métrica 'totalIssues'"); + assertTrue(metrics.contains("labeledIssues"), "Debe contener la métrica 'labeledIssues'"); + } + + // Test que intenta pedir una métrica que no existe, para comprobar que la excepción salta como se espera + + + @Test + void testInvalidMetricThrowsException() { + String repoId = "Isabel-Roman"; + + assertThrows(MetricException.class, () -> { + enquirer.getMetric("nonExistentMetric", repoId); + }); + } + + + // Test que verifica que el tipo de la clase está correctamente identificado como GITHUB + + @Test + void testGetRemoteType() { + assertEquals(RemoteEnquirer.RemoteType.GITHUB, enquirer.getRemoteType()); + } +} From 6db6759ca828852f8b862c44b34a6e22a53cb5e5 Mon Sep 17 00:00:00 2001 From: pedhidtap Date: Mon, 5 May 2025 17:33:17 +0200 Subject: [PATCH 2/8] Tests IndicatorStrategy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clase para la verificación del cáculo del indicador --- .../test/control/IndicatorStrategyTest.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java diff --git a/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java b/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java new file mode 100644 index 00000000..a6332e7f --- /dev/null +++ b/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java @@ -0,0 +1,58 @@ +package us.muit.fs.a4i.test.control; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.Arrays; +import java.util.List; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import us.muit.fs.a4i.control.GDIStrategy; +import us.muit.fs.a4i.control.IndicatorStrategy; +import us.muit.fs.a4i.exceptions.NotAvailableMetricException; +import us.muit.fs.a4i.model.entities.ReportItem; +import us.muit.fs.a4i.model.entities.ReportItemI; + +class IndicatorStrategyTest { + + @Test + @DisplayName("Test correcto del cálculo GDI con métricas válidas") + void testCalcIndicator_OK() throws NotAvailableMetricException { + IndicatorStrategy strategy = new GDIStrategy(); + + List> metrics = Arrays.asList( + new ReportItem<>("issues_total", 10.0), + new ReportItem<>("issues_etiquetados", 7.0) + ); + + ReportItemI result = strategy.calcIndicator(metrics); + assertEquals(70.0, result.getValue(), 0.001, "El cálculo del GDI es incorrecto"); + assertEquals("grado_documentacion_issues", result.getName(), "El nombre del resultado no es el esperado"); + } + + @Test + @DisplayName("Test de excepción cuando faltan métricas") + void testCalcIndicator_MissingMetrics() { + IndicatorStrategy strategy = new GDIStrategy(); + + List> metrics = List.of( + new ReportItem<>("issues_etiquetados", 7.0) + ); + + assertThrows(NotAvailableMetricException.class, () -> { + strategy.calcIndicator(metrics); + }, "Se esperaba una excepción por falta de métricas"); + } + + @Test + @DisplayName("Test de requiredMetrics() devuelve métricas necesarias") + void testRequiredMetrics() { + IndicatorStrategy strategy = new GDIStrategy(); + List required = strategy.requiredMetrics(); + + assertTrue(required.contains("issues_total")); + assertTrue(required.contains("issues_etiquetados")); + assertEquals(2, required.size(), "Se esperaban exactamente dos métricas"); + } +} From a9d8eb827f90d1a6b819f86dff196276f15ba57d Mon Sep 17 00:00:00 2001 From: pedhidtap Date: Mon, 5 May 2025 18:20:46 +0200 Subject: [PATCH 3/8] Tests IndicatorStrategy corregido --- .../test/control/IndicatorStrategyTest.java | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java b/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java index a6332e7f..19b224e2 100644 --- a/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java +++ b/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java @@ -2,29 +2,30 @@ import static org.junit.jupiter.api.Assertions.*; +import us.muit.fs.a4i.exceptions.NotAvailableMetricException; +import us.muit.fs.a4i.exceptions.ReportItemException; +import us.muit.fs.a4i.model.entities.ReportItem; +import us.muit.fs.a4i.model.entities.ReportItemI; +import us.muit.fs.a4i.control.GDIStrategy; +import us.muit.fs.a4i.control.IndicatorStrategy; + import java.util.Arrays; import java.util.List; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import us.muit.fs.a4i.control.GDIStrategy; -import us.muit.fs.a4i.control.IndicatorStrategy; -import us.muit.fs.a4i.exceptions.NotAvailableMetricException; -import us.muit.fs.a4i.model.entities.ReportItem; -import us.muit.fs.a4i.model.entities.ReportItemI; - class IndicatorStrategyTest { @Test @DisplayName("Test correcto del cálculo GDI con métricas válidas") - void testCalcIndicator_OK() throws NotAvailableMetricException { + void testCalcIndicator_OK() throws NotAvailableMetricException, ReportItemException { IndicatorStrategy strategy = new GDIStrategy(); - List> metrics = Arrays.asList( - new ReportItem<>("issues_total", 10.0), - new ReportItem<>("issues_etiquetados", 7.0) - ); + ReportItemI total = new ReportItem.ReportItemBuilder<>("issues_total", 10.0).build(); + ReportItemI etiquetados = new ReportItem.ReportItemBuilder<>("issues_etiquetados", 7.0).build(); + + List> metrics = Arrays.asList(total, etiquetados); ReportItemI result = strategy.calcIndicator(metrics); assertEquals(70.0, result.getValue(), 0.001, "El cálculo del GDI es incorrecto"); @@ -33,12 +34,12 @@ void testCalcIndicator_OK() throws NotAvailableMetricException { @Test @DisplayName("Test de excepción cuando faltan métricas") - void testCalcIndicator_MissingMetrics() { + void testCalcIndicator_MissingMetrics() throws ReportItemException { IndicatorStrategy strategy = new GDIStrategy(); - List> metrics = List.of( - new ReportItem<>("issues_etiquetados", 7.0) - ); + ReportItemI etiquetados = new ReportItem.ReportItemBuilder<>("issues_etiquetados", 7.0).build(); + + List> metrics = List.of(etiquetados); assertThrows(NotAvailableMetricException.class, () -> { strategy.calcIndicator(metrics); @@ -55,4 +56,4 @@ void testRequiredMetrics() { assertTrue(required.contains("issues_etiquetados")); assertEquals(2, required.size(), "Se esperaban exactamente dos métricas"); } -} +} \ No newline at end of file From f47151865ed5a7d5615f186794f24f0606c01340 Mon Sep 17 00:00:00 2001 From: javgarbor2 Date: Mon, 5 May 2025 19:30:04 +0200 Subject: [PATCH 4/8] =?UTF-8?q?Codificaci=C3=B3n=20GDIStrategy=20(Indicato?= =?UTF-8?q?rStrategy)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Codificación realizada con tests exitosos --- .../fs/a4i/config/IndicatorConfiguration.java | 1 + .../us/muit/fs/a4i/control/GDIStrategy.java | 55 +++++++++++++++++++ src/main/resources/a4iDefault.json | 25 +++++++++ 3 files changed, 81 insertions(+) create mode 100644 src/main/java/us/muit/fs/a4i/control/GDIStrategy.java diff --git a/src/main/java/us/muit/fs/a4i/config/IndicatorConfiguration.java b/src/main/java/us/muit/fs/a4i/config/IndicatorConfiguration.java index 75b54f30..9730a9b5 100644 --- a/src/main/java/us/muit/fs/a4i/config/IndicatorConfiguration.java +++ b/src/main/java/us/muit/fs/a4i/config/IndicatorConfiguration.java @@ -122,6 +122,7 @@ private HashMap isDefinedIndicator(String indicatorName, String int warningLimit = 0; int criticalLimit = 0; + if (limits != null) { okLimit = limits.getInt("ok"); warningLimit = limits.getInt("warning"); diff --git a/src/main/java/us/muit/fs/a4i/control/GDIStrategy.java b/src/main/java/us/muit/fs/a4i/control/GDIStrategy.java new file mode 100644 index 00000000..f9367aa8 --- /dev/null +++ b/src/main/java/us/muit/fs/a4i/control/GDIStrategy.java @@ -0,0 +1,55 @@ +package us.muit.fs.a4i.control; + +import us.muit.fs.a4i.exceptions.NotAvailableMetricException; +import us.muit.fs.a4i.exceptions.ReportItemException; +import us.muit.fs.a4i.model.entities.ReportItem; +import us.muit.fs.a4i.model.entities.ReportItemI; + +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +public class GDIStrategy implements IndicatorStrategy { + + private static final String METRIC_TOTAL = "issues_total"; + private static final String METRIC_ETIQUETADOS = "issues_etiquetados"; + private static final String RESULT_NAME = "grado_documentacion_issues"; + + @Override + public ReportItemI calcIndicator(List> metrics) throws NotAvailableMetricException { + Optional> totalOpt = metrics.stream() + .filter(m -> METRIC_TOTAL.equals(m.getName())) + .findFirst(); + + Optional> etiquetadosOpt = metrics.stream() + .filter(m -> METRIC_ETIQUETADOS.equals(m.getName())) + .findFirst(); + + if (totalOpt.isEmpty() || etiquetadosOpt.isEmpty()) { + throw new NotAvailableMetricException("Faltan métricas necesarias para calcular el indicador."); + } + + double total = totalOpt.get().getValue(); + double etiquetados = etiquetadosOpt.get().getValue(); + + if (total == 0) { + throw new RuntimeException("El valor de 'issues_total' no puede ser cero."); + } + + double resultado = (etiquetados / total) * 100.0; + + try { + // Intentamos crear el ReportItem y si algo falla, envolvemos la excepción. + return new ReportItem.ReportItemBuilder<>(RESULT_NAME, resultado).build(); + } catch (ReportItemException e) { + // Envolvemos la ReportItemException en una RuntimeException + throw new RuntimeException("Error al crear el ReportItem: " + e.getMessage(), e); + } + } + + + @Override + public List requiredMetrics() { + return Arrays.asList(METRIC_TOTAL, METRIC_ETIQUETADOS); + } +} diff --git a/src/main/resources/a4iDefault.json b/src/main/resources/a4iDefault.json index 33cee922..b7244873 100644 --- a/src/main/resources/a4iDefault.json +++ b/src/main/resources/a4iDefault.json @@ -90,6 +90,20 @@ "description": "Numero de issues abiertas", "unit": "issues" }, + { + "name": "issues_total", + "type": "java.lang.Double", + "description": "Número de issues totales", + "unit": "issues" + + }, + { + "name": "issues_etiquetados", + "type": "java.lang.Double", + "description": "Número de issues etiquetados", + "unit": "issues" + + }, { "name": "openProjects", "type": "java.lang.Integer", @@ -275,6 +289,17 @@ "critical": 25 } }, + { + "name": "grado_documentacion_issues", + "type": "java.lang.Double", + "description": "% Issues etiquetados frente a totales", + "unit": "%", + "limits": { + "ok": 71, + "warning": 51, + "critical": 31 + } + }, { "name": "developerPerfomance", "type": "java.lang.Double", From e15fd16adef2d28039e7a6c4b57e0ed3d34afe88 Mon Sep 17 00:00:00 2001 From: pedhidtap Date: Tue, 6 May 2025 17:31:33 +0200 Subject: [PATCH 5/8] Codigo de la clase ExtraccionMetricas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Se ha desarrollado el código que implementa la interfaz de RemoteEnquirer y se ha verificado como efectivamente pasan los tests. Además se ha indicado el repositorio de la asignatura en RemoteEnquirerTest, en lugar del que venía, para obtener varios issues que medir. --- .../a4i/model/remote/ExtraccionMetricas.java | 104 ++++++++++++++++++ src/main/resources/a4iDefault.json | 10 +- .../test/model/remote/RemoteEnquirerTest.java | 5 +- 3 files changed, 115 insertions(+), 4 deletions(-) create mode 100644 src/main/java/us/muit/fs/a4i/model/remote/ExtraccionMetricas.java diff --git a/src/main/java/us/muit/fs/a4i/model/remote/ExtraccionMetricas.java b/src/main/java/us/muit/fs/a4i/model/remote/ExtraccionMetricas.java new file mode 100644 index 00000000..fa46906a --- /dev/null +++ b/src/main/java/us/muit/fs/a4i/model/remote/ExtraccionMetricas.java @@ -0,0 +1,104 @@ +package us.muit.fs.a4i.model.remote; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +import org.kohsuke.github.GHIssue; +import org.kohsuke.github.GHRepository; +import org.kohsuke.github.GitHub; +import org.kohsuke.github.GitHubBuilder; + +import us.muit.fs.a4i.exceptions.MetricException; +import us.muit.fs.a4i.model.entities.ReportItemI; +import us.muit.fs.a4i.model.entities.ReportItem.ReportItemBuilder; +import us.muit.fs.a4i.model.entities.Report; +import us.muit.fs.a4i.model.entities.ReportI; + + +public class ExtraccionMetricas implements RemoteEnquirer { + + private static final List SUPPORTED_METRICS = Arrays.asList("totalIssues", "labeledIssues"); + + @Override + public ReportI buildReport(String entityId) { + try { + Report report = new Report(ReportI.ReportType.REPOSITORY, entityId); + + for (String metric : getAvailableMetrics()) { + ReportItemI item = getMetric(metric, entityId); + report.addMetric(item); + } + + return report; + + } catch (MetricException e) { + throw new RuntimeException("Error al construir el informe: " + e.getMessage(), e); + } + } + + @Override + public ReportItemI getMetric(String metricName, String entityId) throws MetricException { + if (!SUPPORTED_METRICS.contains(metricName)) { + throw new MetricException("Métrica no soportada: " + metricName); + } + + if (!entityId.contains("/")) { + entityId = entityId + "/Audit4Improve-API"; + } + + try { + GitHub github; + String token = System.getenv("GITHUB_PACKAGES"); + + if (token != null && !token.isEmpty()) { + github = new GitHubBuilder().withOAuthToken(token).build(); + } else { + github = GitHub.connectAnonymously(); + } + GHRepository repo = github.getRepository(entityId); + + int total = 0; + int etiquetados = 0; + + for (GHIssue issue : repo.getIssues(org.kohsuke.github.GHIssueState.OPEN)) { + if (!issue.isPullRequest()) { + total++; + if (!issue.getLabels().isEmpty()) { + etiquetados++; + } + } + } + + if (metricName.equals("totalIssues")) { + return new ReportItemBuilder("totalIssues", (double) total) + .source("GitHub") + .build(); + } else if (metricName.equals("labeledIssues")) { + return new ReportItemBuilder("labeledIssues", (double) etiquetados) + .source("GitHub") + .build(); + } else { + throw new MetricException("Métrica desconocida: " + metricName); + } + + } catch (IOException e) { + System.err.println("IOException: " + e.getMessage()); + throw new MetricException("Error al conectar con GitHub: " + e.getMessage()); + } catch (Exception e) { + System.err.println("Exception: " + e.getMessage()); + throw new MetricException("Error al construir ReportItem: " + e.getMessage()); + } + } + + @Override + public List getAvailableMetrics() { + return SUPPORTED_METRICS; + } + + @Override + public RemoteType getRemoteType() { + return RemoteType.GITHUB; + } + +} diff --git a/src/main/resources/a4iDefault.json b/src/main/resources/a4iDefault.json index 33cee922..74c12037 100644 --- a/src/main/resources/a4iDefault.json +++ b/src/main/resources/a4iDefault.json @@ -127,8 +127,8 @@ "unit": "issues" }, { - "name": "issues", - "type": "java.lang.Integer", + "name": "totalIssues", + "type": "java.lang.Double", "description": "Tareas totales", "unit": "issues" }, @@ -298,6 +298,12 @@ "description": "Indicador de conformidad con las convenciones en el repo", "unit": "ratio" }, + { + "name": "labeledIssues", + "type": "java.lang.Double", + "description": "Número de issues con al menos una etiqueta", + "unit": "issues" + }, { "name": "teamsBalanceI", "type": "java.lang.Double", diff --git a/src/test/java/us/muit/fs/a4i/test/model/remote/RemoteEnquirerTest.java b/src/test/java/us/muit/fs/a4i/test/model/remote/RemoteEnquirerTest.java index 5deb82da..46a909c7 100644 --- a/src/test/java/us/muit/fs/a4i/test/model/remote/RemoteEnquirerTest.java +++ b/src/test/java/us/muit/fs/a4i/test/model/remote/RemoteEnquirerTest.java @@ -11,6 +11,7 @@ import us.muit.fs.a4i.exceptions.MetricException; import us.muit.fs.a4i.model.entities.ReportItem; import us.muit.fs.a4i.model.entities.ReportItemI; +import us.muit.fs.a4i.model.remote.ExtraccionMetricas; import us.muit.fs.a4i.model.remote.GitHubRepositoryEnquirer; import us.muit.fs.a4i.model.remote.RemoteEnquirer; @@ -26,7 +27,7 @@ class RemoteEnquirerTest { @Test void testGetTotalIssuesMetric() throws MetricException { - String repoId = "Isabel-Roman"; // Reemplazar con un repositorio válido de prueba + String repoId = "MIT-FS"; // Reemplazar con un repositorio válido de prueba ReportItemI metric = enquirer.getMetric("totalIssues", repoId); assertNotNull(metric, "La métrica 'totalIssues' no debe ser null"); @@ -41,7 +42,7 @@ void testGetTotalIssuesMetric() throws MetricException { @Test void testGetLabeledIssuesMetric() throws MetricException { - String repoId = "Isabel-Roman"; // Reemplazar con un repositorio válido de prueba + String repoId = "MIT-FS"; ReportItemI metric = enquirer.getMetric("labeledIssues", repoId); assertNotNull(metric, "La métrica 'labeledIssues' no debe ser null"); From 08fdb762b591ee1d970e8970a15b65017aaec41d Mon Sep 17 00:00:00 2001 From: serramric Date: Fri, 8 May 2026 18:35:14 +0200 Subject: [PATCH 6/8] =?UTF-8?q?Arreglando=20errores=20y=20a=C3=B1adiendo?= =?UTF-8?q?=20tests=20a=20los=20issues=20propuestos=20para=20el=20grupo=20?= =?UTF-8?q?8...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fs/a4i/config/IndicatorConfiguration.java | 3 ++- .../a4i/model/remote/ExtraccionMetricas.java | 8 ++++-- .../test/model/remote/RemoteEnquirerTest.java | 27 +++++++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/main/java/us/muit/fs/a4i/config/IndicatorConfiguration.java b/src/main/java/us/muit/fs/a4i/config/IndicatorConfiguration.java index 9730a9b5..ab9ce0ed 100644 --- a/src/main/java/us/muit/fs/a4i/config/IndicatorConfiguration.java +++ b/src/main/java/us/muit/fs/a4i/config/IndicatorConfiguration.java @@ -1,6 +1,7 @@ /** - * + * Código revisado por Sergio Ramírez. */ + package us.muit.fs.a4i.config; import java.io.FileInputStream; diff --git a/src/main/java/us/muit/fs/a4i/model/remote/ExtraccionMetricas.java b/src/main/java/us/muit/fs/a4i/model/remote/ExtraccionMetricas.java index fa46906a..ad56f7c3 100644 --- a/src/main/java/us/muit/fs/a4i/model/remote/ExtraccionMetricas.java +++ b/src/main/java/us/muit/fs/a4i/model/remote/ExtraccionMetricas.java @@ -1,3 +1,7 @@ +/** + * Código revisado por Sergio Ramírez. + */ + package us.muit.fs.a4i.model.remote; import java.io.IOException; @@ -43,8 +47,8 @@ public ReportItemI getMetric(String metricName, String entityId) throws MetricEx throw new MetricException("Métrica no soportada: " + metricName); } - if (!entityId.contains("/")) { - entityId = entityId + "/Audit4Improve-API"; + if (entityId == null || entityId.isBlank() || !entityId.contains("/")) { + throw new MetricException("El identificador del repositorio debe tener formato owner/repository"); } try { diff --git a/src/test/java/us/muit/fs/a4i/test/model/remote/RemoteEnquirerTest.java b/src/test/java/us/muit/fs/a4i/test/model/remote/RemoteEnquirerTest.java index 46a909c7..61b68bd0 100644 --- a/src/test/java/us/muit/fs/a4i/test/model/remote/RemoteEnquirerTest.java +++ b/src/test/java/us/muit/fs/a4i/test/model/remote/RemoteEnquirerTest.java @@ -1,3 +1,7 @@ +/** + * Código revisado por Sergio Ramírez. + */ + package us.muit.fs.a4i.test.model.remote; import static org.junit.jupiter.api.Assertions.*; @@ -83,4 +87,27 @@ void testInvalidMetricThrowsException() { void testGetRemoteType() { assertEquals(RemoteEnquirer.RemoteType.GITHUB, enquirer.getRemoteType()); } + + // Test sencillo que comprueba que la lista de métricas disponibles no está vacía. + // Este test no depende de conexión a GitHub, por lo que es estable y rápido. + + @Test + void testAvailableMetricsIsNotEmpty() { + List metrics = enquirer.getAvailableMetrics(); + + assertNotNull(metrics, "La lista de métricas disponibles no debe ser null"); + assertFalse(metrics.isEmpty(), "La lista de métricas disponibles no debe estar vacía"); + } + + // Test que comprueba que una métrica con nombre null se rechaza correctamente. + // No se realiza conexión a GitHub porque la validación de la métrica se hace antes. + + @Test + void testNullMetricNameThrowsException() { + String repoId = "MIT-FS"; + + assertThrows(MetricException.class, () -> { + enquirer.getMetric(null, repoId); + }, "Solicitar una métrica null debe lanzar MetricException"); + } } From 2f0501054157d4f967cb3971e8085f715828c0a7 Mon Sep 17 00:00:00 2001 From: sermunagu Date: Fri, 8 May 2026 18:36:37 +0200 Subject: [PATCH 7/8] Verificar y corregir GDIStrategy --- .../us/muit/fs/a4i/control/GDIStrategy.java | 30 +++++++++--- src/main/resources/a4iDefault.json | 17 ++----- .../test/control/IndicatorStrategyTest.java | 46 +++++++++++++++---- 3 files changed, 64 insertions(+), 29 deletions(-) diff --git a/src/main/java/us/muit/fs/a4i/control/GDIStrategy.java b/src/main/java/us/muit/fs/a4i/control/GDIStrategy.java index f9367aa8..98e9fe45 100644 --- a/src/main/java/us/muit/fs/a4i/control/GDIStrategy.java +++ b/src/main/java/us/muit/fs/a4i/control/GDIStrategy.java @@ -11,13 +11,17 @@ public class GDIStrategy implements IndicatorStrategy { - private static final String METRIC_TOTAL = "issues_total"; - private static final String METRIC_ETIQUETADOS = "issues_etiquetados"; + private static final String METRIC_TOTAL = "totalIssues"; + private static final String METRIC_ETIQUETADOS = "labeledIssues"; private static final String RESULT_NAME = "grado_documentacion_issues"; @Override public ReportItemI calcIndicator(List> metrics) throws NotAvailableMetricException { - Optional> totalOpt = metrics.stream() + if (metrics == null) { + throw new NotAvailableMetricException("No se han proporcionado métricas."); + } + + Optional> totalOpt = metrics.stream() .filter(m -> METRIC_TOTAL.equals(m.getName())) .findFirst(); @@ -26,16 +30,30 @@ public ReportItemI calcIndicator(List> metrics) thro .findFirst(); if (totalOpt.isEmpty() || etiquetadosOpt.isEmpty()) { - throw new NotAvailableMetricException("Faltan métricas necesarias para calcular el indicador."); + throw new NotAvailableMetricException("Faltan métricas necesarias para calcular el indicador GDI."); } double total = totalOpt.get().getValue(); double etiquetados = etiquetadosOpt.get().getValue(); - if (total == 0) { - throw new RuntimeException("El valor de 'issues_total' no puede ser cero."); + if (total <= 0) { + throw new IllegalArgumentException( + "El valor de 'totalIssues' debe ser mayor que cero." + ); + } + + if (etiquetados < 0) { + throw new IllegalArgumentException( + "El valor de 'labeledIssues' no puede ser negativo." + ); } + if (etiquetados > total) { + throw new IllegalArgumentException( + "El número de labeledIssues no puede superar el número totalIssues." + ); + } + double resultado = (etiquetados / total) * 100.0; try { diff --git a/src/main/resources/a4iDefault.json b/src/main/resources/a4iDefault.json index f7f34308..0425280a 100644 --- a/src/main/resources/a4iDefault.json +++ b/src/main/resources/a4iDefault.json @@ -90,15 +90,9 @@ "description": "Numero de issues abiertas", "unit": "issues" }, + { - "name": "issues_total", - "type": "java.lang.Double", - "description": "Número de issues totales", - "unit": "issues" - - }, - { - "name": "issues_etiquetados", + "name": "labeledIssues", "type": "java.lang.Double", "description": "Número de issues etiquetados", "unit": "issues" @@ -323,12 +317,7 @@ "description": "Indicador de conformidad con las convenciones en el repo", "unit": "ratio" }, - { - "name": "labeledIssues", - "type": "java.lang.Double", - "description": "Número de issues con al menos una etiqueta", - "unit": "issues" - }, + { "name": "teamsBalanceI", "type": "java.lang.Double", diff --git a/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java b/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java index 19b224e2..eb1bbd1a 100644 --- a/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java +++ b/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java @@ -22,8 +22,8 @@ class IndicatorStrategyTest { void testCalcIndicator_OK() throws NotAvailableMetricException, ReportItemException { IndicatorStrategy strategy = new GDIStrategy(); - ReportItemI total = new ReportItem.ReportItemBuilder<>("issues_total", 10.0).build(); - ReportItemI etiquetados = new ReportItem.ReportItemBuilder<>("issues_etiquetados", 7.0).build(); + ReportItemI total = new ReportItem.ReportItemBuilder<>("totalIssues", 10.0).build(); + ReportItemI etiquetados = new ReportItem.ReportItemBuilder<>("labeledIssues", 7.0).build(); List> metrics = Arrays.asList(total, etiquetados); @@ -33,17 +33,45 @@ void testCalcIndicator_OK() throws NotAvailableMetricException, ReportItemExcept } @Test - @DisplayName("Test de excepción cuando faltan métricas") - void testCalcIndicator_MissingMetrics() throws ReportItemException { + @DisplayName("Test de excepción cuando falta la métrica totalIssues") + void testCalcIndicator_MissingTotalIssues() throws ReportItemException { IndicatorStrategy strategy = new GDIStrategy(); - ReportItemI etiquetados = new ReportItem.ReportItemBuilder<>("issues_etiquetados", 7.0).build(); - + ReportItemI etiquetados = new ReportItem.ReportItemBuilder<>("labeledIssues", 7.0).build(); List> metrics = List.of(etiquetados); assertThrows(NotAvailableMetricException.class, () -> { strategy.calcIndicator(metrics); - }, "Se esperaba una excepción por falta de métricas"); + }, "Se esperaba una excepción por falta de la métrica totalIssues"); + } + + @Test + @DisplayName("Test de excepción cuando falta la métrica labeledIssues") + void testCalcIndicator_MissingLabeledIssues() throws ReportItemException { + IndicatorStrategy strategy = new GDIStrategy(); + + ReportItemI total = new ReportItem.ReportItemBuilder<>("totalIssues", 10.0).build(); + List> metrics = List.of(total); + + assertThrows(NotAvailableMetricException.class, () -> { + strategy.calcIndicator(metrics); + }, "Se esperaba una excepción por falta de la métrica labeledIssues"); + } + + + @Test + @DisplayName("Test de excepción cuando totalIssues es cero") + void testCalcIndicator_TotalIssuesZero() throws ReportItemException { + IndicatorStrategy strategy = new GDIStrategy(); + + ReportItemI total = new ReportItem.ReportItemBuilder<>("totalIssues", 0.0).build(); + ReportItemI etiquetados = new ReportItem.ReportItemBuilder<>("labeledIssues", 0.0).build(); + + List> metrics = Arrays.asList(total, etiquetados); + + assertThrows(IllegalArgumentException.class, () -> { + strategy.calcIndicator(metrics); + }, "Se esperaba una excepción porque totalIssues no puede ser cero"); } @Test @@ -52,8 +80,8 @@ void testRequiredMetrics() { IndicatorStrategy strategy = new GDIStrategy(); List required = strategy.requiredMetrics(); - assertTrue(required.contains("issues_total")); - assertTrue(required.contains("issues_etiquetados")); + assertTrue(required.contains("totalIssues")); + assertTrue(required.contains("labeledIssues")); assertEquals(2, required.size(), "Se esperaban exactamente dos métricas"); } } \ No newline at end of file From d3042449262b68cb57cabe09c4d81fe15f187b73 Mon Sep 17 00:00:00 2001 From: sermunagu Date: Fri, 8 May 2026 18:54:18 +0200 Subject: [PATCH 8/8] Verificar y corregir RemoteEnquirerTest --- .DS_Store | Bin 6148 -> 0 bytes .github/.DS_Store | Bin 6148 -> 0 bytes .../test/model/remote/RemoteEnquirerTest.java | 8 ++++---- 3 files changed, 4 insertions(+), 4 deletions(-) delete mode 100644 .DS_Store delete mode 100644 .github/.DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 02d4679df041b60e79500e959a87e1246e8648a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK!EO^V5FNMMWh{SlFJ|XH6Q3z!W?x6XD@I32=Y&lC8DEJ#{ zQJ$$>D~!Kyto8=afM?);V}Q?YK#%BzGOAY3uR6=KvKkD2immNnXSWk}!oBcAe5x05 zl~nU`oXp(SG`9F7i_eOVt32Yq>XFj_9V;r)k?pTC-X&c77;-0~-I-59y+u!ReBeuwil zo)x(+PGIBpoi%;U6cn1ER z0lpt3lreJHSTt7$8dCxQ1DK7V&$R^mNQaTb#v*1Q!ny*jt8gWTut0nfl?2Da_6$M65ktLy*EPJZMW@C@8221IZiACD1| zds{bxpmEQ!>F`s$4>f{0$sJ(iu(1dW#Qza6H2B6daIFmd0@v=< Ad;kCd diff --git a/.github/.DS_Store b/.github/.DS_Store deleted file mode 100644 index 4d99cc801ae3ccfa5cfd4d7cd3ff299dbffb617a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK!A`tkpM16*=6gRV#99vpyQR&eH1o?osP5x{uY9o;nEp zRJAQw9K$mPQ>1wGdvT=V8yp=o#|%bRfE8c`W>f*YojIi$oj*^T6<`H^P665_!A{wf&C5A9`?3XsrvzQq)bP%@q5cbK! zRwzP09q%u7Itb4ox2ymw@Kph-{m{yE{vUi_|LY`fSOHexe<~mfO~2W|ce7{f#9Pu? uE732}$tW)~_(8!yAH|qUNAU`}Htd%aAbJ)vgV=+{KLT0?Zdid|Rp1?p3|kfe diff --git a/src/test/java/us/muit/fs/a4i/test/model/remote/RemoteEnquirerTest.java b/src/test/java/us/muit/fs/a4i/test/model/remote/RemoteEnquirerTest.java index 61b68bd0..cc382d42 100644 --- a/src/test/java/us/muit/fs/a4i/test/model/remote/RemoteEnquirerTest.java +++ b/src/test/java/us/muit/fs/a4i/test/model/remote/RemoteEnquirerTest.java @@ -31,7 +31,7 @@ class RemoteEnquirerTest { @Test void testGetTotalIssuesMetric() throws MetricException { - String repoId = "MIT-FS"; // Reemplazar con un repositorio válido de prueba + String repoId = "MIT-FS/Audit4Improve-API"; // Reemplazar con un repositorio válido de prueba ReportItemI metric = enquirer.getMetric("totalIssues", repoId); assertNotNull(metric, "La métrica 'totalIssues' no debe ser null"); @@ -46,7 +46,7 @@ void testGetTotalIssuesMetric() throws MetricException { @Test void testGetLabeledIssuesMetric() throws MetricException { - String repoId = "MIT-FS"; + String repoId = "MIT-FS/Audit4Improve-API"; ReportItemI metric = enquirer.getMetric("labeledIssues", repoId); assertNotNull(metric, "La métrica 'labeledIssues' no debe ser null"); @@ -73,7 +73,7 @@ void testGetAvailableMetrics() { @Test void testInvalidMetricThrowsException() { - String repoId = "Isabel-Roman"; + String repoId = "MIT-FS/Audit4Improve-API"; assertThrows(MetricException.class, () -> { enquirer.getMetric("nonExistentMetric", repoId); @@ -104,7 +104,7 @@ void testAvailableMetricsIsNotEmpty() { @Test void testNullMetricNameThrowsException() { - String repoId = "MIT-FS"; + String repoId = "MIT-FS/Audit4Improve-API"; assertThrows(MetricException.class, () -> { enquirer.getMetric(null, repoId);