>(
+ "totalLinesPerUserLastYear", linesPerUser);
+ totalLinesPerUserLastYearMetric.source("GitHub, calculada")
+ .description("Número de líneas modificadas por usuario en el último mes");
+ metric = totalLinesPerUserLastYearMetric.build();
+ } catch (IOException e) {
+ throw new MetricException("Error al consultar los líneas modificadas por usuario en el último año del repositorio");
+ } catch (ReportItemException e) {
+ throw new MetricException("Error al crear la métrica");
+ }
+ return metric;
+ }
+
// Metricas equipo 1 curso 23/24
/**
*
diff --git a/src/main/resources/a4iDefault.json b/src/main/resources/a4iDefault.json
index 33cee922..14b5fe48 100644
--- a/src/main/resources/a4iDefault.json
+++ b/src/main/resources/a4iDefault.json
@@ -233,7 +233,19 @@
"type": "java.lang.Integer",
"description": "Balance de equipos y open issues",
"unit": "ratio"
- }
+ },
+ {
+ "name": "totalCommitsPerUserLastYear",
+ "type": "java.util.HashMap",
+ "description": "Numero de commits creados por cada usuario en el ultimo año",
+ "unit": ""
+ },
+ {
+ "name": "totalLinesPerUserLastYear",
+ "type": "java.util.HashMap",
+ "description": "Numero de lineas modificadas por cada usuario en el ultimo año",
+ "unit": ""
+ }
],
"indicators": [
{
@@ -305,11 +317,17 @@
"unit": "ratio",
"limits": { "ok": 0.2, "warning": 0.6, "critical": 0.8 }
},
- {
+ {
"name": "fixTime",
"type": "java.lang.Double",
"description": "Tiempo para arreglos",
"unit": "ratio"
+ },
+ {
+ "name": "diversityOfContributions",
+ "type": "java.util.HashMap",
+ "description": "Diversidad de contribuciones de los usuarios en el ultimo año",
+ "unit": "ratio"
}
]
}
\ No newline at end of file
diff --git a/src/test/java/us/muit/fs/a4i/test/control/strategies/DiversityOfContributionsStrategyTest.java b/src/test/java/us/muit/fs/a4i/test/control/strategies/DiversityOfContributionsStrategyTest.java
new file mode 100644
index 00000000..8de9dab4
--- /dev/null
+++ b/src/test/java/us/muit/fs/a4i/test/control/strategies/DiversityOfContributionsStrategyTest.java
@@ -0,0 +1,165 @@
+package us.muit.fs.a4i.test.control.strategies;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import us.muit.fs.a4i.control.strategies.DiversityOfContributionsStrategy;
+import us.muit.fs.a4i.exceptions.NotAvailableMetricException;
+import us.muit.fs.a4i.model.entities.ReportItemI;
+
+class DiversityOfContributionsStrategyTest {
+
+ @Test
+ void testCalcIndicatorWithBalancedContributions() throws NotAvailableMetricException {
+ ReportItemI> commitsMetric = createMetric(
+ "totalCommitsPerUserLastYear",
+ mapOf("Antonio", 10.0, "Manolo", 10.0)
+ );
+
+ ReportItemI> linesMetric = createMetric(
+ "totalLinesPerUserLastYear",
+ mapOf("Antonio", 100.0, "Manolo", 100.0)
+ );
+
+ DiversityOfContributionsStrategy strategy = new DiversityOfContributionsStrategy();
+
+ ReportItemI> result = strategy.calcIndicator(Arrays.asList(commitsMetric, linesMetric));
+
+ Assertions.assertEquals("diversityOfContributions", result.getName());
+ Assertions.assertEquals(1.0, result.getValue().get("entropyValue"), 0.01);
+ }
+
+ @Test
+ void testCalcIndicatorWithUnbalancedContributions() throws NotAvailableMetricException {
+ ReportItemI> commitsMetric = createMetric(
+ "totalCommitsPerUserLastYear",
+ mapOf("Antonio", 200.0, "Manolo", 4.0)
+ );
+
+ ReportItemI> linesMetric = createMetric(
+ "totalLinesPerUserLastYear",
+ mapOf("Antonio", 10000.0, "Manolo", 10000.0)
+ );
+
+ DiversityOfContributionsStrategy strategy = new DiversityOfContributionsStrategy();
+
+ ReportItemI> result = strategy.calcIndicator(Arrays.asList(commitsMetric, linesMetric));
+
+ Assertions.assertEquals("diversityOfContributions", result.getName());
+ Assertions.assertEquals(0.822, result.getValue().get("entropyValue"), 0.01);
+ }
+
+ @Test
+ void testCalcIndicatorWithZeros() throws NotAvailableMetricException {
+ ReportItemI> commitsMetric = createMetric(
+ "totalCommitsPerUserLastYear",
+ mapOf("Antonio", 0.0, "Manolo", 0.0)
+ );
+
+ ReportItemI> linesMetric = createMetric(
+ "totalLinesPerUserLastYear",
+ mapOf("Antonio", 0.0, "Manolo", 0.0)
+ );
+
+ DiversityOfContributionsStrategy strategy = new DiversityOfContributionsStrategy();
+
+ ReportItemI> result = strategy.calcIndicator(Arrays.asList(commitsMetric, linesMetric));
+
+ Assertions.assertEquals("diversityOfContributions", result.getName());
+ Assertions.assertEquals(0.0, result.getValue().get("entropyValue"), 0.01);
+ }
+
+ @Test
+ void testCalcIndicatorWithOnlyOneUser() throws NotAvailableMetricException {
+ ReportItemI> commitsMetric = createMetric(
+ "totalCommitsPerUserLastYear",
+ mapOf("Antonio", 10.0)
+ );
+
+ ReportItemI> linesMetric = createMetric(
+ "totalLinesPerUserLastYear",
+ mapOf("Antonio", 100.0)
+ );
+
+ DiversityOfContributionsStrategy strategy = new DiversityOfContributionsStrategy();
+
+ ReportItemI> result = strategy.calcIndicator(Arrays.asList(commitsMetric, linesMetric));
+
+ Assertions.assertEquals("diversityOfContributions", result.getName());
+ Assertions.assertEquals(0.0, result.getValue().get("entropyValue"), 0.01);
+ }
+
+ @Test
+ void testCalcIndicatorWithDifferentUsersInMetrics() throws NotAvailableMetricException {
+ ReportItemI> commitsMetric = createMetric(
+ "totalCommitsPerUserLastYear",
+ mapOf("Antonio", 10.0, "Manolo", 10.0)
+ );
+
+ ReportItemI> linesMetric = createMetric(
+ "totalLinesPerUserLastYear",
+ mapOf("Antonio", 100.0)
+ );
+
+ DiversityOfContributionsStrategy strategy = new DiversityOfContributionsStrategy();
+
+ Assertions.assertDoesNotThrow(() -> strategy.calcIndicator(Arrays.asList(commitsMetric, linesMetric)));
+
+ ReportItemI> result = strategy.calcIndicator(Arrays.asList(commitsMetric, linesMetric));
+
+ Assertions.assertEquals("diversityOfContributions", result.getName());
+ Assertions.assertFalse(Double.isNaN(result.getValue().get("entropyValue")));
+ Assertions.assertFalse(Double.isInfinite(result.getValue().get("entropyValue")));
+ }
+
+ @Test
+ void testCalcIndicatorThrowsNotAvailableMetricException() {
+ ReportItemI> commitsMetric = createMetric(
+ "totalCommitsPerUserLastYear",
+ mapOf("Antonio", 0.0)
+ );
+
+ DiversityOfContributionsStrategy strategy = new DiversityOfContributionsStrategy();
+
+ List>> metrics = Arrays.asList(commitsMetric);
+
+ Assertions.assertThrows(NotAvailableMetricException.class, () -> strategy.calcIndicator(metrics));
+ }
+
+ @Test
+ void testRequiredMetrics() {
+ DiversityOfContributionsStrategy strategy = new DiversityOfContributionsStrategy();
+
+ List requiredMetrics = strategy.requiredMetrics();
+
+ List expectedMetrics = Arrays.asList("totalCommitsPerUserLastYear", "totalLinesPerUserLastYear");
+ Assertions.assertEquals(expectedMetrics, requiredMetrics);
+ }
+
+ private ReportItemI> createMetric(String name, HashMap value) {
+ ReportItemI> metric = Mockito.mock(ReportItemI.class);
+
+ Mockito.when(metric.getName()).thenReturn(name);
+ Mockito.when(metric.getValue()).thenReturn(value);
+
+ return metric;
+ }
+
+ private HashMap mapOf(String user1, Double value1) {
+ HashMap map = new HashMap<>();
+ map.put(user1, value1);
+ return map;
+ }
+
+ private HashMap mapOf(String user1, Double value1, String user2, Double value2) {
+ HashMap map = new HashMap<>();
+ map.put(user1, value1);
+ map.put(user2, value2);
+ return map;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/us/muit/fs/a4i/test/model/remote/GitHubRepositoryEnquirerTest.java b/src/test/java/us/muit/fs/a4i/test/model/remote/GitHubRepositoryEnquirerTest.java
index c7969ae8..0ef6448d 100644
--- a/src/test/java/us/muit/fs/a4i/test/model/remote/GitHubRepositoryEnquirerTest.java
+++ b/src/test/java/us/muit/fs/a4i/test/model/remote/GitHubRepositoryEnquirerTest.java
@@ -7,9 +7,13 @@
import java.util.List;
import java.util.logging.Logger;
+import java.util.HashMap;
+import java.util.Map;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.function.Executable;
+
import us.muit.fs.a4i.exceptions.MetricException;
import us.muit.fs.a4i.exceptions.ReportItemException;
@@ -220,4 +224,87 @@ void testGetReport() {
assertNotNull(report,"No construye el informe");
log.info("Informe construido "+report.toString());
}
+
+
+ // Test realizados por le equipo 13 curso 25/25
+ /**
+ * @throws MetricException
+ */
+ @Test
+ void testGetTotalCommitsPerUserLastYear() throws MetricException {
+
+ // Nombre de la métrica que queremos consultar
+ String nombreMetrica = "totalCommitsPerUserLastYear";
+
+ // Repositorio del que se quiere obtener la métrica
+ String repositoryId = "MIT-FS/Audit4Improve-API";
+
+ // Variable para almacenar el número de commits totales realizados en el último mes
+ ReportItem> totalCommitsPerUserLastYear = null;
+ // Creamos el RemoteEnquirer para el repositorio GitHub
+ GitHubRepositoryEnquirer enquirer = new GitHubRepositoryEnquirer();
+
+ // Obtenemos el número de commits en el último mes
+ totalCommitsPerUserLastYear = enquirer.getMetric(nombreMetrica, repositoryId);
+
+ // Comprobaciones:
+ // 1. El valor de la métrica no es nulo
+ assertNotNull(totalCommitsPerUserLastYear , "Getting total commits per user failed: reportItem is null");
+
+ // COMENTARIO DE REVISIÓN: La aserción 'instanceof HashMap' es correcta y oportuna para asegurar que el enquirer
+ // no ha degradado el tipo dinámico de la colección (por ejemplo, pasándolo a una lista o un mapa inmutable genérico),
+ // garantizando que el consumidor de la API reciba la estructura exacta que requiere el indicador.
+ // 2. El valor de la métrica es un hashmap con los usuarios y sus commits
+ assertTrue(totalCommitsPerUserLastYear.getValue() instanceof HashMap, "Getting total commits per user failed: value is not an HahMap");
+
+ // COMENTARIO DE REVISIÓN: El bucle de validación incremental es un acierto de diseño. Al comprobar 'entry.getValue() >= 0'
+ // mediante un tipo 'Double' explícito, se verifica que la métrica de actividad no contenga valores erróneos o negativos,
+ // respetando la semántica del indicador matemático de contribuciones.
+ // 3. El valor de la métrica es mayor o igual que 0
+ for (Map.Entry entry : totalCommitsPerUserLastYear.getValue().entrySet()) {
+ assertTrue(entry.getValue() >= 0,
+ "Getting total commits per user failed: value is less than 0 for user " + entry.getKey());
+ }
+ }
+
+ /**
+ * @throws MetricException
+ */
+ @Test
+ void testGetTotalLinesPerUserLastYear() throws MetricException {
+
+ // Nombre de la métrica que queremos consultar
+ String nombreMetrica = "totalLinesPerUserLastYear";
+
+ // Repositorio del que se quiere obtener la métrica
+ String repositoryId = "MIT-FS/Audit4Improve-API";
+
+ // Variable para almacenar el número de commits totales realizados en el último mes
+ ReportItem> testGetTotalLinesPerUserLastYear = null;
+
+ // Creamos el RemoteEnquirer para el repositorio GitHub
+ GitHubRepositoryEnquirer enquirer = new GitHubRepositoryEnquirer();
+
+ // Obtenemos el número de commits en el último mes
+ testGetTotalLinesPerUserLastYear = enquirer.getMetric(nombreMetrica, repositoryId);
+
+ // Comprobaciones:
+ // 1. El valor de la métrica no es nulo
+ assertNotNull(testGetTotalLinesPerUserLastYear , "Getting total lines per user failed: reportItem is null");
+
+ // COMENTARIO DE REVISIÓN: El test valida correctamente el contrato de la firma. Al exigir un 'HashMap' con valores
+ // 'Double', se amarra el comportamiento del enquirer para que la recolección de volumen de líneas modificadas sea
+ // compatible de forma transparente con los algoritmos matemáticos de diversidad de aportaciones del modelo.
+ // 2. El valor de la métrica es un hashmap con los usuarios y sus commits
+ assertTrue(testGetTotalLinesPerUserLastYear.getValue() instanceof HashMap, "Getting total lines per user failed: value is not an HashMap");
+
+ // COMENTARIO DE REVISIÓN: La verificación por cada elemento de la colección asegura que la métrica es robusta.
+ // Aunque un usuario elimine más líneas de las que añada, el total de líneas modificadas acumuladas (additions + deletions)
+ // debe ser estrictamente positivo o cero, por lo que evaluar que el valor sea '>= 0' es lógicamente impecable.
+ // 3. El valor de la métrica es mayor o igual que 0
+ for (Map.Entry entry : testGetTotalLinesPerUserLastYear.getValue().entrySet()) {
+ assertTrue(entry.getValue() >= 0,
+ "Getting total lines per user failed: value is less than 0 for user " + entry.getKey());
+ }
+ }
}
diff --git a/src/test/resources/excelTest.xlsx b/src/test/resources/excelTest.xlsx
index b7300c1b..7a0ff641 100644
Binary files a/src/test/resources/excelTest.xlsx and b/src/test/resources/excelTest.xlsx differ