diff --git a/pom.xml b/pom.xml
index 03b1c9b..c5f4dd4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -19,9 +19,10 @@
17
17
17
- elysium
- elysium
- http://localhost:9000
+ ander-ECI
+ Prometeo-Back
+ Prometeo-Back
+ https://sonarcloud.io
target/site/jacoco/jacoco.xml
src//configurators/*
2024.0.1
diff --git a/src/test/java/edu/eci/cvds/prometeo/controller/UserControllerTest.java b/src/test/java/edu/eci/cvds/prometeo/controller/UserControllerTest.java
index abf2d44..8868723 100644
--- a/src/test/java/edu/eci/cvds/prometeo/controller/UserControllerTest.java
+++ b/src/test/java/edu/eci/cvds/prometeo/controller/UserControllerTest.java
@@ -2,6 +2,7 @@
import edu.eci.cvds.prometeo.dto.*;
import edu.eci.cvds.prometeo.model.*;
+import edu.eci.cvds.prometeo.model.enums.ReportFormat;
import edu.eci.cvds.prometeo.repository.RoutineExerciseRepository;
import edu.eci.cvds.prometeo.repository.RoutineRepository;
import edu.eci.cvds.prometeo.service.*;
@@ -12,7 +13,9 @@
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import java.time.LocalDate;
import java.time.LocalDateTime;
@@ -47,6 +50,9 @@ class UserControllerTest {
@Mock
private GymSessionService gymSessionService;
+ @Mock
+ private ReportService reportService;
+
@InjectMocks
private UserController userController;
@@ -1432,4 +1438,105 @@ public void testLambdaCreateCustomRoutine() {
// Verify the lambda did the transformation correctly
verify(userService).createCustomRoutine(eq(userId), any(Routine.class));
}
+
+ @Test
+ public void testGetUserProgressReport() {
+ // Prepare test data
+ UUID userId = UUID.randomUUID();
+ ReportFormat format = ReportFormat.PDF;
+ byte[] mockReportData = "mock report data".getBytes();
+
+ when(reportService.generateUserProgressReport(userId, format)).thenReturn(mockReportData);
+
+ ResponseEntity response = userController.getUserProgressReport(userId, format);
+
+ assertEquals(HttpStatus.OK, response.getStatusCode());
+ assertEquals(mockReportData, response.getBody());
+
+ // Verify the correct content type is set for PDF
+ HttpHeaders headers = response.getHeaders();
+ assertEquals(MediaType.APPLICATION_PDF, headers.getContentType());
+ assertTrue(headers.getContentDisposition().toString().contains("attachment"));
+ assertTrue(headers.getContentDisposition().toString().contains("user_progress_report.pdf"));
+
+ verify(reportService).generateUserProgressReport(userId, format);
+ }
+
+ @Test
+ public void testGetGymUsageReport() {
+ // Prepare test data
+ LocalDate startDate = LocalDate.now().minusMonths(1);
+ LocalDate endDate = LocalDate.now();
+ ReportFormat format = ReportFormat.XLSX;
+ byte[] mockReportData = "mock gym usage report data".getBytes();
+
+ when(reportService.generateGymUsageReport(startDate, endDate, format)).thenReturn(mockReportData);
+
+ ResponseEntity response = userController.getGymUsageReport(startDate, endDate, format);
+
+ assertEquals(HttpStatus.OK, response.getStatusCode());
+ assertEquals(mockReportData, response.getBody());
+
+ // Verify the correct content type is set for XLSX
+ HttpHeaders headers = response.getHeaders();
+ assertEquals(MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"),
+ headers.getContentType());
+ assertTrue(headers.getContentDisposition().toString().contains("attachment"));
+ assertTrue(headers.getContentDisposition().toString().contains("gym_usage_report.xlsx"));
+
+ verify(reportService).generateGymUsageReport(startDate, endDate, format);
+ }
+
+ @Test
+ public void testGetAttendanceReport() {
+ // Prepare test data
+ LocalDate startDate = LocalDate.now().minusMonths(1);
+ LocalDate endDate = LocalDate.now();
+ ReportFormat format = ReportFormat.CSV;
+ byte[] mockReportData = "date,attendance\n2023-01-01,42".getBytes();
+
+ when(reportService.getAttendanceStatistics(startDate, endDate, format)).thenReturn(mockReportData);
+
+ ResponseEntity response = userController.getAttendanceReport(startDate, endDate, format);
+
+ assertEquals(HttpStatus.OK, response.getStatusCode());
+ assertEquals(mockReportData, response.getBody());
+
+ // Verify the correct content type is set for CSV
+ HttpHeaders headers = response.getHeaders();
+ assertEquals(MediaType.parseMediaType("text/csv"), headers.getContentType());
+ assertTrue(headers.getContentDisposition().toString().contains("attachment"));
+ assertTrue(headers.getContentDisposition().toString().contains("attendance_report.csv"));
+
+ verify(reportService).getAttendanceStatistics(startDate, endDate, format);
+ }
+
+ @Test
+ public void testBuildResponseWithJSON() {
+ // Use reflection to access the private method
+ ReportFormat format = ReportFormat.JSON;
+ byte[] content = "{\"data\": \"test\"}".getBytes();
+ String filenameBase = "test_report";
+
+ // Create a method that directly invokes buildResponse using reflection
+ ResponseEntity response = null;
+ try {
+ java.lang.reflect.Method buildResponseMethod = UserController.class.getDeclaredMethod(
+ "buildResponse", byte[].class, ReportFormat.class, String.class);
+ buildResponseMethod.setAccessible(true);
+ response = (ResponseEntity) buildResponseMethod.invoke(userController, content, format, filenameBase);
+ } catch (Exception e) {
+ fail("Failed to invoke buildResponse method: " + e.getMessage());
+ }
+
+ assertNotNull(response);
+ assertEquals(HttpStatus.OK, response.getStatusCode());
+ assertEquals(content, response.getBody());
+
+ // Verify JSON content type
+ HttpHeaders headers = response.getHeaders();
+ assertEquals(MediaType.APPLICATION_JSON, headers.getContentType());
+ assertTrue(headers.getContentDisposition().toString().contains("attachment"));
+ assertTrue(headers.getContentDisposition().toString().contains("test_report.json"));
+ }
}
\ No newline at end of file
diff --git a/src/test/java/edu/eci/cvds/prometeo/model/enums/ReportFormatTest.java b/src/test/java/edu/eci/cvds/prometeo/model/enums/ReportFormatTest.java
new file mode 100644
index 0000000..ac2ed56
--- /dev/null
+++ b/src/test/java/edu/eci/cvds/prometeo/model/enums/ReportFormatTest.java
@@ -0,0 +1,41 @@
+package edu.eci.cvds.prometeo.model.enums;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+
+public class ReportFormatTest {
+
+ @Test
+ public void testEnumValues() {
+ // Test that the enum has the expected number of values
+ assertEquals(4, ReportFormat.values().length);
+
+ // Test that each expected value exists
+ assertNotNull(ReportFormat.CSV);
+ assertNotNull(ReportFormat.PDF);
+ assertNotNull(ReportFormat.XLSX);
+ assertNotNull(ReportFormat.JSON);
+ }
+
+ @Test
+ public void testValueOf() {
+ // Test that valueOf returns the correct enum value for each expected string
+ assertEquals(ReportFormat.CSV, ReportFormat.valueOf("CSV"));
+ assertEquals(ReportFormat.PDF, ReportFormat.valueOf("PDF"));
+ assertEquals(ReportFormat.XLSX, ReportFormat.valueOf("XLSX"));
+ assertEquals(ReportFormat.JSON, ReportFormat.valueOf("JSON"));
+ }
+
+
+ @Test
+ public void testEnumValuesContent() {
+ // Test that values() returns all expected values
+ ReportFormat[] formats = ReportFormat.values();
+
+ assertEquals(ReportFormat.CSV, formats[0]);
+ assertEquals(ReportFormat.PDF, formats[1]);
+ assertEquals(ReportFormat.XLSX, formats[2]);
+ assertEquals(ReportFormat.JSON, formats[3]);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/edu/eci/cvds/prometeo/service/impl/ReportServiceImplTest.java b/src/test/java/edu/eci/cvds/prometeo/service/impl/ReportServiceImplTest.java
new file mode 100644
index 0000000..a5abfe6
--- /dev/null
+++ b/src/test/java/edu/eci/cvds/prometeo/service/impl/ReportServiceImplTest.java
@@ -0,0 +1,409 @@
+package edu.eci.cvds.prometeo.service.impl;
+
+import edu.eci.cvds.prometeo.model.GymSession;
+import edu.eci.cvds.prometeo.model.PhysicalProgress;
+import edu.eci.cvds.prometeo.model.Weight;
+import edu.eci.cvds.prometeo.model.enums.ReportFormat;
+import edu.eci.cvds.prometeo.repository.GymSessionRepository;
+import edu.eci.cvds.prometeo.repository.PhysicalProgressRepository;
+import edu.eci.cvds.prometeo.service.report.ReportGenerator;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.test.util.ReflectionTestUtils;
+import java.io.IOException;
+import java.time.Duration;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+
+
+
+
+
+@ExtendWith(MockitoExtension.class)
+public class ReportServiceImplTest {
+
+ @Mock
+ private PhysicalProgressRepository physicalProgressRepository;
+
+ @Mock
+ private GymSessionRepository gymSessionRepository;
+
+ @Mock
+ private ReportGenerator reportGeneratorMock;
+
+ @InjectMocks
+ private ReportServiceImpl reportService;
+
+ @BeforeEach
+ void setUp() {
+ // Set the mocked ReportGenerator to the reportService
+ ReflectionTestUtils.setField(reportService, "reportGenerator", reportGeneratorMock);
+ }
+
+ @Test
+ void testGenerateUserProgressReport() throws IOException {
+ // Arrange
+ UUID userId = UUID.randomUUID();
+ ReportFormat format = ReportFormat.PDF;
+
+ PhysicalProgress progress1 = createTestProgress(userId, LocalDate.of(2023, 6, 1), 75.0, "Lose weight");
+ PhysicalProgress progress2 = createTestProgress(userId, LocalDate.of(2023, 6, 15), 73.5, "Gain muscle");
+ List progressList = Arrays.asList(progress1, progress2);
+
+ when(physicalProgressRepository.findByUserIdOrderByRecordDateDesc(userId)).thenReturn(progressList);
+
+ byte[] expectedReport = "PDF report content".getBytes();
+ when(reportGeneratorMock.generatePDF(eq(progressList), anyString(), any())).thenReturn(expectedReport);
+
+ // Act
+ byte[] result = reportService.generateUserProgressReport(userId, format);
+
+ // Assert
+ assertArrayEquals(expectedReport, result);
+ verify(physicalProgressRepository).findByUserIdOrderByRecordDateDesc(userId);
+ verify(reportGeneratorMock).generatePDF(eq(progressList), anyString(), any());
+ }
+
+ @Test
+ void testGenerateUserProgressReportWithXLSXFormat() throws IOException {
+ // Arrange
+ UUID userId = UUID.randomUUID();
+ ReportFormat format = ReportFormat.XLSX;
+
+ List progressList = Collections.emptyList();
+ when(physicalProgressRepository.findByUserIdOrderByRecordDateDesc(userId)).thenReturn(progressList);
+
+ byte[] expectedReport = "XLSX report content".getBytes();
+ when(reportGeneratorMock.generateXLSX(eq(progressList), anyList(), any())).thenReturn(expectedReport);
+
+ // Act
+ byte[] result = reportService.generateUserProgressReport(userId, format);
+
+ // Assert
+ assertArrayEquals(expectedReport, result);
+ verify(physicalProgressRepository).findByUserIdOrderByRecordDateDesc(userId);
+ verify(reportGeneratorMock).generateXLSX(eq(progressList), anyList(), any());
+ }
+
+ @Test
+ void testGenerateUserProgressReportThrowsException() throws IOException {
+ // Arrange
+ UUID userId = UUID.randomUUID();
+ ReportFormat format = ReportFormat.PDF;
+
+ List progressList = Collections.emptyList();
+ when(physicalProgressRepository.findByUserIdOrderByRecordDateDesc(userId)).thenReturn(progressList);
+
+ IOException ioException = new IOException("Test exception");
+ when(reportGeneratorMock.generatePDF(eq(progressList), anyString(), any())).thenThrow(ioException);
+
+ // Act & Assert
+ RuntimeException exception = assertThrows(RuntimeException.class,
+ () -> reportService.generateUserProgressReport(userId, format));
+
+ assertEquals("Error generando reporte en formato: " + format, exception.getMessage());
+ assertEquals(ioException, exception.getCause());
+ }
+
+ @Test
+ void testGenerateGymUsageReport() throws IOException {
+ // Arrange
+ LocalDate startDate = LocalDate.of(2023, 6, 1);
+ LocalDate endDate = LocalDate.of(2023, 6, 30);
+ ReportFormat format = ReportFormat.PDF;
+
+ GymSession session1 = createTestSession(LocalDate.of(2023, 6, 10), 20, 15, 60);
+ GymSession session2 = createTestSession(LocalDate.of(2023, 6, 20), 25, 20, 90);
+ List sessionList = Arrays.asList(session1, session2);
+
+ when(gymSessionRepository.findBySessionDateBetween(startDate, endDate)).thenReturn(sessionList);
+
+ byte[] expectedReport = "PDF report content".getBytes();
+ when(reportGeneratorMock.generatePDF(eq(sessionList), anyString(), any())).thenReturn(expectedReport);
+
+ // Act
+ byte[] result = reportService.generateGymUsageReport(startDate, endDate, format);
+
+ // Assert
+ assertArrayEquals(expectedReport, result);
+ verify(gymSessionRepository).findBySessionDateBetween(startDate, endDate);
+ verify(reportGeneratorMock).generatePDF(eq(sessionList), anyString(), any());
+ }
+
+ @Test
+ void testGenerateGymUsageReportWithJSONFormat() throws IOException {
+ // Arrange
+ LocalDate startDate = LocalDate.of(2023, 6, 1);
+ LocalDate endDate = LocalDate.of(2023, 6, 30);
+ ReportFormat format = ReportFormat.JSON;
+
+ List sessionList = Collections.emptyList();
+ when(gymSessionRepository.findBySessionDateBetween(startDate, endDate)).thenReturn(sessionList);
+
+ byte[] expectedReport = "JSON report content".getBytes();
+ when(reportGeneratorMock.generateJSON(anyList())).thenReturn(expectedReport);
+
+ // Act
+ byte[] result = reportService.generateGymUsageReport(startDate, endDate, format);
+
+ // Assert
+ assertArrayEquals(expectedReport, result);
+ verify(gymSessionRepository).findBySessionDateBetween(startDate, endDate);
+ verify(reportGeneratorMock).generateJSON(anyList());
+ }
+
+ @Test
+ void testGetAttendanceStatistics() throws IOException {
+ // Arrange
+ LocalDate startDate = LocalDate.of(2023, 6, 1);
+ LocalDate endDate = LocalDate.of(2023, 6, 30);
+ ReportFormat format = ReportFormat.PDF;
+
+ GymSession session1 = createTestSession(LocalDate.of(2023, 6, 10), 20, 15, 60);
+ GymSession session2 = createTestSession(LocalDate.of(2023, 6, 20), 25, 20, 90);
+ List sessionList = Arrays.asList(session1, session2);
+
+ when(gymSessionRepository.findBySessionDateBetween(startDate, endDate)).thenReturn(sessionList);
+
+ byte[] expectedReport = "PDF report content".getBytes();
+ when(reportGeneratorMock.generatePDF(anyList(), anyString(), any())).thenReturn(expectedReport);
+
+ // Act
+ byte[] result = reportService.getAttendanceStatistics(startDate, endDate, format);
+
+ // Assert
+ assertArrayEquals(expectedReport, result);
+ verify(gymSessionRepository).findBySessionDateBetween(startDate, endDate);
+ verify(reportGeneratorMock).generatePDF(anyList(), anyString(), any());
+ }
+
+ @Test
+ void testGetAttendanceStatisticsWithCSVFormat() throws IOException {
+ // Arrange
+ LocalDate startDate = LocalDate.of(2023, 6, 1);
+ LocalDate endDate = LocalDate.of(2023, 6, 30);
+ ReportFormat format = ReportFormat.CSV;
+
+ List sessionList = Collections.emptyList();
+ when(gymSessionRepository.findBySessionDateBetween(startDate, endDate)).thenReturn(sessionList);
+
+ byte[] expectedReport = "CSV report content".getBytes();
+ when(reportGeneratorMock.generateCSV(anyList(), anyList(), any())).thenReturn(expectedReport);
+
+ // Act
+ byte[] result = reportService.getAttendanceStatistics(startDate, endDate, format);
+
+ // Assert
+ assertArrayEquals(expectedReport, result);
+ verify(gymSessionRepository).findBySessionDateBetween(startDate, endDate);
+ verify(reportGeneratorMock).generateCSV(anyList(), anyList(), any());
+ }
+
+ @Test
+ void testGetAttendanceStatisticsThrowsException() throws IOException {
+ // Arrange
+ LocalDate startDate = LocalDate.of(2023, 6, 1);
+ LocalDate endDate = LocalDate.of(2023, 6, 30);
+ ReportFormat format = ReportFormat.PDF;
+
+ List sessionList = Collections.emptyList();
+ when(gymSessionRepository.findBySessionDateBetween(startDate, endDate)).thenReturn(sessionList);
+
+ IOException ioException = new IOException("Test exception");
+ when(reportGeneratorMock.generatePDF(anyList(), anyString(), any())).thenThrow(ioException);
+
+ // Act & Assert
+ RuntimeException exception = assertThrows(RuntimeException.class,
+ () -> reportService.getAttendanceStatistics(startDate, endDate, format));
+
+ assertEquals("Error generando reporte en formato: " + format, exception.getMessage());
+ assertEquals(ioException, exception.getCause());
+ } @Test
+ void testMapLine() throws Exception {
+ // Arrange
+ GymSession session = createTestSession(LocalDate.of(2023, 6, 10), 20, 15, 60);
+ String expectedLine = String.format(
+ "Fecha: %s | Capacidad Total: %d | Reservas Totales: %d | Tasa de Utilización: %.2f%% | Utilización Promedio: %.2f%% | Duración Promedio: %d minutos",
+ session.getSessionDate(), session.getCapacity(), session.getReservedSpots(),
+ session.getReservedSpots() * 100.0 / session.getCapacity(),
+ session.getReservedSpots() * 100.0 / session.getCapacity(),
+ session.getDuration().toMinutes()
+ );
+
+ // Invoke private method through reflection
+ java.lang.reflect.Method mapLineMethod = ReportServiceImpl.class.getDeclaredMethod(
+ "mapLine", GymSession.class);
+ mapLineMethod.setAccessible(true);
+
+ // Act
+ String result = (String) mapLineMethod.invoke(reportService, session);
+
+ // Assert
+ assertEquals(expectedLine, result);
+ }
+
+ @Test
+ void testUserProgressLineMapper() throws Exception {
+ // Arrange
+ PhysicalProgress progress = createTestProgress(UUID.randomUUID(),
+ LocalDate.of(2023, 6, 1), 75.0, "Lose weight");
+
+ String expectedLine = "Fecha: " + progress.getRecordDate() +
+ " | Peso: " + progress.getWeight().getValue() + "kg" +
+ " | Meta: " + progress.getPhysicalGoal();
+
+ // Get the lineMapper function directly from the implementation
+ // This tests the lambda$generateUserProgressReport$0 method
+ java.lang.reflect.Method generateUserProgressReportMethod = ReportServiceImpl.class.getDeclaredMethod(
+ "generateUserProgressReport", UUID.class, ReportFormat.class);
+ generateUserProgressReportMethod.setAccessible(true);
+
+ // We need to extract the function from the implementation
+ // Since we can't directly access lambdas, we'll test the behavior by using the ReportGenerator's call pattern
+
+ // Mock the generatePDF to capture the lineMapper function
+ doAnswer(invocation -> {
+ @SuppressWarnings("unchecked")
+ java.util.function.Function lineMapper =
+ (java.util.function.Function) invocation.getArgument(2);
+
+ // Apply the lineMapper to our test progress
+ String result = lineMapper.apply(progress);
+
+ // Assert within the mock
+ assertEquals(expectedLine, result);
+
+ return "test".getBytes();
+ }).when(reportGeneratorMock).generatePDF(anyList(), anyString(), any());
+
+ // Act - trigger the use of the lineMapper
+ reportService.generateUserProgressReport(UUID.randomUUID(), ReportFormat.PDF);
+ }
+
+ @Test
+ void testUserProgressRowMapper() throws Exception {
+ // Arrange
+ PhysicalProgress progress = createTestProgress(UUID.randomUUID(),
+ LocalDate.of(2023, 6, 1), 75.0, "Lose weight");
+
+ List expectedRow = List.of(
+ progress.getRecordDate().toString(),
+ String.valueOf(progress.getWeight().getValue()),
+ progress.getPhysicalGoal()
+ );
+
+ // Mock the generateXLSX to capture the rowMapper function
+ doAnswer(invocation -> {
+ @SuppressWarnings("unchecked")
+ java.util.function.Function> rowMapper =
+ (java.util.function.Function>) invocation.getArgument(2);
+
+ // Apply the rowMapper to our test progress
+ List result = rowMapper.apply(progress);
+
+ // Assert within the mock
+ assertEquals(expectedRow, result);
+
+ return "test".getBytes();
+ }).when(reportGeneratorMock).generateXLSX(anyList(), anyList(), any());
+
+ // Act - trigger the use of the rowMapper
+ reportService.generateUserProgressReport(UUID.randomUUID(), ReportFormat.XLSX);
+ }
+
+ @Test
+ void testAttendanceStatisticsLineMapper() throws IOException {
+ // Arrange
+ LocalDate date = LocalDate.of(2023, 6, 1);
+ Integer attendanceCount = 42;
+ Map.Entry entry = Map.entry(date, attendanceCount);
+
+ String expectedLine = "Fecha: " + date + " | Asistencias: " + attendanceCount;
+
+ // Mock the generatePDF to capture the lineMapper function
+ doAnswer(invocation -> {
+ @SuppressWarnings("unchecked")
+ java.util.function.Function, String> lineMapper =
+ (java.util.function.Function, String>) invocation.getArgument(2);
+
+ // Apply the lineMapper to our test entry
+ String result = lineMapper.apply(entry);
+
+ // Assert within the mock
+ assertEquals(expectedLine, result);
+
+ return "test".getBytes();
+ }).when(reportGeneratorMock).generatePDF(anyList(), anyString(), any());
+
+ // Act - trigger the use of the lineMapper
+ reportService.getAttendanceStatistics(LocalDate.now(), LocalDate.now(), ReportFormat.PDF);
+ }
+
+ @Test
+ void testAttendanceStatisticsRowMapper() throws IOException {
+ // Arrange
+ LocalDate date = LocalDate.of(2023, 6, 1);
+ Integer attendanceCount = 42;
+ Map.Entry entry = Map.entry(date, attendanceCount);
+
+ List expectedRow = List.of(
+ date.toString(),
+ String.valueOf(attendanceCount)
+ );
+
+ // Mock the generateXLSX to capture the rowMapper function
+ doAnswer(invocation -> {
+ @SuppressWarnings("unchecked")
+ java.util.function.Function, List> rowMapper =
+ (java.util.function.Function, List>) invocation.getArgument(2);
+
+ // Apply the rowMapper to our test entry
+ List result = rowMapper.apply(entry);
+
+ // Assert within the mock
+ assertEquals(expectedRow, result);
+
+ return "test".getBytes();
+ }).when(reportGeneratorMock).generateXLSX(anyList(), anyList(), any());
+
+ // Act - trigger the use of the rowMapper
+ reportService.getAttendanceStatistics(LocalDate.now(), LocalDate.now(), ReportFormat.XLSX);
+ }
+
+ // Helper methods to create test data
+ private PhysicalProgress createTestProgress(UUID userId, LocalDate date, double weightValue, String goal) {
+ PhysicalProgress progress = new PhysicalProgress();
+ progress.setUserId(userId);
+ progress.setRecordDate(date);
+
+ Weight weight = new Weight();
+ weight.setValue(weightValue);
+ progress.setWeight(weight);
+ progress.setPhysicalGoal(goal);
+
+ return progress;
+ }
+ private GymSession createTestSession(LocalDate date, int capacity, int reservedSpots, int durationMinutes) {
+ GymSession session = new GymSession();
+ session.setSessionDate(date);
+ session.setCapacity(capacity);
+ session.setReservedSpots(reservedSpots);
+ // Set start and end times so that getDuration() works properly
+ session.setStartTime(LocalTime.of(10, 0)); // 10:00 AM
+ session.setEndTime(LocalTime.of(10, 0).plusMinutes(durationMinutes)); // End time based on duration
+ return session;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/edu/eci/cvds/prometeo/service/report/ReportGeneratorTest.java b/src/test/java/edu/eci/cvds/prometeo/service/report/ReportGeneratorTest.java
new file mode 100644
index 0000000..2f1552c
--- /dev/null
+++ b/src/test/java/edu/eci/cvds/prometeo/service/report/ReportGeneratorTest.java
@@ -0,0 +1,198 @@
+package edu.eci.cvds.prometeo.service.report;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Function;
+import static org.junit.jupiter.api.Assertions.*;
+
+
+
+
+
+
+public class ReportGeneratorTest {
+
+ private ReportGenerator reportGenerator;
+ private List testDataList;
+ private List headers;
+ private Function> rowMapper;
+ private Function lineMapper;
+
+ @BeforeEach
+ void setUp() {
+ reportGenerator = new ReportGenerator();
+ testDataList = Arrays.asList(
+ new TestData(1, "Item 1", 100.0),
+ new TestData(2, "Item 2", 200.0),
+ new TestData(3, "Item 3", 300.0)
+ );
+ headers = Arrays.asList("ID", "Name", "Value");
+ rowMapper = data -> Arrays.asList(
+ String.valueOf(data.getId()),
+ data.getName(),
+ String.valueOf(data.getValue())
+ );
+ lineMapper = data -> String.format("ID: %d, Name: %s, Value: %.2f",
+ data.getId(), data.getName(), data.getValue());
+ }
+
+ @Test
+ void testGenerateJSON() throws IOException {
+ // Given testDataList from setUp
+
+ // When
+ byte[] result = reportGenerator.generateJSON(testDataList);
+
+ // Then
+ assertNotNull(result);
+ assertTrue(result.length > 0);
+
+ // Verify content by deserializing
+ ObjectMapper mapper = new ObjectMapper();
+ List deserializedData = mapper.readValue(result, new TypeReference>() {});
+ assertEquals(testDataList.size(), deserializedData.size());
+ for (int i = 0; i < testDataList.size(); i++) {
+ assertEquals(testDataList.get(i).getId(), deserializedData.get(i).getId());
+ assertEquals(testDataList.get(i).getName(), deserializedData.get(i).getName());
+ assertEquals(testDataList.get(i).getValue(), deserializedData.get(i).getValue(), 0.001);
+ }
+ }
+
+ @Test
+ void testGenerateCSV() {
+ // Given testDataList, headers, and rowMapper from setUp
+
+ // When
+ byte[] result = reportGenerator.generateCSV(testDataList, headers, rowMapper);
+
+ // Then
+ assertNotNull(result);
+ String csvContent = new String(result, StandardCharsets.UTF_8);
+
+ // Verify header row
+ assertTrue(csvContent.startsWith("ID,Name,Value"));
+
+ // Verify data rows
+ assertTrue(csvContent.contains("1,Item 1,100.0"));
+ assertTrue(csvContent.contains("2,Item 2,200.0"));
+ assertTrue(csvContent.contains("3,Item 3,300.0"));
+ }
+
+ @Test
+ void testGenerateXLSX() throws IOException {
+ // Given testDataList, headers, and rowMapper from setUp
+
+ // When
+ byte[] result = reportGenerator.generateXLSX(testDataList, headers, rowMapper);
+
+ // Then
+ assertNotNull(result);
+ assertTrue(result.length > 0);
+
+ // Verify Excel content
+ try (Workbook workbook = new XSSFWorkbook(new ByteArrayInputStream(result))) {
+ Sheet sheet = workbook.getSheetAt(0);
+ assertEquals("Reporte", sheet.getSheetName());
+
+ // Check header row
+ Row headerRow = sheet.getRow(0);
+ assertEquals("ID", headerRow.getCell(0).getStringCellValue());
+ assertEquals("Name", headerRow.getCell(1).getStringCellValue());
+ assertEquals("Value", headerRow.getCell(2).getStringCellValue());
+
+ // Check data rows
+ Row firstRow = sheet.getRow(1);
+ assertEquals("1", firstRow.getCell(0).getStringCellValue());
+ assertEquals("Item 1", firstRow.getCell(1).getStringCellValue());
+ assertEquals("100.0", firstRow.getCell(2).getStringCellValue());
+ }
+ }
+
+ @Test
+ void testGeneratePDF() throws IOException {
+ // Given testDataList and lineMapper from setUp
+
+ // When
+ byte[] result = reportGenerator.generatePDF(testDataList, "Test Report", lineMapper);
+
+ // Then
+ assertNotNull(result);
+ assertTrue(result.length > 0);
+
+ // Verify PDF is valid by loading it
+ try (PDDocument document = PDDocument.load(new ByteArrayInputStream(result))) {
+ assertNotNull(document);
+ assertTrue(document.getNumberOfPages() > 0);
+ }
+ }
+
+ @Test
+ void testEmptyList() throws IOException {
+ // Given
+ List emptyList = Collections.emptyList();
+
+ // When
+ byte[] jsonResult = reportGenerator.generateJSON(emptyList);
+ byte[] csvResult = reportGenerator.generateCSV(emptyList, headers, rowMapper);
+ byte[] xlsxResult = reportGenerator.generateXLSX(emptyList, headers, rowMapper);
+ byte[] pdfResult = reportGenerator.generatePDF(emptyList, "Empty Report", lineMapper);
+
+ // Then
+ assertEquals("[]", new String(jsonResult, StandardCharsets.UTF_8));
+ assertTrue(new String(csvResult, StandardCharsets.UTF_8).contains("ID,Name,Value"));
+ assertTrue(xlsxResult.length > 0);
+ assertTrue(pdfResult.length > 0);
+ }
+
+ // Simple test data class
+ static class TestData {
+ private int id;
+ private String name;
+ private double value;
+
+ public TestData() {
+ // Default constructor for Jackson
+ }
+
+ public TestData(int id, String name, double value) {
+ this.id = id;
+ this.name = name;
+ this.value = value;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public double getValue() {
+ return value;
+ }
+
+ public void setValue(double value) {
+ this.value = value;
+ }
+ }
+}
\ No newline at end of file