Repository: decorators-squad/eo-yaml
Pull request #247 (2020-03-28 12:58:31)

Fixed Scalar Printing for YamlSequence
PR for #230 

* we fixed printing of Scalar in the case of YamlSequence
* fixed reading of Scalar in ReadYamlSequence
* added tests for full printing of YamlSequence with all types of nodes we have so far

Next: same fixes for YamlMapping


Patch:
diff --git a/src/main/java/com/amihaiemil/eoyaml/BaseYamlSequence.java b/src/main/java/com/amihaiemil/eoyaml/BaseYamlSequence.java
index aa64193..adf7b1f 100644
--- a/src/main/java/com/amihaiemil/eoyaml/BaseYamlSequence.java
+++ b/src/main/java/com/amihaiemil/eoyaml/BaseYamlSequence.java
@@ -143,21 +143,21 @@ abstract class BaseYamlSequence extends BaseYamlNode implements YamlSequence {
         final String newLine = System.lineSeparator();
         final StringBuilder print = new StringBuilder();
         int spaces = indentation;
-        final StringBuilder indent = new StringBuilder();
+        final StringBuilder alignment = new StringBuilder();
         while (spaces > 0) {
-            indent.append(" ");
+            alignment.append(" ");
             spaces--;
         }
         for (final YamlNode node : this.values()) {
-            final BaseYamlNode indentable = (BaseYamlNode) node;
-            print.append(indent)
+            print
+                .append(alignment)
                 .append("- ");
-            if (indentable instanceof Scalar) {
-                print.append(indentable.indent(0)).append(newLine);
+            if (node instanceof Scalar) {
+                this.printScalar((Scalar) node, print, indentation);
             } else  {
                 print
                     .append(newLine)
-                    .append(indentable.indent(indentation + 2))
+                    .append(((BaseYamlNode) node).indent(indentation + 2))
                     .append(newLine);
             }
         }
@@ -168,6 +168,47 @@ abstract class BaseYamlSequence extends BaseYamlNode implements YamlSequence {
         return printed;
     }
 
+    /**
+     * Print a Scalar. We need to check what kind of Scalar is it.
+     * If it's a plain scalar, we print it on the same line. If it's
+     * a folded or literal scalar, we must first print a line containing
+     * '>' or '|', then print the Scalar's lines bellow, with a +2 indentation.
+     * @checkstyle LineLength (50 lines)
+     * @param scalar YamlNode scalar.
+     * @param print Printer to add it to.
+     * @param indentation How much to indent it?
+     */
+    private void printScalar(
+        final Scalar scalar,
+        final StringBuilder print,
+        final int indentation
+    ) {
+        final BaseScalar indentable = (BaseScalar) scalar;
+        if (indentable instanceof PlainStringScalar
+            || indentable instanceof ReadPlainScalarValue
+        ) {
+            print.append(indentable.indent(0)).append(System.lineSeparator());
+        } else if (indentable instanceof RtYamlScalarBuilder.BuiltFoldedBlockScalar
+            || indentable instanceof ReadFoldedBlockScalar
+        ) {
+            print
+                .append(">")
+                .append(System.lineSeparator())
+                .append(
+                    indentable.indent(indentation + 2)
+                ).append(System.lineSeparator());
+        } else if (indentable instanceof RtYamlScalarBuilder.BuiltLiteralBlockScalar
+            || indentable instanceof ReadLiteralBlockScalar
+        ) {
+            print
+                .append("|")
+                .append(System.lineSeparator())
+                .append(
+                    indentable.indent(indentation + 2)
+                ).append(System.lineSeparator());
+        }
+    }
+
     /**
      * When printing a YamlSequence, just call this.indent(0), no need for
      * other wrappers.
diff --git a/src/main/java/com/amihaiemil/eoyaml/ReadFoldedBlockScalar.java b/src/main/java/com/amihaiemil/eoyaml/ReadFoldedBlockScalar.java
index 4cf8932..9335820 100644
--- a/src/main/java/com/amihaiemil/eoyaml/ReadFoldedBlockScalar.java
+++ b/src/main/java/com/amihaiemil/eoyaml/ReadFoldedBlockScalar.java
@@ -54,7 +54,11 @@ final class ReadFoldedBlockScalar extends BaseScalar {
      * @param lines Given lines to represent.
      */
     ReadFoldedBlockScalar(final YamlLines lines) {
-        this.lines = lines;
+        this.lines = new NoScalarMarkers(
+            new NoDirectivesOrMarkers(
+                lines
+            )
+        );
     }
 
     @Override
diff --git a/src/main/java/com/amihaiemil/eoyaml/ReadLiteralBlockScalar.java b/src/main/java/com/amihaiemil/eoyaml/ReadLiteralBlockScalar.java
index 6dcff1d..75600a1 100644
--- a/src/main/java/com/amihaiemil/eoyaml/ReadLiteralBlockScalar.java
+++ b/src/main/java/com/amihaiemil/eoyaml/ReadLiteralBlockScalar.java
@@ -54,7 +54,11 @@ final class ReadLiteralBlockScalar extends BaseScalar {
      * @param lines Given lines to represent.
      */
     ReadLiteralBlockScalar(final YamlLines lines) {
-        this.lines = lines;
+        this.lines = new NoScalarMarkers(
+            new NoDirectivesOrMarkers(
+                lines
+            )
+        );
     }
 
     @Override
diff --git a/src/main/java/com/amihaiemil/eoyaml/ReadYamlSequence.java b/src/main/java/com/amihaiemil/eoyaml/ReadYamlSequence.java
index 0b6ebe6..84eec68 100644
--- a/src/main/java/com/amihaiemil/eoyaml/ReadYamlSequence.java
+++ b/src/main/java/com/amihaiemil/eoyaml/ReadYamlSequence.java
@@ -63,7 +63,11 @@ final class ReadYamlSequence extends BaseYamlSequence {
     public Collection<YamlNode> values() {
         final List<YamlNode> kids = new LinkedList<>();
         for(final YamlLine line : this.lines) {
-            if("-".equals(line.trimmed())) {
+            final String trimmed = line.trimmed();
+            if("-".equals(trimmed)
+                || trimmed.endsWith("|")
+                || trimmed.endsWith(">")
+            ) {
                 kids.add(this.lines.nested(line.number()).toYamlNode(line));
             } else {
                 kids.add(new ReadPlainScalarValue(line));
diff --git a/src/main/java/com/amihaiemil/eoyaml/RtYamlInput.java b/src/main/java/com/amihaiemil/eoyaml/RtYamlInput.java
index 1483790..6d4dced 100644
--- a/src/main/java/com/amihaiemil/eoyaml/RtYamlInput.java
+++ b/src/main/java/com/amihaiemil/eoyaml/RtYamlInput.java
@@ -87,24 +87,12 @@ final class RtYamlInput implements YamlInput {
 
     @Override
     public Scalar readFoldedBlockScalar() throws IOException {
-        return new ReadFoldedBlockScalar(
-            new NoScalarMarkers(
-                new NoDirectivesOrMarkers(
-                    this.readInput()
-                )
-            )
-        );
+        return new ReadFoldedBlockScalar(this.readInput());
     }
 
     @Override
     public Scalar readLiteralBlockScalar() throws IOException {
-        return new ReadLiteralBlockScalar(
-            new NoScalarMarkers(
-                new NoDirectivesOrMarkers(
-                    this.readInput()
-                )
-            )
-        );
+        return new ReadLiteralBlockScalar(this.readInput());
     }
 
     /**


Test patch:
diff --git a/src/test/java/com/amihaiemil/eoyaml/YamlSequencePrintTest.java b/src/test/java/com/amihaiemil/eoyaml/YamlSequencePrintTest.java
new file mode 100644
index 0000000..2fc94cf
--- /dev/null
+++ b/src/test/java/com/amihaiemil/eoyaml/YamlSequencePrintTest.java
@@ -0,0 +1,135 @@
+/**
+ * Copyright (c) 2016-2020, Mihai Emil Andronache
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ *  list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright notice,
+ *  this list of conditions and the following disclaimer in the documentation
+ *  and/or other materials provided with the distribution.
+ * Neither the name of the copyright holder nor the names of its
+ *  contributors may be used to endorse or promote products derived from
+ *  this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+package com.amihaiemil.eoyaml;
+
+import org.apache.commons.io.IOUtils;
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+/**
+ * Full printing tests for built and read YamlSequences.
+ * This will call toString() triggering the whole printing
+ * process done by the internal indent(...) method.
+ *
+ * Assertions on printed YAML are done in other tests as well,
+ * but it's better to also have a dedicated test class.
+ * @checkstyle LineLength (300 lines)
+ * @author Mihai Andronache (amihaiemil@gmail.com)
+ * @version $Id$
+ * @since 4.0.0
+ */
+public final class YamlSequencePrintTest {
+
+    /**
+     * We read a YamlSequence containing all types of
+     * YamlNode we have so far and print it.
+     * @throws Exception If something goes wrong.
+     */
+    @Test
+    public void printsReadYamlSequenceWithAllNodes() throws Exception {
+        final YamlSequence read = Yaml.createYamlInput(
+            new File("src/test/resources/printing_tests/yamlSequenceAllNodes.txt")
+        ).readYamlSequence();
+        MatcherAssert.assertThat(
+            read.toString(),
+            Matchers.equalTo(
+                this.readExpected("yamlSequenceAllNodes.txt")
+            )
+        );
+    }
+
+    /**
+     * We build a YamlSequence containing all types of
+     * YamlNode we have so far and print it.
+     * @throws Exception If something goes wrong.
+     */
+    @Test
+    public void printsBuiltYamlSequenceWithAllNodes() throws Exception {
+        final YamlSequence built = Yaml.createYamlSequenceBuilder()
+            .add("plain scalar")
+            .add(
+                Yaml.createYamlScalarBuilder()
+                    .addLine("literal")
+                    .addLine("block")
+                    .addLine("scalar")
+                    .buildLiteralBlockScalar()
+            )
+            .add(
+                Yaml.createYamlScalarBuilder()
+                    .addLine("a scalar folded")
+                    .addLine("on more lines")
+                    .addLine("for readability")
+                    .buildFoldedBlockScalar()
+            )
+            .add(
+                Yaml.createYamlMappingBuilder()
+                    .add("key", "value")
+                    .build()
+            )
+            .add(
+                Yaml.createYamlSequenceBuilder()
+                    .add("a sequence")
+                    .add("of plain scalars")
+                    .add("as child")
+                    .build()
+            )
+            .build();
+        MatcherAssert.assertThat(
+            built.toString(),
+            Matchers.equalTo(
+                this.readExpected("yamlSequenceAllNodes.txt")
+            )
+        );
+    }
+
+    /**
+     * Read a test resource file's contents.
+     * @param fileName File to read.
+     * @return File's contents as String.
+     * @throws FileNotFoundException If something is wrong.
+     * @throws IOException If something is wrong.
+     */
+    private String readExpected(final String fileName)
+        throws FileNotFoundException, IOException {
+        return new String(
+            IOUtils.toByteArray(
+                new FileInputStream(
+                    new File(
+                        "src/test/resources/printing_tests/" + fileName
+                    )
+                )
+            )
+        );
+    }
+}
diff --git a/src/test/resources/printing_tests/yamlSequenceAllNodes.txt b/src/test/resources/printing_tests/yamlSequenceAllNodes.txt
new file mode 100644
index 0000000..2831169
--- /dev/null
+++ b/src/test/resources/printing_tests/yamlSequenceAllNodes.txt
@@ -0,0 +1,15 @@
+- plain scalar
+- |
+  literal
+  block
+  scalar
+- >
+  a scalar folded
+  on more lines
+  for readability
+- 
+  key: value
+- 
+  - a sequence
+  - of plain scalars
+  - as child
\ No newline at end of file