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

Issue:
Question marks in values lead to YamlIndentationException
Hello! 👋🏻 

Consider the following piece of code:
```java
package test;

import java.io.IOException;

import com.amihaiemil.eoyaml.Yaml;
import com.amihaiemil.eoyaml.YamlMapping;

public class Main {

	public static void main(String[] args) throws IOException {
		YamlMapping yaml = Yaml.createYamlMappingBuilder()
				.add("key1", "Some value?")
				.add("key2", "Some other value.")
				.build();

		YamlMapping copy = Yaml.createYamlInput(yaml.toString()).readYamlMapping();
		System.out.println(copy.toString());
	}
}

```

The value with the question mark is happily parsed, but when trying to turn the mapping back into a string using `copy.toString()`, an exception is thrown:
```
Exception in thread "main" com.amihaiemil.eoyaml.exceptions.YamlIndentationException: Indentation of line 2 [key2: Some other value.] is not ok. It should be greater than the one of line 1 [key1: Some value?] by 2 spaces.
	at com.amihaiemil.eoyaml.WellIndented.iterator(WellIndented.java:135)
	at com.amihaiemil.eoyaml.SameIndentationLevel.iterator(SameIndentationLevel.java:74)
	at com.amihaiemil.eoyaml.ReadYamlMapping.lambda$comment$6(ReadYamlMapping.java:201)
	at com.amihaiemil.eoyaml.Skip.iterator(Skip.java:74)
	at com.amihaiemil.eoyaml.Backwards.iterator(Backwards.java:69)
	at com.amihaiemil.eoyaml.FirstCommentFound.documentComment(FirstCommentFound.java:137)
	at com.amihaiemil.eoyaml.FirstCommentFound.iterator(FirstCommentFound.java:84)
	at com.amihaiemil.eoyaml.Backwards.iterator(Backwards.java:69)
	at com.amihaiemil.eoyaml.ReadComment.value(ReadComment.java:66)
	at com.amihaiemil.eoyaml.RtYamlPrinter.printPossibleComment(RtYamlPrinter.java:306)
	at com.amihaiemil.eoyaml.RtYamlPrinter.print(RtYamlPrinter.java:72)
	at com.amihaiemil.eoyaml.BaseYamlNode.toString(BaseYamlNode.java:104)
	at test.Main.main(Main.java:17)
```

If I try explicitly quoting the value (`"\"Some value?\""`), the above piece of code no longer throws an exception, but `copy.toString()` removes the quotations. Parsing and printing a second time therefore leads back to the initial problem.

Two other observations:
* special characters such as exclamation marks don't cause any problems when printed, even unquoted.
* special characters such as hyphens don't cause any problems when printed, but quotations are automatically added by the library.

Let me know if you need more information.

Pull request:
#422 Fixed bug where values with '?' where not escaped.
Fixes #422

Patch:
diff --git a/src/main/java/com/amihaiemil/eoyaml/RtYamlPrinter.java b/src/main/java/com/amihaiemil/eoyaml/RtYamlPrinter.java
index 7f6cb1a..69fb26a 100644
--- a/src/main/java/com/amihaiemil/eoyaml/RtYamlPrinter.java
+++ b/src/main/java/com/amihaiemil/eoyaml/RtYamlPrinter.java
@@ -377,7 +377,7 @@ final class RtYamlPrinter implements YamlPrinter {
             String escaped = value;
             boolean quoted = (value.startsWith("'") && value.endsWith("'"))
                     || (value.startsWith("\"") && value.endsWith("\""));
-            if (!quoted && value.matches(".*[\\-#:>|$%&{}\\[\\]]+.*|[ ]+")) {
+            if (!quoted && value.matches(".*[?\\-#:>|$%&{}\\[\\]]+.*|[ ]+")) {
                 if(value.contains("\"")) {
                     escaped = "'" + value + "'";
                 } else {


Test patch:
diff --git a/src/test/java/com/amihaiemil/eoyaml/ReadYamlMappingTest.java b/src/test/java/com/amihaiemil/eoyaml/ReadYamlMappingTest.java
index a5ea47a..3bd0f55 100644
--- a/src/test/java/com/amihaiemil/eoyaml/ReadYamlMappingTest.java
+++ b/src/test/java/com/amihaiemil/eoyaml/ReadYamlMappingTest.java
@@ -27,6 +27,7 @@
  */
 package com.amihaiemil.eoyaml;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
@@ -1150,4 +1151,23 @@ public final class ReadYamlMappingTest {
                 Matchers.equalTo(expectedSeq.comment().value())
         );
     }
+
+    /**
+     * ReadYamlMapping can be created from another YamlMapping.
+     * @throws IOException If something goes wrong.
+     */
+    @Test
+    public void shouldReadFromAnotherFromYamlMapping()
+        throws IOException {
+        YamlMapping yaml = Yaml.createYamlMappingBuilder()
+            .add("key1", "Some value?")
+            .add("key2", "Some other value.")
+            .build();
+        YamlMapping copy = Yaml.createYamlInput(yaml.toString())
+            .readYamlMapping();
+        MatcherAssert.assertThat(copy.string("key1"), Matchers
+            .equalTo("Some value?"));
+        MatcherAssert.assertThat(copy.string("key2"), Matchers
+            .equalTo("Some other value."));
+    }
 }
diff --git a/src/test/java/com/amihaiemil/eoyaml/RtYamlPrinterTest.java b/src/test/java/com/amihaiemil/eoyaml/RtYamlPrinterTest.java
index 00c6fe0..aedbec8 100644
--- a/src/test/java/com/amihaiemil/eoyaml/RtYamlPrinterTest.java
+++ b/src/test/java/com/amihaiemil/eoyaml/RtYamlPrinterTest.java
@@ -32,7 +32,9 @@ import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Test;
 
-import java.io.*;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
 
 /**
  *
@@ -78,4 +80,32 @@ public final class RtYamlPrinterTest {
         }
     }
 
+    /**
+     * {@link RtYamlPrinter.Escaped} escapes values when encounter special
+     * characters or when there are quotations inside and ignores when the
+     * values are already escaped with
+     * <code>"</code> or <code>'</code>.
+     */
+    @Test
+    public void escapesWhenEncounterSpecialChars(){
+        MatcherAssert.assertThat(new RtYamlPrinter
+                .Escaped(new PlainStringScalar("Some value?")).value(),
+            Matchers.equalTo("\"Some value?\""));
+        MatcherAssert.assertThat(new RtYamlPrinter
+                .Escaped(new PlainStringScalar("Some value-")).value(),
+            Matchers.equalTo("\"Some value-\""));
+        MatcherAssert.assertThat(new RtYamlPrinter
+                .Escaped(new PlainStringScalar("Some value#")).value(),
+            Matchers.equalTo("\"Some value#\""));
+        MatcherAssert.assertThat(new RtYamlPrinter
+                .Escaped(new PlainStringScalar("'Some value'")).value(),
+            Matchers.equalTo("'Some value'"));
+        MatcherAssert.assertThat(new RtYamlPrinter
+                .Escaped(new PlainStringScalar("Some \"value\"|"))
+                .value(),
+            Matchers.equalTo("'Some \"value\"|'"));
+        MatcherAssert.assertThat(new RtYamlPrinter
+                .Escaped(new PlainStringScalar("\"Some value\"")).value(),
+            Matchers.equalTo("\"Some value\""));
+    }
 }