Repository: decorators-squad/eo-yaml (java)

Issue:
Created empty sequences are invalid on parsing
I just noticed that Camel creates empty sequences that it then can't parse successfully.

Steps to reproduce:
- Create a YamlMapping and add a YamlSequence with no elements and any key.
- Add at least one other key-value pair to the YamlMapping
- Call `toString()` and write the String to a file.
- Read the file via `YamlMapping m = Yaml.createYamlInput(InputStream).readYamlMapping()`
- Extract the empty YamlSequence via `m.yamlSequence(key)`

Expected behaviour:
The last call should return null as there is no yamlSequence there.

Actual behaviour:
An IllegalStateException occurs:

    Exception in thread "main" java.lang.IllegalStateException: Indentation of line 1 isn't ok.  It should be greater than the previous line's by 2
    	at com.amihaiemil.camel.WellIndentedLine.indentation(WellIndentedLine.java:77)
    	at com.amihaiemil.camel.CachedYamlLine.indentation(CachedYamlLine.java:89)
    	at com.amihaiemil.camel.RtYamlLines.iterator(RtYamlLines.java:44)
    	at com.amihaiemil.camel.ReadYamlMapping.nodeValue(ReadYamlMapping.java:161)
    	at com.amihaiemil.camel.ReadYamlMapping.yamlSequence(ReadYamlMapping.java:101)

Example:
Camel produces this YAML file, which triggers the above error

    emptyseq:
    
    key1: val1
    key2: val2

A simple fix is to write the empty sequence in JSON notation

    emptyseq: []
    
    key1: val1
    key2: val2

This parses correctly, although `yamlSequence("emptyseq")` does now not return null but an empty YamlSequence.

Pull request:
#134 read the null Scalar + tests
Fixes #134 
Final step:
* read the ``null`` YAML keyword as a Scalar with ``null`` value.
* added unit tests

Patch:
diff --git a/src/main/java/com/amihaiemil/eoyaml/ReadPlainScalar.java b/src/main/java/com/amihaiemil/eoyaml/ReadPlainScalar.java
index e729347..9aaba5d 100644
--- a/src/main/java/com/amihaiemil/eoyaml/ReadPlainScalar.java
+++ b/src/main/java/com/amihaiemil/eoyaml/ReadPlainScalar.java
@@ -59,6 +59,13 @@ final class ReadPlainScalar extends BaseScalar {
         this.scalar = scalar;
     }
 
+    /**
+     * Unescaped String value of this scalar. Pay attention, if the
+     * scalar's value is the "null" String, then we return null, because
+     * "null" is a reserved keyword in YAML, indicating a null Scalar.
+     * @checkstyle ReturnCount (50 lines)
+     * @return String or null if the Strings value is "null".
+     */
     @Override
     public String value() {
         final String value;
@@ -70,7 +77,11 @@ final class ReadPlainScalar extends BaseScalar {
         } else {
             value = trimmed;
         }
-        return this.unescape(value);
+        if("null".equals(value)) {
+            return null;
+        } else {
+            return this.unescape(value);
+        }
     }
 
     @Override


Test patch:
diff --git a/src/test/java/com/amihaiemil/eoyaml/ReadPlainScalarTest.java b/src/test/java/com/amihaiemil/eoyaml/ReadPlainScalarTest.java
index 619875e..7a7f4e0 100644
--- a/src/test/java/com/amihaiemil/eoyaml/ReadPlainScalarTest.java
+++ b/src/test/java/com/amihaiemil/eoyaml/ReadPlainScalarTest.java
@@ -54,6 +54,31 @@ public final class ReadPlainScalarTest {
         MatcherAssert.assertThat(scalar.value(), Matchers.equalTo("value"));
     }
 
+    /**
+     * ReadPlainScalar can return the scalar's null value from a mapping line.
+     */
+    @Test
+    public void returnsNullValueFromMappingLine() {
+        final Scalar scalar = new ReadPlainScalar(
+            new AllYamlLines(new ArrayList<>()),
+            new RtYamlLine("key: null", 0)
+        );
+        MatcherAssert.assertThat(scalar.value(), Matchers.nullValue());
+    }
+
+    /**
+     * ReadPlainScalar can return the "null" String value from a mapping line,
+     * because it is escaped.
+     */
+    @Test
+    public void returnsEscapedNullStringFromMappingLine() {
+        final Scalar scalar = new ReadPlainScalar(
+            new AllYamlLines(new ArrayList<>()),
+            new RtYamlLine("key: 'null'", 0)
+        );
+        MatcherAssert.assertThat(scalar.value(), Matchers.equalTo("null"));
+    }
+
     /**
      * ReadPlainScalar can return the scalar's value from a sequence line.
      */
@@ -66,6 +91,31 @@ public final class ReadPlainScalarTest {
         MatcherAssert.assertThat(scalar.value(), Matchers.equalTo("value"));
     }
 
+    /**
+     * ReadPlainScalar can return the scalar's null value from a sequence line.
+     */
+    @Test
+    public void returnsNullValueFromSequenceLine() {
+        final Scalar scalar = new ReadPlainScalar(
+            new AllYamlLines(new ArrayList<>()),
+            new RtYamlLine("- null", 0)
+        );
+        MatcherAssert.assertThat(scalar.value(), Matchers.nullValue());
+    }
+
+    /**
+     * ReadPlainScalar can return the "null" String, because
+     * it is escaped.
+     */
+    @Test
+    public void returnsEscapedNullStringFromSequenceLine() {
+        final Scalar scalar = new ReadPlainScalar(
+            new AllYamlLines(new ArrayList<>()),
+            new RtYamlLine("- \"null\"", 0)
+        );
+        MatcherAssert.assertThat(scalar.value(), Matchers.equalTo("null"));
+    }
+
     /**
      * ReadPlainScalar can return the comment referring to a scalar
      * in a sequence.
@@ -121,6 +171,33 @@ public final class ReadPlainScalarTest {
         MatcherAssert.assertThat(scalar.value(), Matchers.equalTo("value"));
     }
 
+    /**
+     * ReadPlainScalar will return the null scalar.
+     */
+    @Test
+    public void returnsNullScalar() {
+        final YamlLine line = new RtYamlLine("null", 0);
+        final Scalar scalar = new ReadPlainScalar(
+                new AllYamlLines(new ArrayList<>()),
+                line
+        );
+        MatcherAssert.assertThat(scalar.value(), Matchers.nullValue());
+    }
+
+    /**
+     * ReadPlainScalar will return the "null" String scalar, not null,
+     * because it is escaped.
+     */
+    @Test
+    public void returnsEscapedNullScalar() {
+        final YamlLine line = new RtYamlLine("'null'", 0);
+        final Scalar scalar = new ReadPlainScalar(
+            new AllYamlLines(new ArrayList<>()),
+            line
+        );
+        MatcherAssert.assertThat(scalar.value(), Matchers.equalTo("null"));
+    }
+
     /**
      * ReadPlainScalar will return empty string if the line is empty.
      * Should never be the case in real practice, however, because empty