Repository: xlate/staedi (java)

Issue:
Allow leading zeros in X12 trailer segment counts
For example, GE-01 and IEA-01 should allow `00001` instead of just `1`.

Relevant code: https://github.com/xlate/staedi/blob/920bccbdcbc7517fc454f12e46f2a20247870424/src/main/java/io/xlate/edi/internal/stream/validation/ControlUsageNode.java#L63

Relevant quotes:

1. https://x12.org/resources/requests-for-interpretation/rfi-1750-allow-lead-0-value-code-amt

    > Leading zeros should be suppressed unless necessary to satisfy a minimum length requirement. The word “should” indicates a recommendation; the word "shall" indicates a requirement.
    
    > Until corrections are made with the next guide, receivers must allow, but not require, leading zeroes

2. https://www.stedi.com/blog/control-numbers-in-x12-edi

    > Numbers should only be padded with zeros if those zeros are necessary to meet the minimum length requirement. Despite of this, you’ll see a lot of group control numbers that include leading zeros.
    
    > Your safest option is to accept leading zeros in the control numbers you receive, and only include them when required for the control numbers you send.

Pull request description:
fix: strip leading zeros before comparing trailer control counts
Fixes #526 

Patch:
diff --git a/src/main/java/io/xlate/edi/internal/stream/validation/ControlUsageNode.java b/src/main/java/io/xlate/edi/internal/stream/validation/ControlUsageNode.java
index 4dc1d97..3b903c4 100644
--- a/src/main/java/io/xlate/edi/internal/stream/validation/ControlUsageNode.java
+++ b/src/main/java/io/xlate/edi/internal/stream/validation/ControlUsageNode.java
@@ -60,11 +60,27 @@ class ControlUsageNode extends UsageNode {
         if (matchesLocation(type.getReferences().size() - 1, type.getTrailerCountPosition(), location)
                 // Don't bother comparing the actual value if it's not formatted correctly
                 && !errors.contains(EDIStreamValidationError.INVALID_CHARACTER_DATA)
-                && !String.valueOf(count).contentEquals(value)) {
+                && !countEqualsActual(value)) {
             errors.add(EDIStreamValidationError.CONTROL_COUNT_DOES_NOT_MATCH_ACTUAL_COUNT);
         }
     }
 
+    /**
+     * Check whether the actual number counted matches the count given by the
+     * input. Leading zeros are stripped from the input string.
+     */
+    boolean countEqualsActual(CharSequence value) {
+        int i = 0;
+        int len = value.length();
+        int max = len - 1;
+
+        while (i < max && value.charAt(i) == '0') {
+            i++;
+        }
+
+        return Integer.toString(count).contentEquals(value.subSequence(i, len));
+    }
+
     int incrementCount(EDIControlType.Type countType) {
         if (this.type.getCountType() == countType) {
             count++;


Test patch:
diff --git a/src/test/java/io/xlate/edi/internal/stream/ErrorEventsTest.java b/src/test/java/io/xlate/edi/internal/stream/ErrorEventsTest.java
index 1b0b687..91e3893 100644
--- a/src/test/java/io/xlate/edi/internal/stream/ErrorEventsTest.java
+++ b/src/test/java/io/xlate/edi/internal/stream/ErrorEventsTest.java
@@ -288,7 +288,7 @@ class ErrorEventsTest {
                 + "UXA+1'"
                 + "UXC+1'"
                 + "UNT+4+00000000000117'"
-                + "UNZ+1+00000000000001'").getBytes());
+                + "UNZ+0001+00000000000001'").getBytes());
 
         EDIStreamReader reader = factory.createEDIStreamReader(stream);
         reader = factory.createFilteredReader(reader, (rdr) -> {
@@ -331,7 +331,7 @@ class ErrorEventsTest {
                 + "S12*X~"
                 + "S19*X~"
                 + "S09*X~"
-                + "IEA*0*508121953~").getBytes());
+                + "IEA*00*508121953~").getBytes());
 
         SchemaFactory schemaFactory = SchemaFactory.newFactory();
         URL schemaLocation = getClass().getResource("/x12/EDISchemaSegmentValidation.xml");