test(importing): pin relationship error propagation and short-row reads
Add a negative test that an unexpected DomainException from addRelationshipIdempotently propagates rather than being swallowed (only DUPLICATE/CIRCULAR are caught for idempotency), guarding against a future swallow-all refactor. Add a CanonicalSheetReader test for a row narrower than the header (POI omits trailing empty cells) reading absent columns as "". Refs #669 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -55,6 +55,21 @@ class CanonicalSheetReaderTest {
|
|||||||
assertThat(rows.get(0).get("does_not_exist")).isEmpty();
|
assertThat(rows.get(0).get("does_not_exist")).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void get_returnsEmptyString_forTrailingColumns_whenRowShorterThanHeader(@TempDir Path tempDir) throws Exception {
|
||||||
|
// POI omits trailing empty cells, so a real-world artifact row can be narrower than
|
||||||
|
// the header. The missing columns must read as "" rather than throwing.
|
||||||
|
Path xlsx = write(tempDir,
|
||||||
|
List.of("index", "file", "summary"),
|
||||||
|
List.of(List.of("W-0001")));
|
||||||
|
|
||||||
|
List<CanonicalSheetReader.Row> rows = CanonicalSheetReader.readRows(xlsx.toFile(), List.of("index", "file", "summary"));
|
||||||
|
|
||||||
|
assertThat(rows.get(0).get("index")).isEqualTo("W-0001");
|
||||||
|
assertThat(rows.get(0).get("file")).isEmpty();
|
||||||
|
assertThat(rows.get(0).get("summary")).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void splitList_splitsOnPipe() {
|
void splitList_splitsOnPipe() {
|
||||||
assertThat(CanonicalSheetReader.splitList("a|b|c")).containsExactly("a", "b", "c");
|
assertThat(CanonicalSheetReader.splitList("a|b|c")).containsExactly("a", "b", "c");
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import java.nio.file.Path;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.doThrow;
|
import static org.mockito.Mockito.doThrow;
|
||||||
@@ -106,6 +107,31 @@ class PersonTreeImporterTest {
|
|||||||
verify(relationshipService).addRelationship(any(), any());
|
verify(relationshipService).addRelationship(any(), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void load_propagatesUnexpectedDomainException_fromAddRelationship(@TempDir Path tempDir) throws Exception {
|
||||||
|
PersonService personService = mock(PersonService.class);
|
||||||
|
RelationshipService relationshipService = mock(RelationshipService.class);
|
||||||
|
when(personService.upsertBySourceRef(any()))
|
||||||
|
.thenAnswer(inv -> personOf(inv.getArgument(0)));
|
||||||
|
// An unexpected ErrorCode (not DUPLICATE/CIRCULAR) must NOT be swallowed.
|
||||||
|
doThrow(DomainException.internal(ErrorCode.INTERNAL_ERROR, "boom"))
|
||||||
|
.when(relationshipService).addRelationship(any(), any());
|
||||||
|
Path json = write(tempDir, """
|
||||||
|
{"persons":[
|
||||||
|
{"rowId":"row_a","lastName":"A","familyMember":true,"personId":"a"},
|
||||||
|
{"rowId":"row_b","lastName":"B","familyMember":true,"personId":"b"}
|
||||||
|
],"relationships":[
|
||||||
|
{"personId":"row_a","relatedPersonId":"row_b","type":"SPOUSE_OF","source":"verheiratet_mit"}
|
||||||
|
]}
|
||||||
|
""");
|
||||||
|
|
||||||
|
PersonTreeImporter importer = new PersonTreeImporter(personService, relationshipService);
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> importer.load(json.toFile()))
|
||||||
|
.isInstanceOf(DomainException.class)
|
||||||
|
.extracting("code").isEqualTo(ErrorCode.INTERNAL_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void load_skipsRelationship_whenRowIdUnresolved(@TempDir Path tempDir) throws Exception {
|
void load_skipsRelationship_whenRowIdUnresolved(@TempDir Path tempDir) throws Exception {
|
||||||
PersonService personService = mock(PersonService.class);
|
PersonService personService = mock(PersonService.class);
|
||||||
|
|||||||
Reference in New Issue
Block a user