Repository: xlate/staedi (java)

Issue:
Incorrect output for premature UNB delimiter (EDIFACT)
From @javaduke in Gitter channel (https://gitter.im/xlate/staedi)

```
'UNA:+.? '
UNB+UNOA:3
UNH+00000000000117+CONTRL:4:1:UN'
UCI+00000000000778+1+1+8++++'
UNT+1+00000000000117'
UNZ+1+00000000000778'
```
> note the single quote before UNA and no single quote at the end of the UNB

Pull request description:
Fix handling of UNB terminated prematurely
Fixes #167 

Patch:
diff --git a/src/main/java/io/xlate/edi/internal/stream/StaEDIStreamWriter.java b/src/main/java/io/xlate/edi/internal/stream/StaEDIStreamWriter.java
index 73b0b04..4d59362 100644
--- a/src/main/java/io/xlate/edi/internal/stream/StaEDIStreamWriter.java
+++ b/src/main/java/io/xlate/edi/internal/stream/StaEDIStreamWriter.java
@@ -321,6 +321,7 @@ public class StaEDIStreamWriter implements EDIStreamWriter, ElementDataHandler,
         case HEADER_DATA:
         case HEADER_ELEMENT_END:
         case HEADER_COMPONENT_END:
+        case HEADER_SEGMENT_END:
             writeHeader((char) output);
             break;
         case INVALID:
@@ -353,6 +354,9 @@ public class StaEDIStreamWriter implements EDIStreamWriter, ElementDataHandler,
             case HEADER_COMPONENT_END:
                 state = State.COMPONENT_END;
                 break;
+            case HEADER_SEGMENT_END:
+                state = State.SEGMENT_END;
+                break;
             default:
                 throw new IllegalStateException("Confirmed at state " + state);
             }
diff --git a/src/main/java/io/xlate/edi/internal/stream/tokenization/EDIFACTDialect.java b/src/main/java/io/xlate/edi/internal/stream/tokenization/EDIFACTDialect.java
index 0b71115..037161b 100644
--- a/src/main/java/io/xlate/edi/internal/stream/tokenization/EDIFACTDialect.java
+++ b/src/main/java/io/xlate/edi/internal/stream/tokenization/EDIFACTDialect.java
@@ -23,8 +23,6 @@ public class EDIFACTDialect extends Dialect {
     public static final String UNA = "UNA";
     public static final String UNB = "UNB";
 
-    private static final String[] EMPTY = new String[0];
-
     static final char DFLT_SEGMENT_TERMINATOR = '\'';
     static final char DFLT_DATA_ELEMENT_SEPARATOR = '+';
     static final char DFLT_COMPONENT_ELEMENT_SEPARATOR = ':';
@@ -109,14 +107,15 @@ public class EDIFACTDialect extends Dialect {
     }
 
     private String[] parseVersion() {
-        int versionStart = findVersionStart();
-        int versionEnd = header.indexOf(String.valueOf(elementDelimiter), versionStart);
+        final int versionStart = findVersionStart();
+        String versionComposite = findVersionString(versionStart, elementDelimiter);
 
-        if (versionEnd - versionStart > 1) {
-            return header.substring(versionStart, versionEnd).split('\\' + String.valueOf(componentDelimiter));
+        if (versionComposite == null) {
+            // Handle the case where the segment was terminated prematurely (zero or one element)
+            versionComposite = findVersionString(versionStart, segmentDelimiter);
         }
 
-        return EMPTY;
+        return versionComposite.split('\\' + String.valueOf(componentDelimiter));
     }
 
     int findVersionStart() {
@@ -124,6 +123,16 @@ public class EDIFACTDialect extends Dialect {
         return UNB.equals(headerTag) ? 4 : unbStart + 4;
     }
 
+    String findVersionString(int versionStart, char delimiter) {
+        final int versionEnd = header.indexOf(String.valueOf(delimiter), versionStart);
+
+        if (versionEnd - versionStart > -1) {
+            return header.substring(versionStart, versionEnd);
+        }
+
+        return null;
+    }
+
     @Override
     public boolean isServiceAdviceSegment(CharSequence tag) {
         return UNA.contentEquals(tag);
@@ -214,7 +223,7 @@ public class EDIFACTDialect extends Dialect {
             if (characters.isIgnored(value)) {
                 header.deleteCharAt(index--);
             } else if (isIndexBeyondUNBFirstElement()) {
-                if (value == elementDelimiter) {
+                if (value == elementDelimiter || value == segmentDelimiter) {
                     rejected = !initialize(characters);
                     proceed = isConfirmed();
                 }


Test patch:
diff --git a/src/test/java/io/xlate/edi/internal/stream/StaEDIStreamWriterTest.java b/src/test/java/io/xlate/edi/internal/stream/StaEDIStreamWriterTest.java
index 453070a..bbd0f1e 100644
--- a/src/test/java/io/xlate/edi/internal/stream/StaEDIStreamWriterTest.java
+++ b/src/test/java/io/xlate/edi/internal/stream/StaEDIStreamWriterTest.java
@@ -2094,4 +2094,27 @@ class StaEDIStreamWriterTest {
 
         assertEquals("UNB+UNO1:1++++'ISA+??????'", new String(stream.toByteArray()));
     }
+
+    @Test
+    void testIncompleteUNB() throws IOException, EDIStreamException, EDISchemaException {
+        final EDIOutputFactory factory = EDIOutputFactory.newFactory();
+        ByteArrayOutputStream stream = new ByteArrayOutputStream(4096);
+
+        try (EDIStreamWriter writer = factory.createEDIStreamWriter(stream)) {
+            writer.startInterchange();
+            writer.writeStartSegment("UNA")
+                .writeEndSegment();
+            writer.writeStartSegment("UNB")
+                .writeStartElement()
+                    .writeComponent("UNOA")
+                    .writeComponent("3")
+                .endElement()
+                .writeEndSegment();
+
+            writer.writeStartSegment("UNH");
+            writer.flush();
+        }
+
+        assertEquals("UNA:+.? 'UNB+UNOA:3'UNH", new String(stream.toByteArray()));
+    }
 }