refactor(#240): replace Object[] positional mapping with Spring Data projections
Introduces TranscriptionQueueProjection and TranscriptionWeeklyStatsProjection interfaces so column reordering in native SQL can never silently produce wrong data. Removes the four type-coercion helpers (toUUID, toLocalDate, toInt, toLong) from TranscriptionQueueService. Covered by TranscriptionQueueServiceTest (6 tests). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
package org.raddatz.familienarchiv.service;
|
||||
|
||||
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.raddatz.familienarchiv.dto.TranscriptionQueueItemDTO;
|
||||
import org.raddatz.familienarchiv.dto.TranscriptionWeeklyStatsDTO;
|
||||
import org.raddatz.familienarchiv.repository.DocumentRepository;
|
||||
import org.raddatz.familienarchiv.repository.TranscriptionQueueProjection;
|
||||
import org.raddatz.familienarchiv.repository.TranscriptionWeeklyStatsProjection;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class TranscriptionQueueServiceTest {
|
||||
|
||||
@Mock DocumentRepository documentRepository;
|
||||
@InjectMocks TranscriptionQueueService service;
|
||||
|
||||
// ─── getSegmentationQueue ─────────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
void getSegmentationQueue_delegatesToRepositoryWithDefaultSize() {
|
||||
UUID id = UUID.randomUUID();
|
||||
TranscriptionQueueProjection proj = mockQueueProjection(id, "Brief von 1920", null, 0, 0, 0);
|
||||
when(documentRepository.findSegmentationQueue(5)).thenReturn(List.of(proj));
|
||||
|
||||
List<TranscriptionQueueItemDTO> result = service.getSegmentationQueue();
|
||||
|
||||
verify(documentRepository).findSegmentationQueue(5);
|
||||
assertThat(result).hasSize(1);
|
||||
assertThat(result.get(0).id()).isEqualTo(id);
|
||||
assertThat(result.get(0).title()).isEqualTo("Brief von 1920");
|
||||
assertThat(result.get(0).documentDate()).isNull();
|
||||
assertThat(result.get(0).annotationCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getSegmentationQueue_mapsDocumentDateWhenPresent() {
|
||||
LocalDate date = LocalDate.of(1920, 6, 15);
|
||||
TranscriptionQueueProjection proj = mockQueueProjection(UUID.randomUUID(), "Brief", date, 0, 0, 0);
|
||||
when(documentRepository.findSegmentationQueue(5)).thenReturn(List.of(proj));
|
||||
|
||||
List<TranscriptionQueueItemDTO> result = service.getSegmentationQueue();
|
||||
|
||||
assertThat(result.get(0).documentDate()).isEqualTo(date);
|
||||
}
|
||||
|
||||
// ─── getTranscriptionQueue ────────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
void getTranscriptionQueue_delegatesToRepositoryWithDefaultSize() {
|
||||
UUID id = UUID.randomUUID();
|
||||
TranscriptionQueueProjection proj = mockQueueProjection(id, "Tagebuch", LocalDate.of(1943, 1, 1), 3, 1, 0);
|
||||
when(documentRepository.findTranscriptionQueue(5)).thenReturn(List.of(proj));
|
||||
|
||||
List<TranscriptionQueueItemDTO> result = service.getTranscriptionQueue();
|
||||
|
||||
verify(documentRepository).findTranscriptionQueue(5);
|
||||
assertThat(result).hasSize(1);
|
||||
assertThat(result.get(0).annotationCount()).isEqualTo(3);
|
||||
assertThat(result.get(0).textedBlockCount()).isEqualTo(1);
|
||||
assertThat(result.get(0).reviewedBlockCount()).isEqualTo(0);
|
||||
}
|
||||
|
||||
// ─── getReadyToReadQueue ──────────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
void getReadyToReadQueue_delegatesToRepositoryWithDefaultSize() {
|
||||
TranscriptionQueueProjection proj = mockQueueProjection(UUID.randomUUID(), "Urkunde", null, 4, 4, 4);
|
||||
when(documentRepository.findReadyToReadQueue(5)).thenReturn(List.of(proj));
|
||||
|
||||
List<TranscriptionQueueItemDTO> result = service.getReadyToReadQueue();
|
||||
|
||||
verify(documentRepository).findReadyToReadQueue(5);
|
||||
assertThat(result).hasSize(1);
|
||||
assertThat(result.get(0).reviewedBlockCount()).isEqualTo(4);
|
||||
}
|
||||
|
||||
// ─── getWeeklyStats ───────────────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
void getWeeklyStats_mapsProjectionToDTO() {
|
||||
TranscriptionWeeklyStatsProjection proj = mockStatsProjection(3L, 7L, 2L);
|
||||
when(documentRepository.findWeeklyStats()).thenReturn(proj);
|
||||
|
||||
TranscriptionWeeklyStatsDTO result = service.getWeeklyStats();
|
||||
|
||||
assertThat(result.segmentationCount()).isEqualTo(3L);
|
||||
assertThat(result.transcriptionCount()).isEqualTo(7L);
|
||||
assertThat(result.readyCount()).isEqualTo(2L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getWeeklyStats_returnsZeros_whenAllCountsAreZero() {
|
||||
TranscriptionWeeklyStatsProjection proj = mockStatsProjection(0L, 0L, 0L);
|
||||
when(documentRepository.findWeeklyStats()).thenReturn(proj);
|
||||
|
||||
TranscriptionWeeklyStatsDTO result = service.getWeeklyStats();
|
||||
|
||||
assertThat(result.segmentationCount()).isEqualTo(0L);
|
||||
assertThat(result.transcriptionCount()).isEqualTo(0L);
|
||||
assertThat(result.readyCount()).isEqualTo(0L);
|
||||
}
|
||||
|
||||
// ─── helpers ─────────────────────────────────────────────────────────────
|
||||
|
||||
private TranscriptionQueueProjection mockQueueProjection(
|
||||
UUID id, String title, LocalDate documentDate,
|
||||
int annotationCount, int textedBlockCount, int reviewedBlockCount) {
|
||||
TranscriptionQueueProjection proj = mock(TranscriptionQueueProjection.class);
|
||||
when(proj.getId()).thenReturn(id);
|
||||
when(proj.getTitle()).thenReturn(title);
|
||||
when(proj.getDocumentDate()).thenReturn(documentDate);
|
||||
when(proj.getAnnotationCount()).thenReturn(annotationCount);
|
||||
when(proj.getTextedBlockCount()).thenReturn(textedBlockCount);
|
||||
when(proj.getReviewedBlockCount()).thenReturn(reviewedBlockCount);
|
||||
return proj;
|
||||
}
|
||||
|
||||
private TranscriptionWeeklyStatsProjection mockStatsProjection(
|
||||
long segmentationCount, long transcriptionCount, long readyCount) {
|
||||
TranscriptionWeeklyStatsProjection proj = mock(TranscriptionWeeklyStatsProjection.class);
|
||||
when(proj.getSegmentationCount()).thenReturn(segmentationCount);
|
||||
when(proj.getTranscriptionCount()).thenReturn(transcriptionCount);
|
||||
when(proj.getReadyCount()).thenReturn(readyCount);
|
||||
return proj;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user