Skip to content

Commit

Permalink
Cover additional validation case, validator re-factoring
Browse files Browse the repository at this point in the history
  • Loading branch information
MikeEdgar committed Mar 7, 2020
1 parent 3bff846 commit 57e39a5
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ public static boolean hasMinimumUsage(UsageNode node) {
return node == null || node.hasMinimumUsage();
}

public static UsageNode getParent(UsageNode node) {
return node != null ? node.getParent() : null;
}

public static UsageNode getFirstChild(UsageNode node) {
return node != null ? node.getFirstChild() : null;
}

@Override
public String toString() {
return String.format(TOSTRING_FORMAT, usageCount, depth, link);
Expand Down
186 changes: 106 additions & 80 deletions src/main/java/io/xlate/edi/internal/stream/validation/Validator.java
Original file line number Diff line number Diff line change
Expand Up @@ -281,13 +281,7 @@ public void validateSegment(ValidationEventHandler handler, CharSequence tag) {
checkMinimumUsage(current);

UsageNode next = current.getNextSibling();
UsageNode nextImpl = currentImpl;

while (nextImpl != null && nextImpl.getReferencedType().equals(current.getReferencedType())) {
// Advance past multiple implementations of the 'current' standard node
checkMinimumUsage(nextImpl);
nextImpl = nextImpl.getNextSibling();
}
UsageNode nextImpl = checkMinimumImplUsage(currentImpl, current);

if (next != null) {
// Advance to the next segment in the loop
Expand All @@ -301,12 +295,12 @@ public void validateSegment(ValidationEventHandler handler, CharSequence tag) {

if (!handled) {
if (this.depth > 1) {
current = current.getParent();
currentImpl = currentImpl != null ? currentImpl.getParent() : null;
current = UsageNode.getParent(current);
currentImpl = UsageNode.getParent(currentImpl);
this.depth--;
} else {
current = this.root.getFirstChild();
currentImpl = this.implRoot != null ? this.implRoot.getFirstChild() : null;
current = UsageNode.getFirstChild(this.root);
currentImpl = UsageNode.getFirstChild(this.implRoot);
handled = checkUnexpectedSegment(tag, current, startDepth, handler);
}
}
Expand All @@ -317,6 +311,16 @@ public void validateSegment(ValidationEventHandler handler, CharSequence tag) {
handleMissingMandatory(handler);
}

UsageNode checkMinimumImplUsage(UsageNode nextImpl, UsageNode current) {
while (nextImpl != null && nextImpl.getReferencedType().equals(current.getReferencedType())) {
// Advance past multiple implementations of the 'current' standard node
checkMinimumUsage(nextImpl);
nextImpl = nextImpl.getNextSibling();
}

return nextImpl;
}

boolean handleNode(CharSequence tag, UsageNode current, UsageNode currentImpl, int startDepth, ValidationEventHandler handler) {
final boolean handled;

Expand Down Expand Up @@ -670,6 +674,14 @@ public List<UsageError> getElementErrors() {
return elementErrors;
}

boolean isImplElementSelected() {
return implSegmentSelected && this.implElement != null;
}

boolean isImplUnusedElementPresent() {
return implSegmentSelected && this.implElement == null;
}

public boolean validCompositeOccurrences(Location position) {
if (!segmentExpected) {
return true;
Expand Down Expand Up @@ -719,7 +731,7 @@ public boolean validCompositeOccurrences(Location position) {
return false;
}

if (implSegmentSelected && this.implElement == null) {
if (isImplUnusedElementPresent()) {
elementErrors.add(new UsageError(composite, IMPLEMENTATION_UNUSED_DATA_ELEMENT_PRESENT));
return false;
}
Expand Down Expand Up @@ -756,6 +768,7 @@ public boolean validateElement(Dialect dialect, StaEDIStreamLocation position, C

if (implSegmentSelected && elementPosition > 0 && componentIndex < 0) {
UsageNode previousImpl = implSegment.getChild(elementPosition - 1);

if (tooFewRepetitions(previousImpl)) {
elementErrors.add(new UsageError(previousImpl, IMPLEMENTATION_TOO_FEW_REPETITIONS));
}
Expand Down Expand Up @@ -794,34 +807,8 @@ public boolean validateElement(Dialect dialect, StaEDIStreamLocation position, C
}

if (componentIndex > -1) {
if (!isComposite) {
/*
* This element has components but is not defined as a composite
* structure.
*/
elementErrors.add(new UsageError(this.element, TOO_MANY_COMPONENTS));
} else {
if (componentIndex == 0) {
this.element.resetChildren();
if (this.implSegmentSelected && this.implElement != null) {
this.implElement.resetChildren();
}
}

if (componentIndex < element.getChildren().size()) {
if (valueReceived || !derivedComposite) {
this.element = this.element.getChild(componentIndex);

if (this.implSegmentSelected && this.implElement != null) {
this.implElement = this.implElement.getChild(componentIndex);
}
}
} else {
elementErrors.add(new UsageError(this.element, TOO_MANY_COMPONENTS));
}
}
//TODO: for components - elementErrors.add(new UsageError(this.element, IMPLEMENTATION_UNUSED_DATA_ELEMENT_PRESENT));
} else if (implSegmentSelected && this.implElement == null) {
validateComponentElement(componentIndex, valueReceived, derivedComposite);
} else if (isImplUnusedElementPresent()) {
// Validated in validCompositeOccurrences for received composites
elementErrors.add(new UsageError(this.element, IMPLEMENTATION_UNUSED_DATA_ELEMENT_PRESENT));
}
Expand All @@ -831,42 +818,77 @@ public boolean validateElement(Dialect dialect, StaEDIStreamLocation position, C
}

if (valueReceived) {
if (!isComposite) {
this.element.incrementUsage();
validateElementValue(dialect, value);
} else {
if (!UsageNode.hasMinimumUsage(element) || !UsageNode.hasMinimumUsage(implElement)) {
elementErrors.add(new UsageError(this.element, REQUIRED_DATA_ELEMENT_MISSING));
}
}

if (this.implElement != null) {
this.implElement.incrementUsage();
}
return elementErrors.isEmpty();
}

void validateComponentElement(int componentIndex, boolean valueReceived, boolean derivedComposite) {
if (!element.isNodeType(EDIType.Type.COMPOSITE)) {
/*
* This element has components but is not defined as a composite
* structure.
*/
elementErrors.add(new UsageError(this.element, TOO_MANY_COMPONENTS));
} else {
if (componentIndex == 0) {
this.element.resetChildren();

if (this.element.exceedsMaximumUsage()) {
elementErrors.add(new UsageError(this.element, TOO_MANY_REPETITIONS));
if (isImplElementSelected()) {
this.implElement.resetChildren();
}
}

List<EDIStreamValidationError> errors = new ArrayList<>();
this.element.validate(dialect, value, errors);
if (componentIndex < element.getChildren().size()) {
if (valueReceived || !derivedComposite) {
this.element = this.element.getChild(componentIndex);

for (EDIStreamValidationError error : errors) {
elementErrors.add(new UsageError(this.element, error));
if (isImplElementSelected()) {
this.implElement = this.implElement.getChild(componentIndex);
}
}
} else {
elementErrors.add(new UsageError(this.element, TOO_MANY_COMPONENTS));
}
}
//TODO: for components - elementErrors.add(new UsageError(this.element, IMPLEMENTATION_UNUSED_DATA_ELEMENT_PRESENT));
}

if (errors.isEmpty() && implSegmentSelected && implElement != null) {
this.implElement.validate(dialect, value, errors);
void validateElementValue(Dialect dialect, CharSequence value) {
if (!element.isNodeType(EDIType.Type.COMPOSITE)) {
this.element.incrementUsage();

for (EDIStreamValidationError error : errors) {
if (error == INVALID_CODE_VALUE) {
error = IMPLEMENTATION_INVALID_CODE_VALUE;
}
elementErrors.add(new UsageError(this.element, error));
}
if (this.implElement != null) {
this.implElement.incrementUsage();
}
} else {
if (!UsageNode.hasMinimumUsage(element) || !UsageNode.hasMinimumUsage(implElement)) {
elementErrors.add(new UsageError(this.element, REQUIRED_DATA_ELEMENT_MISSING));

if (this.element.exceedsMaximumUsage()) {
elementErrors.add(new UsageError(this.element, TOO_MANY_REPETITIONS));
}
}

return elementErrors.isEmpty();
List<EDIStreamValidationError> errors = new ArrayList<>();
this.element.validate(dialect, value, errors);

for (EDIStreamValidationError error : errors) {
elementErrors.add(new UsageError(this.element, error));
}

if (errors.isEmpty() && implSegmentSelected && implElement != null) {
this.implElement.validate(dialect, value, errors);

for (EDIStreamValidationError error : errors) {
if (error == INVALID_CODE_VALUE) {
error = IMPLEMENTATION_INVALID_CODE_VALUE;
}
elementErrors.add(new UsageError(this.element, error));
}
}
}

public void validateSyntax(ElementDataHandler handler, ValidationEventHandler validationHandler, final StaEDIStreamLocation location, final boolean isComposite) {
Expand All @@ -876,23 +898,9 @@ public void validateSyntax(ElementDataHandler handler, ValidationEventHandler va
}

final UsageNode structure = isComposite ? composite : segment;

final int index;
int elementPosition = location.getElementPosition() - 1;
int componentIndex = location.getComponentPosition() - 1;

if (isComposite) {
int componentPosition = location.getComponentPosition();

if (componentPosition < 1) {
index = 1;
} else {
index = componentPosition;
}
} else {
index = location.getElementPosition();
}

final int index = getCurrentIndex(location, isComposite);
final int elementPosition = location.getElementPosition() - 1;
final int componentIndex = location.getComponentPosition() - 1;
final List<UsageNode> children = structure.getChildren();

for (int i = index, max = children.size(); i < max; i++) {
Expand Down Expand Up @@ -932,4 +940,22 @@ boolean tooFewRepetitions(UsageNode node) {

return false;
}

int getCurrentIndex(Location location, boolean isComposite) {
final int index;

if (isComposite) {
int componentPosition = location.getComponentPosition();

if (componentPosition < 1) {
index = 1;
} else {
index = componentPosition;
}
} else {
index = location.getElementPosition();
}

return index;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public void testInvalidCompositeOccurrences() throws EDISchemaException, EDIStre
+ "S99*X:X~" // SEGMENT_NOT_IN_DEFINED_TRANSACTION_SET
+ "S12*A^B**X~" // REQUIRED_DATA_ELEMENT_MISSING (S1202), IMPLEMENTATION_TOO_FEW_REPETITIONS (S1203)
+ "S12*A*X:Y*1^2*YY~" // IMPLEMENTATION_TOO_FEW_REPETITIONS (S1201)
+ "S13*A*1234567890~" // IMPLEMENTATION_TOO_FEW_REPETITIONS (S1202)
+ "S09*X~"
+ "IEA*1*508121953~").getBytes());

Expand Down Expand Up @@ -127,6 +128,10 @@ public boolean accept(EDIStreamReader reader) {
assertEquals(EDIStreamValidationError.IMPLEMENTATION_INVALID_CODE_VALUE, reader.getErrorType());
assertEquals("E003", reader.getReferenceCode());

assertEquals(EDIStreamEvent.ELEMENT_OCCURRENCE_ERROR, reader.next());
assertEquals(EDIStreamValidationError.IMPLEMENTATION_TOO_FEW_REPETITIONS, reader.getErrorType());
assertEquals("E002", reader.getReferenceCode());

assertTrue(!reader.hasNext(), "Unexpected segment errors exist");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
</loop>

<segment type="S12" maxOccurs="5" />
<segment type="S13" maxOccurs="1" />
</sequence>
</transaction>

Expand Down Expand Up @@ -95,6 +96,13 @@
</element>
</sequence>
</segment>

<segment type="S13">
<sequence>
<element position="1" />
<element position="2" minOccurs="2" />
</sequence>
</segment>
</sequence>
</implementation>

Expand Down Expand Up @@ -145,4 +153,11 @@
<element type="E003" />
</sequence>
</segmentType>

<segmentType name="S13">
<sequence>
<element type="E001" />
<element type="E002" />
</sequence>
</segmentType>
</schema>

0 comments on commit 57e39a5

Please sign in to comment.