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