Repository: decorators-squad/eo-yaml
Pull request #217 (2020-03-23 19:14:15)

Read YamlStream with missing first Start Marker
PR for #211 
When reading a YamlStream, the start marker of the first document can be missing.
Wrote unit tests and left 2 puzzles, 1 for refactoring and 1 for fixing a bug regarding YAML Comments and line numbering.


Patch:
diff --git a/src/main/java/com/amihaiemil/eoyaml/AllYamlLines.java b/src/main/java/com/amihaiemil/eoyaml/AllYamlLines.java
index 5ee8edc..d1e33ab 100644
--- a/src/main/java/com/amihaiemil/eoyaml/AllYamlLines.java
+++ b/src/main/java/com/amihaiemil/eoyaml/AllYamlLines.java
@@ -42,6 +42,9 @@ import java.util.List;
  * @author Mihai Andronache (amihaiemil@gmail.com)
  * @version $Id$
  * @since 1.0.0
+ * @todo #211:30min Method toYamlNode has a lot of duplicated case, it
+ *  most likely needs to be refactored. Make sure to add tests for all
+ *  the performed changes as this method is quite important in the library.
  */
 final class AllYamlLines implements YamlLines {
 
@@ -141,7 +144,13 @@ final class AllYamlLines implements YamlLines {
                 node = new ReadFoldedBlockScalar(this);
                 break;
             default:
-                node = null;
+                final boolean elementSequence = this.iterator()
+                    .next().trimmed().startsWith("-");
+                if(elementSequence) {
+                    node = new ReadYamlSequence(this);
+                } else {
+                    node = new ReadYamlMapping(this);
+                }
                 break;
         }
         return node;
diff --git a/src/main/java/com/amihaiemil/eoyaml/NoDirectives.java b/src/main/java/com/amihaiemil/eoyaml/NoDirectives.java
new file mode 100644
index 0000000..def2e31
--- /dev/null
+++ b/src/main/java/com/amihaiemil/eoyaml/NoDirectives.java
@@ -0,0 +1,100 @@
+/**
+ * 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 java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * No directives. Decorates some YamlLines
+ * and ignores YAML directives from the iteration.
+ * This class can be used as follows:
+ * <pre>
+ *  YamlLines noDirs = new NoDirectives(
+ *      new AllYamlLines(lines)
+ * );//Ignores YAML Directives from iteration.
+ * </pre>
+ * @author Mihai Andronache (amihaiemil@gmail.com)
+ * @version $Id$
+ * @since 3.1.4
+ */
+final class NoDirectives implements YamlLines {
+    /**
+     * YamlLines.
+     */
+    private final YamlLines yamlLines;
+
+    /**
+     * Ctor.
+     * @param yamlLines The Yaml lines.
+     */
+    NoDirectives(final YamlLines yamlLines) {
+        this.yamlLines = yamlLines;
+    }
+
+    /**
+     * Returns an iterator over these Yaml lines.
+     * It ignores the lines containing YAML Directives.
+     * @return Iterator over these yaml lines.
+     */
+    @Override
+    public Iterator<YamlLine> iterator() {
+        Iterator<YamlLine> iterator = this.yamlLines.iterator();
+        if (iterator.hasNext()) {
+            final List<YamlLine> noDirectives = new ArrayList<>();
+            while (iterator.hasNext()) {
+                final YamlLine current = iterator.next();
+                final String currentLine = current.trimmed();
+                if (currentLine.startsWith("%")) {
+                    continue;
+                } else {
+                    noDirectives.add(current);
+                }
+            }
+            iterator = noDirectives.iterator();
+        }
+        return iterator;
+    }
+
+    @Override
+    public Collection<YamlLine> lines() {
+        return this.yamlLines.lines();
+    }
+
+    @Override
+    public AllYamlLines nested(final int after) {
+        return this.yamlLines.nested(after);
+    }
+
+    @Override
+    public YamlNode toYamlNode(final YamlLine prev) {
+        return this.yamlLines.toYamlNode(prev);
+    }
+}
diff --git a/src/main/java/com/amihaiemil/eoyaml/NoDirectivesOrMarkers.java b/src/main/java/com/amihaiemil/eoyaml/NoDirectivesOrMarkers.java
index 5b0a795..9a26847 100644
--- a/src/main/java/com/amihaiemil/eoyaml/NoDirectivesOrMarkers.java
+++ b/src/main/java/com/amihaiemil/eoyaml/NoDirectivesOrMarkers.java
@@ -35,6 +35,12 @@ import java.util.List;
 /**
  * No directives or markers. Decorates some YamlLines
  * and ignores YAML directives and markers from iteration.
+ * Use this class as follows:
+ * <pre>
+ *  YamlLines noDirs = new NoDirectivesOrMarkers(
+ *      new AllYamlLines(lines)
+ * );//Ignores YAML Directives and Start/End markers from iteration.
+ * </pre>
  * @author Mihai Andronache (amihaiemil@gmail.com)
  * @version $Id$
  * @since 3.1.2
diff --git a/src/main/java/com/amihaiemil/eoyaml/ReadYamlStream.java b/src/main/java/com/amihaiemil/eoyaml/ReadYamlStream.java
index 6b08bb6..b644179 100644
--- a/src/main/java/com/amihaiemil/eoyaml/ReadYamlStream.java
+++ b/src/main/java/com/amihaiemil/eoyaml/ReadYamlStream.java
@@ -50,7 +50,9 @@ final class ReadYamlStream extends ComparableYamlStream {
      */
     ReadYamlStream(final AllYamlLines lines) {
         this.lines = new WellIndented(
-            new StartMarkers(lines)
+            new StartMarkers(
+                new NoDirectives(lines)
+            )
         );
     }
 
diff --git a/src/main/java/com/amihaiemil/eoyaml/SameIndentationLevel.java b/src/main/java/com/amihaiemil/eoyaml/SameIndentationLevel.java
index e6813f9..c2f1c0d 100644
--- a/src/main/java/com/amihaiemil/eoyaml/SameIndentationLevel.java
+++ b/src/main/java/com/amihaiemil/eoyaml/SameIndentationLevel.java
@@ -36,6 +36,12 @@ import java.util.List;
  * SameIndentationLevel. Decorates some YamlLines
  * and iterates only over those which are at the same
  * indentation level with the first one.
+ * Use this class as follows:
+ * <pre>
+ *  YamlLines noDirs = new SameIndentationLevel(
+ *      new AllYamlLines(lines)
+ *  ); //Iterates only over the lines which have the same indentation.
+ * </pre>
  * @author Mihai Andronache (amihaiemil@gmail.com)
  * @version $Id$
  * @since 3.0.2
@@ -88,7 +94,7 @@ final class SameIndentationLevel implements YamlLines {
     public AllYamlLines nested(final int after) {
         return this.yamlLines.nested(after);
     }
-    
+
     @Override
     public YamlNode toYamlNode(final YamlLine prev) {
         return this.yamlLines.toYamlNode(prev);
diff --git a/src/main/java/com/amihaiemil/eoyaml/StartMarkers.java b/src/main/java/com/amihaiemil/eoyaml/StartMarkers.java
index de96de7..b43dae8 100644
--- a/src/main/java/com/amihaiemil/eoyaml/StartMarkers.java
+++ b/src/main/java/com/amihaiemil/eoyaml/StartMarkers.java
@@ -48,57 +48,75 @@ final class StartMarkers implements YamlLines {
     private YamlLines yamlLines;
 
     /**
-     * Constructor.
+     * Constructor. Pay attention, directives will be
+     * omitted from the given lines.
      * @param yamlLines The YAML Lines.
      */
     StartMarkers(final YamlLines yamlLines){
+        this(new NoDirectives(yamlLines));
+    }
+
+    /**
+     * Constructor.
+     * @param yamlLines The YAML Lines. YAML Directives
+     *  should always be omitted, we only iterate over
+     *  the Start markers.
+     */
+    StartMarkers(final NoDirectives yamlLines){
         this.yamlLines = yamlLines;
     }
 
     /**
-     * Returns an iterator over these Yaml lines.
-     * It ignores the YAML Directives and Marker lines.
-     * @todo #90:30min This method has to be enhanced to also cover
-     *  the case when the first "---" is missing. A YAML Stream of documents
-     *  can also omit the Start Marker for the first YAML Document.
+     * Returns an iterator containing only the Start Marker lines (---),
+     * with the possible exception of the FIRST line, which can be the first
+     * line of the first document (in YAML Streams, the Start Marker
+     * of the first document can be missing). e.g. Both are valid:
+     * <pre>
+     * ---
+     * test: 1
+     * ---
+     * test 2
+     * </pre>
+     * and
+     * <pre>
+     * test: 1
+     * ---
+     * test: 2
+     * </pre>
      * @return Iterator over these yaml lines.
      */
     @Override
     public Iterator<YamlLine> iterator() {
         Iterator<YamlLine> iterator = this.yamlLines.iterator();
         if (iterator.hasNext()) {
-            final List<YamlLine> startMarkers = new ArrayList<>();
+            final List<YamlLine> docsStart = new ArrayList<>();
+            docsStart.add(iterator.next());
             while (iterator.hasNext()) {
                 final YamlLine current = iterator.next();
                 final String currentLine = current.trimmed();
                 if ("---".equals(currentLine)) {
-                    startMarkers.add(current);
+                    docsStart.add(current);
                 }
             }
-            iterator = startMarkers.iterator();
+            iterator = docsStart.iterator();
         }
         return iterator;
     }
 
     /**
-     * Lines which are nested after the given YamlLine. The given YamlLine
-     * has to be a Start Marker (---). "Nested lines" means all the lines
-     * which are after it, until Start Marker, End Marker (...) or end-of-file
-     * is met.
+     * Lines which are nested after the given YamlLine. "Nested lines" means
+     * all the lines which are after it, until a Start Marker,
+     * an End Marker (...) or end-of-file is met.
      * @param after Number of a YamlLine
      * @return YamlLines
      */
     @Override
     public AllYamlLines nested(final int after) {
+        final List<YamlLine> yamlDocLines = new ArrayList<>();
         final YamlLine startLine = this.yamlLines.line(after);
         if(!"---".equals(startLine.trimmed())) {
-            throw new IllegalStateException(
-                "Expected start of Yaml document on line " + (after + 1)
-              + " (---) while reading the Yaml stream. Instead, the line is ["
-              + startLine.trimmed() + "]."
-            );
+            yamlDocLines.add(startLine);
         }
-        final List<YamlLine> yamlDocLines = new ArrayList<>();
         for(final YamlLine line : this.lines()) {
             if(line.number() > after) {
                 final String current = line.trimmed();


Test patch:
diff --git a/src/test/java/com/amihaiemil/eoyaml/BuiltYamlStreamTest.java b/src/test/java/com/amihaiemil/eoyaml/BuiltYamlStreamTest.java
index f0f0ac5..a543854 100644
--- a/src/test/java/com/amihaiemil/eoyaml/BuiltYamlStreamTest.java
+++ b/src/test/java/com/amihaiemil/eoyaml/BuiltYamlStreamTest.java
@@ -386,8 +386,8 @@ public final class BuiltYamlStreamTest {
      * 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.
+     * @throws FileNotFoundException If somethig is wrong.
+     * @throws IOException If somethig is wrong.
      */
     private String readTestResource(final String fileName)
         throws FileNotFoundException, IOException {
diff --git a/src/test/java/com/amihaiemil/eoyaml/NoDirectivesTest.java b/src/test/java/com/amihaiemil/eoyaml/NoDirectivesTest.java
new file mode 100644
index 0000000..91732dd
--- /dev/null
+++ b/src/test/java/com/amihaiemil/eoyaml/NoDirectivesTest.java
@@ -0,0 +1,172 @@
+package com.amihaiemil.eoyaml;
+
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Unit tests for {@link NoDirectives}.
+ * @checkstyle ExecutableStatementCount (200 lines)
+ * @author Mihai Andronache (amihaiemil@gmail.com)
+ * @version $Id$
+ * @since 3.1.4
+ */
+public final class NoDirectivesTest {
+
+    /**
+     * NoDirectives can return the encapsulated lines.
+     */
+    @Test
+    @SuppressWarnings("unchecked")
+    public void returnsLines() {
+        final YamlLines lines = Mockito.mock(YamlLines.class);
+        final Collection<YamlLine> collection = Mockito.mock(Collection.class);
+        Mockito.when(lines.lines()).thenReturn(collection);
+        MatcherAssert.assertThat(
+            new NoDirectives(lines).lines(),
+            Matchers.is(collection)
+        );
+    }
+
+    /**
+     * NoDirectives can turn itself into YamlNode.
+     */
+    @Test
+    public void turnsIntoYamlNode() {
+        final YamlLines lines = Mockito.mock(YamlLines.class);
+        final YamlLine prev = Mockito.mock(YamlLine.class);
+        final YamlNode result = Mockito.mock(YamlNode.class);
+        Mockito.when(lines.toYamlNode(prev)).thenReturn(result);
+        MatcherAssert.assertThat(
+            new NoDirectives(lines).toYamlNode(prev),
+            Matchers.is(result)
+        );
+    }
+
+    /**
+     * NoDirectives should ignore YAML directives
+     * and markers from iteration.
+     */
+    @Test
+    public void ignoresDirectives() {
+        final List<YamlLine> lines = new ArrayList<>();
+        lines.add(new RtYamlLine("%YAML 1.2", 0));
+        lines.add(new RtYamlLine("---", 1));
+        lines.add(new RtYamlLine("first: something", 2));
+        lines.add(new RtYamlLine("second: ", 3));
+        lines.add(new RtYamlLine("  fourth: some", 4));
+        lines.add(new RtYamlLine("  fifth: values", 5));
+        lines.add(new RtYamlLine("third:", 6));
+        lines.add(new RtYamlLine("  - seq", 7));
+        lines.add(new RtYamlLine("...", 8));
+        lines.add(new RtYamlLine("%YAML 1.2", 9));
+        lines.add(new RtYamlLine("---", 10));
+        lines.add(new RtYamlLine("...", 11));
+
+        final YamlLines ndmLines = new NoDirectives(
+            new AllYamlLines(lines)
+        );
+        MatcherAssert.assertThat(
+            ndmLines,
+            Matchers.iterableWithSize(10)
+        );
+        final Iterator<YamlLine> iterator = ndmLines.iterator();
+        MatcherAssert.assertThat(
+            iterator.next().trimmed(),
+            Matchers.equalTo("---")
+        );
+        MatcherAssert.assertThat(
+            iterator.next().trimmed(),
+            Matchers.equalTo("first: something")
+        );
+        MatcherAssert.assertThat(
+            iterator.next().trimmed(),
+            Matchers.equalTo("second:")
+        );
+        MatcherAssert.assertThat(
+            iterator.next().trimmed(),
+            Matchers.equalTo("fourth: some")
+        );
+        MatcherAssert.assertThat(
+            iterator.next().trimmed(),
+            Matchers.equalTo("fifth: values")
+        );
+        MatcherAssert.assertThat(
+            iterator.next().trimmed(),
+            Matchers.equalTo("third:")
+        );
+        MatcherAssert.assertThat(
+            iterator.next().trimmed(),
+            Matchers.equalTo("- seq")
+        );
+        MatcherAssert.assertThat(
+            iterator.next().trimmed(),
+            Matchers.equalTo("...")
+        );
+        MatcherAssert.assertThat(
+            iterator.next().trimmed(),
+            Matchers.equalTo("---")
+        );
+        MatcherAssert.assertThat(
+            iterator.next().trimmed(),
+            Matchers.equalTo("...")
+        );
+    }
+
+    /**
+     * NoDirectives iterates over all the lines, since
+     * there are actually no directives to ignore.
+     */
+    @Test
+    public void noDirectivesAndMarkersToIgnore() {
+        final List<YamlLine> lines = new ArrayList<>();
+        lines.add(new RtYamlLine("first: something", 0));
+        lines.add(new RtYamlLine("second: ", 1));
+        lines.add(new RtYamlLine("  fourth: some", 2));
+        lines.add(new RtYamlLine("  fifth: values", 3));
+        final YamlLines ndmLines = new NoDirectives(
+            new AllYamlLines(lines)
+        );
+        MatcherAssert.assertThat(
+            ndmLines,
+            Matchers.iterableWithSize(4)
+        );
+        final Iterator<YamlLine> iterator = ndmLines.iterator();
+        MatcherAssert.assertThat(
+            iterator.next().trimmed(),
+            Matchers.equalTo("first: something")
+        );
+        MatcherAssert.assertThat(
+            iterator.next().trimmed(),
+            Matchers.equalTo("second:")
+        );
+        MatcherAssert.assertThat(
+            iterator.next().trimmed(),
+            Matchers.equalTo("fourth: some")
+        );
+        MatcherAssert.assertThat(
+            iterator.next().trimmed(),
+            Matchers.equalTo("fifth: values")
+        );
+    }
+
+    /**
+     * NoDirectivesOrMarkers works with no lines.
+     */
+    @Test
+    public void iteratesEmptyLines() {
+        final YamlLines ndmLines = new NoDirectives(
+            new AllYamlLines(new ArrayList<YamlLine>())
+        );
+        MatcherAssert.assertThat(
+            ndmLines,
+            Matchers.iterableWithSize(0)
+        );
+    }
+}
diff --git a/src/test/java/com/amihaiemil/eoyaml/RtYamlInputTest.java b/src/test/java/com/amihaiemil/eoyaml/RtYamlInputTest.java
index 7ee1320..42f60d6 100644
--- a/src/test/java/com/amihaiemil/eoyaml/RtYamlInputTest.java
+++ b/src/test/java/com/amihaiemil/eoyaml/RtYamlInputTest.java
@@ -28,11 +28,14 @@
 package com.amihaiemil.eoyaml;
 
 import java.io.*;
+import java.util.Collection;
+import java.util.Iterator;
 import java.util.Set;
 
 import org.apache.commons.io.IOUtils;
 import org.hamcrest.MatcherAssert;
 import org.hamcrest.Matchers;
+import org.junit.Ignore;
 import org.junit.Test;
 
 /**
@@ -366,6 +369,78 @@ public final class RtYamlInputTest {
         );
     }
 
+    /**
+     * A stream of YAML Documents, when the first Start Marker is missing,
+     * can be read.
+     * @throws Exception If something goes wrong.
+     */
+    @Test
+    public void readsStreamWithoutFirstStartMarker() throws Exception {
+        final YamlInput input = Yaml.createYamlInput(
+            new FileInputStream(
+                new File(
+                    "src/test/resources/streamWithoutFirstStartMarker.yml"
+                )
+            )
+        );
+        final YamlStream read = input.readYamlStream();
+        final Collection<YamlNode> values = read.values();
+        final Iterator<YamlNode> iterator = values.iterator();
+        MatcherAssert.assertThat(values, Matchers.iterableWithSize(3));
+        MatcherAssert.assertThat(
+            ((YamlMapping) iterator.next()).string("architect"),
+            Matchers.equalTo("mihai")
+        );
+        MatcherAssert.assertThat(
+            ((YamlMapping) iterator.next()).string("architect"),
+            Matchers.equalTo("vlad")
+        );
+        MatcherAssert.assertThat(
+            ((YamlMapping) iterator.next()).string("architect"),
+            Matchers.equalTo("felicia")
+        );
+    }
+
+    /**
+     * A stream of YAML Documents, when the first Start Marker is missing,
+     * can be read. The file also contains comments.
+     * @throws Exception If something goes wrong.
+     * @todo #211:30min Fix this unit test. The YAML from the file is not
+     *  read properly, most likely because of line-numbering Issues. The first
+     *  actual line of YAML has number 3 because the comments are omitted.
+     *  YamlLines.line(...) is not aware of these possible numbering diffs.
+     */
+    @Test
+    @Ignore
+    public void readsStreamWithoutFirstStartMarkerAndComments()
+        throws Exception {
+        final YamlInput input = Yaml.createYamlInput(
+            new FileInputStream(
+                new File(
+                    "src/test/resources/streamWithComments.yml"
+                )
+            )
+        );
+        final YamlStream read = input.readYamlStream();
+        System.out.print(read);
+        final Collection<YamlNode> values = read.values();
+        final Iterator<YamlNode> iterator = values.iterator();
+        MatcherAssert.assertThat(values, Matchers.iterableWithSize(3));
+        MatcherAssert.assertThat(
+            ((YamlMapping) iterator.next()).string("architect"),
+            Matchers.equalTo("mihai")
+        );
+        MatcherAssert.assertThat(
+            ((YamlMapping) iterator.next()).string("architect"),
+            Matchers.equalTo("vlad")
+        );
+        MatcherAssert.assertThat(
+            ((YamlMapping) iterator.next()).string("architect"),
+            Matchers.equalTo("felicia")
+        );
+    }
+
+
     /**
      * RtYamlInput can read an empty mapping.
      * @throws Exception If something goes wrong.
@@ -430,8 +505,8 @@ public final class RtYamlInputTest {
      * 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.
+     * @throws FileNotFoundException If somethig is wrong.
+     * @throws IOException If somethig is wrong.
      */
     private String readTestResource(final String fileName)
         throws FileNotFoundException, IOException {
diff --git a/src/test/java/com/amihaiemil/eoyaml/RtYamlMappingTest.java b/src/test/java/com/amihaiemil/eoyaml/RtYamlMappingTest.java
index e1e1ef7..561bae0 100644
--- a/src/test/java/com/amihaiemil/eoyaml/RtYamlMappingTest.java
+++ b/src/test/java/com/amihaiemil/eoyaml/RtYamlMappingTest.java
@@ -449,8 +449,8 @@ public final class RtYamlMappingTest {
      * 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.
+     * @throws FileNotFoundException If somethig is wrong.
+     * @throws IOException If somethig is wrong.
      */
     private String readTestResource(final String fileName)
         throws FileNotFoundException, IOException {
diff --git a/src/test/java/com/amihaiemil/eoyaml/StartMarkersTest.java b/src/test/java/com/amihaiemil/eoyaml/StartMarkersTest.java
index a1428f9..79e9306 100644
--- a/src/test/java/com/amihaiemil/eoyaml/StartMarkersTest.java
+++ b/src/test/java/com/amihaiemil/eoyaml/StartMarkersTest.java
@@ -179,6 +179,48 @@ public final class StartMarkersTest {
         );
     }
 
+    /**
+     * The iterator returned by StartMarkers only covers the lines
+     * representing a start marker (---), with the exception of the first one,
+     * which might not be a start marker (in a stream, the start marker of the
+     * first document can be missing).
+     */
+    @Test
+    public void iteratesOnlyOverStartMarkersMissingFirst() {
+        final List<YamlLine> lines = new ArrayList<>();
+        lines.add(new RtYamlLine("  time: 12:00", 0));
+        lines.add(new RtYamlLine("  temperature: 25C", 1));
+        lines.add(new RtYamlLine("...", 2));
+        lines.add(new RtYamlLine("---", 3));
+        lines.add(new RtYamlLine("  time: 16:00", 4));
+        lines.add(new RtYamlLine("  temperature: 20C", 5));
+        lines.add(new RtYamlLine("...", 6));
+        lines.add(new RtYamlLine("---", 7));
+        lines.add(new RtYamlLine("  time: 22:00", 8));
+        lines.add(new RtYamlLine("  temperature: 15C", 9));
+        lines.add(new RtYamlLine("...", 10));
+        final YamlLines smLines = new StartMarkers(
+            new AllYamlLines(lines)
+        );
+        MatcherAssert.assertThat(
+            smLines,
+            Matchers.iterableWithSize(3)
+        );
+        final Iterator<YamlLine> iterator = smLines.iterator();
+        MatcherAssert.assertThat(
+            iterator.next().trimmed(),
+            Matchers.equalTo("time: 12:00")
+        );
+        MatcherAssert.assertThat(
+            iterator.next().trimmed(),
+            Matchers.equalTo("---")
+        );
+        MatcherAssert.assertThat(
+            iterator.next().trimmed(),
+            Matchers.equalTo("---")
+        );
+    }
+
     /**
      * The iterator returned by StartMarkers only covers the lines
      * representing a start marker (---). In this test case,
@@ -451,4 +493,32 @@ public final class StartMarkersTest {
             Matchers.equalTo("temperature: 25C")
         );
     }
+
+    /**
+     * StartMarkers can get the lines of the first YAML Document,
+     * when its Start Marker is missing.
+     */
+    @Test
+    public void getsNestedLinesOfFirstDocWithoutStartMarker() {
+        final List<YamlLine> lines = new ArrayList<>();
+        lines.add(new RtYamlLine("time: 12:00", 0));
+        lines.add(new RtYamlLine("temperature: 25C", 1));
+        lines.add(new RtYamlLine("---", 2));
+        lines.add(new RtYamlLine("time: 16:00", 3));
+        lines.add(new RtYamlLine("temperature: 17C", 4));
+        lines.add(new RtYamlLine("...", 5));
+        final AllYamlLines mapping = new StartMarkers(
+            new AllYamlLines(lines)
+        ).nested(0);
+        MatcherAssert.assertThat(mapping, Matchers.iterableWithSize(2));
+        final Iterator<YamlLine> iterator = mapping.iterator();
+        MatcherAssert.assertThat(
+            iterator.next().trimmed(),
+            Matchers.equalTo("time: 12:00")
+        );
+        MatcherAssert.assertThat(
+            iterator.next().trimmed(),
+            Matchers.equalTo("temperature: 25C")
+        );
+    }
 }
diff --git a/src/test/resources/streamWithComments.yml b/src/test/resources/streamWithComments.yml
new file mode 100644
index 0000000..88a019e
--- /dev/null
+++ b/src/test/resources/streamWithComments.yml
@@ -0,0 +1,18 @@
+#In YAML Streams, the first document can have its Start Marker missing.
+#Also, indentation of the documents can be the same or greatedr than the
+#indentation of Start Markers.
+architect: mihai
+developers:
+  - rultor
+  - salikjan
+  - sherif
+name: eo-yaml
+---
+architect: vlad
+developers:
+  - andrei
+name: eo-json-impl
+---
+architect: felicia
+developer: sara
+name: docker-java-api
diff --git a/src/test/resources/streamWithoutFirstStartMarker.yml b/src/test/resources/streamWithoutFirstStartMarker.yml
new file mode 100644
index 0000000..a6c9eea
--- /dev/null
+++ b/src/test/resources/streamWithoutFirstStartMarker.yml
@@ -0,0 +1,15 @@
+architect: mihai
+developers:
+  - rultor
+  - salikjan
+  - sherif
+name: eo-yaml
+---
+architect: vlad
+developers:
+  - andrei
+name: eo-json-impl
+---
+architect: felicia
+developer: sara
+name: docker-java-api