From 3aa3b5975a03e9bc05d6762477be733fa967fa30 Mon Sep 17 00:00:00 2001 From: Bryce Willey Date: Thu, 14 May 2026 15:55:15 -0400 Subject: [PATCH] Add Name checks to TylerCodesParser For First/Middle/Last/Suffix parts of case party names. --- ...rmationDocassembleJacksonDeserializer.java | 15 ++-- .../NameDocassembleDeserializer.java | 65 ++++++++++++++-- .../PersonDocassembleJacksonDeserializer.java | 7 +- .../litlab/efsp/server/ecf4/CodesParser.java | 14 ++++ .../ecf4/EcfCourtSpecificSerializer.java | 73 ++---------------- .../server/ecf4/tyler/TylerCodesParser.java | 57 ++++++++++++++ .../litlab/efsp/utils/InfoCollector.java | 30 ++++++++ .../litlab/efsp/utils/InterviewVariable.java | 8 ++ ...embleToFilingInformationConverterTest.java | 16 ++++ ...sonDocassembleJacksonDeserializerTest.java | 51 ++++++++++--- .../ecf4/tyler/TylerCodesParserTest.java | 74 ++++++++++++++++++- 11 files changed, 316 insertions(+), 94 deletions(-) diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/docassemble/FilingInformationDocassembleJacksonDeserializer.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/docassemble/FilingInformationDocassembleJacksonDeserializer.java index 0cd416fd6..7c95e0043 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/docassemble/FilingInformationDocassembleJacksonDeserializer.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/docassemble/FilingInformationDocassembleJacksonDeserializer.java @@ -62,7 +62,8 @@ public FilingInformationDocassembleJacksonDeserializer( * @throws FilingError */ private static List collectPeople( - JsonNode topObj, String potentialMember, InfoCollector collector) throws FilingError { + JsonNode topObj, String potentialMember, CodesParser parser, InfoCollector collector) + throws FilingError { if (!topObj.has(potentialMember)) { return List.of(); // Just an empty list: we don't know if it's required } @@ -77,7 +78,7 @@ private static List collectPeople( JsonNode personJson = peopleElements.get(i); collector.pushAttributeStack(potentialMember + "[" + i + "]"); Result per = - PersonDocassembleJacksonDeserializer.fromNode(personJson, collector); + PersonDocassembleJacksonDeserializer.fromNode(personJson, parser, collector); collector.popAttributeStack(); if (per.isErr()) { FilingError ex = per.unwrapErrOrElseThrow(); @@ -103,8 +104,8 @@ public FilingInformation fromNode(JsonNode node, InfoCollector collector) throws boolean isInitialFiling = entities.getPreviousCaseId().isEmpty() && entities.getCaseDocketNumber().isEmpty(); - List users = collectPeople(node, "users", collector); - List otherParties = collectPeople(node, "other_parties", collector); + List users = collectPeople(node, "users", parser, collector); + List otherParties = collectPeople(node, "other_parties", parser, collector); var varToPartyId = new HashMap(); int perIdx = 0; @@ -323,7 +324,8 @@ public FilingInformation fromNode(JsonNode node, InfoCollector collector) throws } else { collector.pushAttributeStack("lead_contact"); Result per = - PersonDocassembleJacksonDeserializer.fromNode(node.get("lead_contact"), collector); + PersonDocassembleJacksonDeserializer.fromNode( + node.get("lead_contact"), parser, collector); collector.popAttributeStack(); if (per.isErr()) { FilingError ex = per.unwrapErrOrElseThrow(); @@ -544,7 +546,8 @@ private Optional extractLowerCourt(JsonNode node, InfoCollector } else if (jsonLowerCase.get("judge").isObject()) { collector.pushAttributeStack("judge"); judgeName = - NameDocassembleDeserializer.fromNode(jsonLowerCase.get("judge"), collector).getFullName(); + NameDocassembleDeserializer.fromNode(jsonLowerCase.get("judge"), parser, collector) + .getFullName(); collector.popAttributeStack(); } Optional title = JsonHelpers.getStringMember(jsonLowerCase, "title"); diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/docassemble/NameDocassembleDeserializer.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/docassemble/NameDocassembleDeserializer.java index e7c10bb7a..ef5b55487 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/docassemble/NameDocassembleDeserializer.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/docassemble/NameDocassembleDeserializer.java @@ -4,14 +4,20 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.NullNode; +import com.hubspot.algebra.Result; import edu.suffolk.litlab.efsp.model.Name; +import edu.suffolk.litlab.efsp.server.ecf4.CodesParser; +import edu.suffolk.litlab.efsp.server.ecf4.CodesParser.CodeError; +import edu.suffolk.litlab.efsp.server.ecf4.CodesParser.TextVarError; import edu.suffolk.litlab.efsp.utils.FilingError; import edu.suffolk.litlab.efsp.utils.InfoCollector; import edu.suffolk.litlab.efsp.utils.InterviewVariable; +import edu.suffolk.litlab.efsp.utils.InterviewVariable.VarBuilder; public class NameDocassembleDeserializer { - public static Name fromNode(JsonNode node, InfoCollector collector) throws FilingError { + public static Name fromNode(JsonNode node, CodesParser parser, InfoCollector collector) + throws FilingError { if (node == null || node.isNull()) { InterviewVariable var = collector.requestVar("name", "The full name of the person", "IndividualName"); @@ -33,17 +39,66 @@ public static Name fromNode(JsonNode node, InfoCollector collector) throws Filin "name.first", "The first name of a person / name of a business", "text"); collector.addRequired(var); } + var firstBuilder = + collector + .varBuilder() + .name("name.first") + .description("The first name of a person / name of a business") + .datatype("text"); + String firstName = + unwrap(parser.vetFirstName(getStringMember(node, "first")), collector, firstBuilder); + var middleBuilder = + collector + .varBuilder() + .name("name.middle") + .description("The middle name of a person") + .datatype("text"); + String middleName = + unwrap(parser.vetMiddleName(getStringMember(node, "middle")), collector, middleBuilder); + var lastBuilder = + collector + .varBuilder() + .name("name.last") + .description("The last name of a person") + .datatype("text"); + String lastName = + unwrap(parser.vetLastName(getStringMember(node, "last")), collector, lastBuilder); + + var suffixBuilder = + collector.varBuilder().name("name.suffix").description("The suffix of a person's name"); + var suffix = + unwrapCode(parser.vetSuffix(getStringMember(node, "suffix")), collector, suffixBuilder); Name name = new Name( "", // TODO(#55): where should we handle prefixes? Are they always empty? - getStringMember(node, "first").orElse(""), - getStringMember(node, "middle").orElse(""), - getStringMember(node, "last").orElse(""), - getStringMember(node, "suffix").orElse(""), + firstName, + middleName, + lastName, + suffix, "" // TODO(#55): where would Maiden name go, if asked for? ); return name; } + + private static String unwrap( + Result res, InfoCollector collector, VarBuilder varBuilder) + throws FilingError { + if (res.isErr()) { + collector.addTextError(res.unwrapErrOrElseThrow(), varBuilder); + return ""; + } + return res.unwrapOrElseThrow(); + } + + private static String unwrapCode( + Result res, InfoCollector collector, VarBuilder varBuilder) + throws FilingError { + if (res.isErr()) { + collector.addCodeError(res.unwrapErrOrElseThrow(), varBuilder); + return ""; + } + return res.unwrapOrElseThrow(); + } } diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/docassemble/PersonDocassembleJacksonDeserializer.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/docassemble/PersonDocassembleJacksonDeserializer.java index a78be4ec5..dc027c79f 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/docassemble/PersonDocassembleJacksonDeserializer.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/docassemble/PersonDocassembleJacksonDeserializer.java @@ -10,6 +10,7 @@ import edu.suffolk.litlab.efsp.model.ContactInformation; import edu.suffolk.litlab.efsp.model.Name; import edu.suffolk.litlab.efsp.model.Person; +import edu.suffolk.litlab.efsp.server.ecf4.CodesParser; import edu.suffolk.litlab.efsp.utils.FilingError; import edu.suffolk.litlab.efsp.utils.InfoCollector; import edu.suffolk.litlab.efsp.utils.InterviewVariable; @@ -31,8 +32,8 @@ protected PersonDocassembleJacksonDeserializer() {} * * @throws FilingError */ - public static Result fromNode(JsonNode node, InfoCollector collector) - throws FilingError { + public static Result fromNode( + JsonNode node, CodesParser parser, InfoCollector collector) throws FilingError { if (!node.isObject()) { FilingError err = FilingError.malformedInterview( @@ -112,7 +113,7 @@ public static Result fromNode(JsonNode node, InfoCollector }) .orElse(Optional.empty()); collector.pushAttributeStack("name"); - Name name = NameDocassembleDeserializer.fromNode(node.get("name"), collector); + Name name = NameDocassembleDeserializer.fromNode(node.get("name"), parser, collector); collector.popAttributeStack(); boolean isPer = !name.getMiddleName().isBlank() || !name.getLastName().isBlank(); diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/ecf4/CodesParser.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/ecf4/CodesParser.java index a726d92c7..2d85726e7 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/ecf4/CodesParser.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/ecf4/CodesParser.java @@ -8,6 +8,7 @@ import edu.suffolk.litlab.efsp.utils.FilingError; import java.util.List; import java.util.Optional; +import java.util.regex.Pattern; public interface CodesParser { // Types specifically for errors. @@ -16,6 +17,11 @@ public sealed interface CodeError {} public record NoMatchingCode(String given, List options) implements CodeError {} public record RequiredCodeNotPresent(List options) implements CodeError {} public record BadCode(FilingError err) implements CodeError {} + + public sealed interface TextVarError {} + public record MissingVar(Pattern regex) implements TextVarError {} + public record WrongVar(String given, Pattern regex) implements TextVarError {} + public record TooLongVar(String given, int length) implements TextVarError {} // spotless:on // Methods @@ -33,4 +39,12 @@ public Result, BadCode> retrieveFilingOptions( public Result, CodeError> vetFilingType( Optional filingCode, List filingOptions); + + public Result vetSuffix(Optional suffix); + + public Result vetFirstName(Optional name); + + public Result vetMiddleName(Optional name); + + public Result vetLastName(Optional name); } diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/ecf4/EcfCourtSpecificSerializer.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/ecf4/EcfCourtSpecificSerializer.java index dda928427..31e810cd3 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/ecf4/EcfCourtSpecificSerializer.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/ecf4/EcfCourtSpecificSerializer.java @@ -502,80 +502,17 @@ public ecf4.latest.gov.niem.niem.niem_core._2.PersonNameType serializeNameType( return t; }; PersonNameType personName = niemObjFac.createPersonNameType(); - personName.setPersonGivenName( - checkName( - name.getFirstName(), - allDataFields.getFieldRow("PartyFirstName"), - collector, - collector.requestVar( - "name.first", - "First name of a case party", - "text", - List.of(), - Optional.of(name.getFirstName())))); + personName.setPersonGivenName(wrapName.apply(name.getFirstName())); personName.setPersonMaidenName(wrapName.apply(name.getMaidenName())); - personName.setPersonMiddleName( - checkName( - name.getMiddleName(), - allDataFields.getFieldRow("PartyMiddleName"), - collector, - collector.requestVar("name.middle", "Middle name of the case party", "text"))); - personName.setPersonSurName( - checkName( - name.getLastName(), - allDataFields.getFieldRow("PartyLastName"), - collector, - collector.requestVar("name.last", "Last name of the case party", "text"))); + personName.setPersonMiddleName(wrapName.apply(name.getMiddleName())); + personName.setPersonSurName(wrapName.apply(name.getLastName())); personName.setPersonNamePrefixText(wrapName.apply(name.getPrefix())); - DataFieldRow suffixRow = allDataFields.getFieldRow("PartyNameSuffix"); - if (suffixRow.isvisible) { - List suffixes = cd.getNameSuffixes(this.court.code); - InterviewVariable var = - collector.requestVar( - "name.suffix", - "Suffix of the name of the party", - "choices", - suffixes.stream().map(s -> s.getName()).collect(Collectors.toList()), - Optional.of(name.getSuffix())); - if (name.getSuffix().isBlank()) { - if (suffixRow.isrequired) { - // TODO(brycew-later): - log.error( - "DEV WARNING: why would you ever require a suffix? There aren't empty suffix codes at" - + " all."); - collector.addRequired(var); - } else { - personName.setPersonNameSuffixText(wrapName.apply(name.getSuffix())); - } - } else { - Optional suffix = - suffixes.stream() - .filter(s -> s.getName().equalsIgnoreCase(name.getSuffix())) - .findFirst(); - if (suffix.isEmpty()) { - collector.addWrong(var); - } else { - personName.setPersonNameSuffixText(wrapName.apply(name.getSuffix())); - } - } + if (!name.getSuffix().isBlank()) { + personName.setPersonNameSuffixText(wrapName.apply(name.getSuffix())); } return personName; } - private PersonNameTextType checkName( - String name, DataFieldRow row, InfoCollector collector, InterviewVariable var) - throws FilingError { - if (!row.matchRegex(name)) { - collector.addWrong(var.appendDesc(": must match regex: " + row.regularexpression)); - } - if (name.length() > 100) { - collector.addWrong(var.appendDesc(": can't exceed 100 characters")); - } - PersonNameTextType t = niemObjFac.createPersonNameTextType(); - t.setValue(name); - return t; - } - public JAXBElement filingDocToXml( FilingDoc doc, boolean isInitialFiling, diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/ecf4/tyler/TylerCodesParser.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/ecf4/tyler/TylerCodesParser.java index 622e41eae..5a3dfa52f 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/ecf4/tyler/TylerCodesParser.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/ecf4/tyler/TylerCodesParser.java @@ -147,4 +147,61 @@ public Result, CodeError> vetFilingType( } return Result.ok(maybeCode); } + + public Result vetSuffix(Optional maybeSuffix) { + DataFieldRow suffixRow = allDataFields.getFieldRow("PartyNameSuffix"); + if (suffixRow.isvisible) { + List suffixes = cd.getNameSuffixes(this.court.code); + if ((maybeSuffix.isEmpty() || maybeSuffix.get().isBlank()) && suffixRow.isrequired) { + // TODO(brycew-later): + log.error( + "DEV WARNING: Court {}: WHY would you ever require a suffix? There aren't empty suffix codes at all.", + this.court.code); + } + String suffix = maybeSuffix.orElse(""); + Optional suffixMatch = + suffixes.stream().filter(s -> s.getName().equalsIgnoreCase(suffix)).findFirst(); + if (suffixMatch.isEmpty()) { + return Result.err( + new NoMatchingCode(suffix, suffixes.stream().map(s -> s.getName()).toList())); + } else { + return Result.ok(suffixMatch.get().getName()); + } + } + return Result.ok(maybeSuffix.orElse("")); + } + + /** + * Doesn't return optional because we can set the People names to null / blank. + * + * @param name + * @param row + * @return + */ + private Result vetName(Optional maybeName, DataFieldRow row) { + var name = maybeName.orElse(""); + if (!row.matchRegex(name)) { + return Result.err(new WrongVar(name, row.regularexpression)); + } + if (name.length() > 100) { + return Result.err(new TooLongVar(name, 100)); + } + return Result.ok(name); + } + + public Result vetFirstName(Optional name) { + var dataField = allDataFields.getFieldRow("PartyFirstName"); + if (name.isEmpty() || name.get().isBlank()) { + return Result.err(new MissingVar(dataField.regularexpression)); + } + return vetName(name, dataField); + } + + public Result vetMiddleName(Optional name) { + return vetName(name, allDataFields.getFieldRow("PartyMiddleName")); + } + + public Result vetLastName(Optional name) { + return vetName(name, allDataFields.getFieldRow("PartyLastName")); + } } diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/utils/InfoCollector.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/utils/InfoCollector.java index a60b7a85c..70c8b9598 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/utils/InfoCollector.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/utils/InfoCollector.java @@ -2,8 +2,12 @@ import edu.suffolk.litlab.efsp.server.ecf4.CodesParser.BadCode; import edu.suffolk.litlab.efsp.server.ecf4.CodesParser.CodeError; +import edu.suffolk.litlab.efsp.server.ecf4.CodesParser.MissingVar; import edu.suffolk.litlab.efsp.server.ecf4.CodesParser.NoMatchingCode; import edu.suffolk.litlab.efsp.server.ecf4.CodesParser.RequiredCodeNotPresent; +import edu.suffolk.litlab.efsp.server.ecf4.CodesParser.TextVarError; +import edu.suffolk.litlab.efsp.server.ecf4.CodesParser.TooLongVar; +import edu.suffolk.litlab.efsp.server.ecf4.CodesParser.WrongVar; import edu.suffolk.litlab.efsp.utils.InterviewVariable.VarBuilder; import java.util.ArrayList; import java.util.EmptyStackException; @@ -104,6 +108,32 @@ public InterviewVariable addCodeError(CodeError err, VarBuilder varBuilder) thro return null; } + public InterviewVariable addTextError(TextVarError err, VarBuilder varBuilder) + throws FilingError { + switch (err) { + case MissingVar missing -> { + varBuilder.appendDesc(", missing, must also match regex: " + missing.regex()); + var interviewVar = varBuilder.build(); + addRequired(interviewVar); + return interviewVar; + } + case WrongVar wrong -> { + varBuilder.appendDesc(": must match regex: " + wrong.regex()).currentVal(wrong.given()); + var interviewVar = varBuilder.build(); + addWrong(interviewVar); + return interviewVar; + } + case TooLongVar tooLong -> { + varBuilder + .appendDesc(": can't exceed " + tooLong.length() + " characters") + .currentVal(tooLong.given()); + var interviewVar = varBuilder.build(); + addWrong(interviewVar); + return interviewVar; + } + } + } + public void pushAttributeStack(String variableName) { variableAttributes.push(variableName); } diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/utils/InterviewVariable.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/utils/InterviewVariable.java index ea3fd4a55..bfc49dc82 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/utils/InterviewVariable.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/utils/InterviewVariable.java @@ -136,6 +136,14 @@ public VarBuilder description(String description) { return this; } + public VarBuilder appendDesc(String newDescription) { + if (this.description == null) { + this.description = ""; + } + this.description += newDescription; + return this; + } + public VarBuilder datatype(String datatype) { this.datatype = datatype; return this; diff --git a/proxyserver/src/test/java/edu/suffolk/litlab/efsp/docassemble/DocassembleToFilingInformationConverterTest.java b/proxyserver/src/test/java/edu/suffolk/litlab/efsp/docassemble/DocassembleToFilingInformationConverterTest.java index 6f00edf47..7ef794f63 100644 --- a/proxyserver/src/test/java/edu/suffolk/litlab/efsp/docassemble/DocassembleToFilingInformationConverterTest.java +++ b/proxyserver/src/test/java/edu/suffolk/litlab/efsp/docassemble/DocassembleToFilingInformationConverterTest.java @@ -13,6 +13,8 @@ import edu.suffolk.litlab.efsp.ecfcodes.tyler.CaseType; import edu.suffolk.litlab.efsp.ecfcodes.tyler.CodeDatabase; import edu.suffolk.litlab.efsp.ecfcodes.tyler.CourtLocationInfo; +import edu.suffolk.litlab.efsp.ecfcodes.tyler.DataFieldRow; +import edu.suffolk.litlab.efsp.ecfcodes.tyler.DataFields; import edu.suffolk.litlab.efsp.ecfcodes.tyler.FilingCode; import edu.suffolk.litlab.efsp.model.FilingDoc; import edu.suffolk.litlab.efsp.model.FilingInformation; @@ -28,6 +30,7 @@ import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.List; +import java.util.Map; import java.util.Optional; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -60,6 +63,19 @@ public void setUp() throws IOException { when(cd.getCaseTypesFor("01", "123987", Optional.empty())).thenReturn(List.of(exampleCaseType)); when(cd.getFilingType("01", "123987", "456098", true)).thenReturn(List.of(exampleFilingType)); when(cd.getFilingType("01", "123987", "456098", false)).thenReturn(List.of(exampleFilingType)); + when(cd.getDataFields("01")) + .thenReturn( + new DataFields( + List.of( + Map.of( + "PartyFirstName", + new DataFieldRow("PartyFirstName", "first name", true, true, "adams"), + "PartyMiddleName", + new DataFieldRow( + "PartyMiddleName", "middle name", true, false, "adams"), + "PartyLastName", + new DataFieldRow( + "PartyLastName", "last name", true, false, "adams"))))); var loc = new CourtLocationInfo("01"); loc.initial = true; loc.subsequent = true; diff --git a/proxyserver/src/test/java/edu/suffolk/litlab/efsp/docassemble/PersonDocassembleJacksonDeserializerTest.java b/proxyserver/src/test/java/edu/suffolk/litlab/efsp/docassemble/PersonDocassembleJacksonDeserializerTest.java index afe721cdb..6f443eb4f 100644 --- a/proxyserver/src/test/java/edu/suffolk/litlab/efsp/docassemble/PersonDocassembleJacksonDeserializerTest.java +++ b/proxyserver/src/test/java/edu/suffolk/litlab/efsp/docassemble/PersonDocassembleJacksonDeserializerTest.java @@ -3,32 +3,58 @@ import static edu.suffolk.litlab.efsp.docassemble.PersonDocassembleJacksonDeserializer.fromNode; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import edu.suffolk.litlab.efsp.ecfcodes.tyler.CodeDatabase; +import edu.suffolk.litlab.efsp.ecfcodes.tyler.CourtLocationInfo; +import edu.suffolk.litlab.efsp.ecfcodes.tyler.DataFieldRow; +import edu.suffolk.litlab.efsp.ecfcodes.tyler.DataFields; import edu.suffolk.litlab.efsp.model.PartyId; +import edu.suffolk.litlab.efsp.server.ecf4.CodesParser; +import edu.suffolk.litlab.efsp.server.ecf4.tyler.TylerCodesParser; import edu.suffolk.litlab.efsp.utils.AllWrongCollector; import edu.suffolk.litlab.efsp.utils.FailFastCollector; import edu.suffolk.litlab.efsp.utils.FilingError; import edu.suffolk.litlab.efsp.utils.InfoCollector; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Map; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class PersonDocassembleJacksonDeserializerTest { InfoCollector collector; + CodesParser parser; @BeforeEach public void setUp() { collector = new FailFastCollector(); + var cd = mock(CodeDatabase.class); + when(cd.getDataFields("adams")) + .thenReturn( + new DataFields( + List.of( + Map.of( + "PartyFirstName", + new DataFieldRow("PartyFirstName", "first name", true, true, "adams"), + "PartyMiddleName", + new DataFieldRow( + "PartyMiddleName", "middle name", true, false, "adams"), + "PartyLastName", + new DataFieldRow( + "PartyLastName", "last name", true, false, "adams"))))); + parser = new TylerCodesParser(cd, new CourtLocationInfo("adams")); } @Test public void testShouldParseWithAllJsonFields() throws FilingError, IOException { JsonNode node = readFile("person_with_all.json"); - var res = fromNode(node, collector); + var res = fromNode(node, parser, collector); assertThat(res.isOk()).isTrue(); var per = res.unwrapOrElseThrow(); assertThat(per.getContactInfo().getEmail()).contains("john.brown@example.com"); @@ -43,7 +69,7 @@ public void testShouldParseWithAllJsonFields() throws FilingError, IOException { @Test public void testShouldParseWithMinimal() throws FilingError, IOException { JsonNode node = readFile("person_with_minimal.json"); - var res = fromNode(node, collector); + var res = fromNode(node, parser, collector); assertThat(res.isOk()).isTrue(); var per = res.unwrapOrElseThrow(); assertThat(per.getName().getFirstName()).isEqualTo("John"); @@ -52,7 +78,7 @@ public void testShouldParseWithMinimal() throws FilingError, IOException { @Test public void testShouldParseWithExtraJson() throws FilingError, IOException { JsonNode node = readFile("person_with_extras.json"); - var res = fromNode(node, collector); + var res = fromNode(node, parser, collector); assertThat(res.isOk()).isTrue(); var per = res.unwrapOrElseThrow(); assertThat(per.getContactInfo().getEmail()).contains("john.brown@example.com"); @@ -67,17 +93,18 @@ public void testShouldParseWithExtraJson() throws FilingError, IOException { @Test public void testDontParseBadJson() throws FilingError, IOException { collector = new AllWrongCollector(); - assertThrows(FilingError.class, () -> fromNode(readString("\"abc\""), collector)); + assertThrows(FilingError.class, () -> fromNode(readString("\"abc\""), parser, collector)); collector = new AllWrongCollector(); - assertThrows(FilingError.class, () -> fromNode(readString("[{}]"), collector)); + assertThrows(FilingError.class, () -> fromNode(readString("[{}]"), parser, collector)); collector = new AllWrongCollector(); - fromNode(readString("{\"abc\": \"def\"}"), collector); + fromNode(readString("{\"abc\": \"def\"}"), parser, collector); assertThat(collector.getRequired()).hasSize(1); // only requires name } @Test public void testValidBirthDate() throws IOException, FilingError { - var res = fromNode(readTemplate("person_birthdate_template.json", "2000-11-02"), collector); + var res = + fromNode(readTemplate("person_birthdate_template.json", "2000-11-02"), parser, collector); assertThat(res.isOk()).isTrue(); var per = res.unwrapOrElseThrow(); assertThat(per.getBirthdate()).isPresent(); @@ -86,7 +113,8 @@ public void testValidBirthDate() throws IOException, FilingError { @Test public void testInvalidBirthDate() throws IOException, FilingError { - var res = fromNode(readTemplate("person_birthdate_template.json", "2000-11-32"), collector); + var res = + fromNode(readTemplate("person_birthdate_template.json", "2000-11-32"), parser, collector); assertThat(res.isOk()).isTrue(); var per = res.unwrapOrElseThrow(); assertThat(per.getBirthdate()).isEmpty(); @@ -95,14 +123,15 @@ public void testInvalidBirthDate() throws IOException, FilingError { @Test public void testIsNewNotABoolean() throws FilingError, IOException { collector = new AllWrongCollector(); - fromNode(readTemplate("person_new_id.json", "\"abc\"", "\"this will fail\""), collector); + fromNode( + readTemplate("person_new_id.json", "\"abc\"", "\"this will fail\""), parser, collector); assertThat(collector.getWrong()).hasSize(1); } @Test public void testIsNewAndEfmId() throws FilingError, IOException { collector = new AllWrongCollector(); - fromNode(readTemplate("person_new_id.json", "\"abc\"", "true"), collector); + fromNode(readTemplate("person_new_id.json", "\"abc\"", "true"), parser, collector); assertThat(collector.getWrong()).hasSize(1); assertThat(collector.getWrong().get(0).getDescription()) .contains("EFM (tyler) ID on a brand new party to the case"); @@ -111,7 +140,7 @@ public void testIsNewAndEfmId() throws FilingError, IOException { @Test public void testIsNotNewAndNoEfmId() throws FilingError, IOException { collector = new AllWrongCollector(); - fromNode(readTemplate("person_new_id.json", "null", "false"), collector); + fromNode(readTemplate("person_new_id.json", "null", "false"), parser, collector); assertThat(collector.getWrong()).hasSize(1); assertThat(collector.getWrong().get(0).getDescription()) .contains("Can't be marked as not new, but not have an EFM ID"); diff --git a/proxyserver/src/test/java/edu/suffolk/litlab/efsp/server/ecf4/tyler/TylerCodesParserTest.java b/proxyserver/src/test/java/edu/suffolk/litlab/efsp/server/ecf4/tyler/TylerCodesParserTest.java index 1d445f3ae..a781f7f7f 100644 --- a/proxyserver/src/test/java/edu/suffolk/litlab/efsp/server/ecf4/tyler/TylerCodesParserTest.java +++ b/proxyserver/src/test/java/edu/suffolk/litlab/efsp/server/ecf4/tyler/TylerCodesParserTest.java @@ -11,10 +11,12 @@ import edu.suffolk.litlab.efsp.ecfcodes.tyler.CourtLocationInfo; import edu.suffolk.litlab.efsp.ecfcodes.tyler.DataFieldRow; import edu.suffolk.litlab.efsp.ecfcodes.tyler.DataFields; +import edu.suffolk.litlab.efsp.ecfcodes.tyler.FilingCode; import edu.suffolk.litlab.efsp.ecfcodes.tyler.NameAndCode; import edu.suffolk.litlab.efsp.server.ecf4.CodesParser; import edu.suffolk.litlab.efsp.server.ecf4.CodesParser.BadCode; import edu.suffolk.litlab.efsp.server.ecf4.CodesParser.NoMatchingCode; +import edu.suffolk.litlab.efsp.server.ecf4.CodesParser.TooLongVar; import edu.suffolk.litlab.efsp.utils.FilingError; import java.util.List; import java.util.Optional; @@ -24,6 +26,7 @@ public class TylerCodesParserTest { CodesParser parser; + CodeDatabase cd; DataFields dataFields; CaseCategory exampleCategory = @@ -39,16 +42,34 @@ public class TylerCodesParserTest { new CaseType("456098", "Test Case Type", "123987", "true", "0", "", "", "01"); CaseType exampleCaseType2 = new CaseType("54321", "Test Case Type (no initial)", "123987", "false", "0", "", "", "01"); + FilingCode filingCode = + new FilingCode( + "777", + "", + "", + exampleCategory.code, + exampleCaseType.code, + "", + false, + "", + "", + "", + false, + false, + "", + "01"); @BeforeEach public void setUp() { - CodeDatabase cd = mock(CodeDatabase.class); + cd = mock(CodeDatabase.class); when(cd.getCaseCategoriesFor("01")).thenReturn(List.of(exampleCategory)); when(cd.getCaseCategoryWithCode("01", "123987")).thenReturn(Optional.of(exampleCategory)); when(cd.getCaseTypesFor("01", "123987", Optional.empty())) .thenReturn(List.of(exampleCaseType, exampleCaseType2)); when(cd.getCaseSubtypesFor("01", "456098")) .thenReturn(List.of(new NameAndCode("SubType code", "998877"))); + when(cd.getFilingType("01", exampleCategory.code, exampleCaseType.code, true)) + .thenReturn(List.of(filingCode)); var loc = new CourtLocationInfo("01"); loc.initial = true; @@ -135,4 +156,55 @@ public void testVetCaseSubTypeRequired() { var res = parser.vetSubType("998800", exampleCaseType); assertThat(res).containsErr(new NoMatchingCode("998800", List.of("998877"))); } + + @Test + public void testVetFilingCodesRestricted() { + when(cd.getFilingType("01", exampleCategory.code, exampleCaseType.code, true)) + .thenReturn(List.of()); + var res = parser.retrieveFilingOptions(exampleCategory, exampleCaseType, true); + assertThat(res) + .containsErr( + new BadCode( + FilingError.malformedInterview( + "Need a filing type! FilingTypes are empty, so 123987, Test Category, and 456098, Test Case Type, 123987, true, 0.0, , , 01 are restricted"))); + } + + @Test + public void testSuffixVisibleNotVisible() { + when(dataFields.getFieldRow("PartyNameSuffix")) + .thenReturn(DataFieldRow.MissingDataField("PartyNameSuffix")); + var res = parser.vetSuffix(Optional.empty()); + assertThat(res).containsOk(""); + } + + @Test + public void testSuffixVisibleAndRequired() { + when(dataFields.getFieldRow("PartyNameSuffix")) + .thenReturn(new DataFieldRow("PartyNameSuffix", "suffix", true, true, "01")); + var res = parser.vetSuffix(Optional.empty()); + assertThat(res).containsErr(new NoMatchingCode("", List.of())); + } + + @Test + public void testSuffixVisibleAndPresent() { + when(dataFields.getFieldRow("PartyNameSuffix")) + .thenReturn(new DataFieldRow("PartyNameSuffix", "suffix", true, true, "01")); + when(cd.getNameSuffixes("01")).thenReturn(List.of(new NameAndCode("MD", "MD"))); + var res = parser.vetSuffix(Optional.of("md")); + assertThat(res).containsOk("MD"); + } + + @Test + public void testNameTooLong() { + when(dataFields.getFieldRow("PartyFirstName")) + .thenReturn(new DataFieldRow("PartyFirstName", "first name", true, true, "01")); + String longName = + "abcdefghijklmnopqrstuvwxyz" + + "abcdefghijklmnopqrstuvwxyz" + + "abcdefghijklmnopqrstuvwxyz" + + "abcdefghijklmnopqrstuvwxyz" + + "abcdefghijklmnopqrstuvwxyz"; + var res = parser.vetFirstName(Optional.of(longName)); + assertThat(res).containsErr(new TooLongVar(longName, 100)); + } }