test(document): close review-flagged coverage gaps for auto-title sync (#726)
- save-time: precision+raw carry-over when the DTO omits them (exercises the shared skip-null resolvers), and a RANGE label round-trip (Sara/Elicit) - factory: a bare Document with a null index builds "" rather than NPE-ing (Felix) - backfill matcher: negative near-misses — ASCII hyphen vs en dash, missing separator before trailing text, year-with-trailing-letters, index followed by text without a separator (Sara) - backfill integration: tighten the count assertion to exactly 1 on the clean test DB (Sara) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -371,6 +371,43 @@ class DocumentServiceTest {
|
|||||||
assertThat(stored.getTitle()).isEqualTo("C-0029 – Frühling 1943");
|
assertThat(stored.getTitle()).isEqualTo("C-0029 – Frühling 1943");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void updateDocument_carriesStoredPrecisionAndRaw_whenDtoOmitsThem() throws Exception {
|
||||||
|
// Only the year changes; precision/end/raw are omitted from the DTO, so projectedState
|
||||||
|
// must carry them from the entity (exercises the skip-null effective* resolvers).
|
||||||
|
Document stored = makeStored("C-0029", LocalDate.of(1943, 4, 1), DatePrecision.SEASON, null);
|
||||||
|
stored.setMetaDateRaw("Frühling 1943");
|
||||||
|
stored.setTitle(documentTitleFactory.build(stored)); // "C-0029 – Frühling 1943"
|
||||||
|
DocumentUpdateDTO dto = editDto(stored.getTitle(), LocalDate.of(1944, 4, 1), null, null);
|
||||||
|
|
||||||
|
runUpdate(stored, dto);
|
||||||
|
|
||||||
|
assertThat(stored.getTitle()).isEqualTo("C-0029 – Frühling 1944");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void updateDocument_roundTripsRangeLabel_atSaveTime() throws Exception {
|
||||||
|
Document stored = Document.builder()
|
||||||
|
.id(UUID.randomUUID())
|
||||||
|
.originalFilename("C-0029")
|
||||||
|
.documentDate(LocalDate.of(1917, 1, 10))
|
||||||
|
.metaDatePrecision(DatePrecision.RANGE)
|
||||||
|
.metaDateEnd(LocalDate.of(1917, 1, 11))
|
||||||
|
.receivers(new HashSet<>())
|
||||||
|
.tags(new HashSet<>())
|
||||||
|
.build();
|
||||||
|
stored.setTitle(documentTitleFactory.build(stored)); // "C-0029 – 10.–11. Jan. 1917"
|
||||||
|
DocumentUpdateDTO dto = new DocumentUpdateDTO();
|
||||||
|
dto.setTitle(stored.getTitle());
|
||||||
|
dto.setDocumentDate(LocalDate.of(1918, 1, 10));
|
||||||
|
dto.setMetaDatePrecision(DatePrecision.RANGE);
|
||||||
|
dto.setMetaDateEnd(LocalDate.of(1918, 1, 11));
|
||||||
|
|
||||||
|
runUpdate(stored, dto);
|
||||||
|
|
||||||
|
assertThat(stored.getTitle()).isEqualTo("C-0029 – 10.–11. Jan. 1918");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void updateDocument_doesNotRegenerateToBlank_whenSubmittedTitleEmpty() throws Exception {
|
void updateDocument_doesNotRegenerateToBlank_whenSubmittedTitleEmpty() throws Exception {
|
||||||
Document stored = makeStored("C-0029", LocalDate.of(1928, 1, 1), DatePrecision.YEAR, "Berlin");
|
Document stored = makeStored("C-0029", LocalDate.of(1928, 1, 1), DatePrecision.YEAR, "Berlin");
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class DocumentTitleBackfillIntegrationTest {
|
|||||||
|
|
||||||
int count = documentService.backfillTitles();
|
int count = documentService.backfillTitles();
|
||||||
|
|
||||||
assertThat(count).isGreaterThanOrEqualTo(1);
|
assertThat(count).isEqualTo(1); // exactly the one stale row seeded (clean test DB)
|
||||||
assertThat(documentRepository.findById(stale.getId()).orElseThrow().getTitle())
|
assertThat(documentRepository.findById(stale.getId()).orElseThrow().getTitle())
|
||||||
.isEqualTo("C-0029 – 1928 – Berlin");
|
.isEqualTo("C-0029 – 1928 – Berlin");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,6 +118,30 @@ class DocumentTitleBackfillMatcherTest {
|
|||||||
assertThat(overwritable("Ganz anderer Titel", null)).isFalse();
|
assertThat(overwritable("Ganz anderer Titel", null)).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── near-miss: shapes that look almost machine-built but are not ──────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void ascii_hyphen_instead_of_en_dash_separator_is_skipped() {
|
||||||
|
// The separator is " – " (en dash); a plain " - " is not the machine separator.
|
||||||
|
assertThat(overwritable("C-0029 - 1916", null)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void date_label_without_separator_before_trailing_text_is_skipped() {
|
||||||
|
// "1916 Berlin" is not a date label and is not joined by " – "; prose, not machine.
|
||||||
|
assertThat(overwritable("C-0029 – 1916 Berlin", null)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void year_with_trailing_letters_is_not_a_year_label() {
|
||||||
|
assertThat(overwritable("C-0029 – 1916er Brief", null)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void index_immediately_followed_by_text_without_separator_is_skipped() {
|
||||||
|
assertThat(overwritable("C-0029x – 1916", null)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
// ─── fail-closed guards ───────────────────────────────────────────────────
|
// ─── fail-closed guards ───────────────────────────────────────────────────
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -71,6 +71,13 @@ class DocumentTitleFactoryTest {
|
|||||||
assertThat(factory.build(d)).isEqualTo("C-0029 – 1928");
|
assertThat(factory.build(d)).isEqualTo("C-0029 – 1928");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void bare_document_with_null_index_builds_empty_string_not_npe() {
|
||||||
|
// originalFilename is NOT NULL in production; the guard keeps a synthetic/partial entity
|
||||||
|
// from tripping StringBuilder(null) with an opaque NPE.
|
||||||
|
assertThat(factory.build(Document.builder().build())).isEqualTo("");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void day_precision_renders_the_full_german_label() {
|
void day_precision_renders_the_full_german_label() {
|
||||||
Document d = doc("C-0029")
|
Document d = doc("C-0029")
|
||||||
|
|||||||
Reference in New Issue
Block a user