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", 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..19b224e2 --- /dev/null +++ b/src/test/java/us/muit/fs/a4i/test/control/IndicatorStrategyTest.java @@ -0,0 +1,59 @@ +package us.muit.fs.a4i.test.control; + +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; + +class IndicatorStrategyTest { + + @Test + @DisplayName("Test correcto del cálculo GDI con métricas válidas") + 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(); + + 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"); + 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() throws ReportItemException { + IndicatorStrategy strategy = new GDIStrategy(); + + ReportItemI etiquetados = new ReportItem.ReportItemBuilder<>("issues_etiquetados", 7.0).build(); + + List> metrics = List.of(etiquetados); + + 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"); + } +} \ No newline at end of file