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

Issue:
Add YamlNode:value(YamlNode) to YamlMapping
YamlMapping should have a generic ``YamlNode : value(key:YamlNode)`` to fetch a value mapped to a key.

Pull request description:
#183 implemented YamlMapping.value(...) + unit tests
fixes #183 

Patch:
diff --git a/src/main/java/com/amihaiemil/eoyaml/ReadYamlMapping.java b/src/main/java/com/amihaiemil/eoyaml/ReadYamlMapping.java
index 3c27aee..47fcdec 100644
--- a/src/main/java/com/amihaiemil/eoyaml/ReadYamlMapping.java
+++ b/src/main/java/com/amihaiemil/eoyaml/ReadYamlMapping.java
@@ -57,18 +57,11 @@ final class ReadYamlMapping extends ComparableYamlMapping {
 
     @Override
     public Collection<YamlNode> values() {
-        final List<YamlNode> kids = new LinkedList<>();
+        final List<YamlNode> values = new LinkedList<>();
         for(final YamlNode key : this.keys()) {
-            YamlNode value = this.yamlMapping(key);
-            if(value == null) {
-                value = this.yamlSequence(key);
-                if(value == null) {
-                    value = new Scalar(this.string(key));
-                }
-            }
-            kids.add(value);
+            values.add(this.value(key));
         }
-        return kids;
+        return values;
     }
 
     @Override
@@ -259,4 +252,20 @@ final class ReadYamlMapping extends ComparableYamlMapping {
         }
         return keys;
     }
+
+    @Override
+    public YamlNode value(final YamlNode key) {
+        YamlNode value = this.yamlMapping(key);
+        if(value == null) {
+            value = this.yamlSequence(key);
+            if(value == null) {
+                final String val = this.string(key);
+                if(val != null) {
+                    value = new Scalar(val);
+
+                }
+            }
+        }
+        return value;
+    }
 }
diff --git a/src/main/java/com/amihaiemil/eoyaml/RtYamlMapping.java b/src/main/java/com/amihaiemil/eoyaml/RtYamlMapping.java
index a6d5df6..7bb14b6 100644
--- a/src/main/java/com/amihaiemil/eoyaml/RtYamlMapping.java
+++ b/src/main/java/com/amihaiemil/eoyaml/RtYamlMapping.java
@@ -163,4 +163,9 @@ final class RtYamlMapping extends ComparableYamlMapping {
         keys.addAll(this.mappings.keySet());
         return keys;
     }
+
+    @Override
+    public YamlNode value(final YamlNode key) {
+        return this.mappings.get(key);
+    }
 }
diff --git a/src/main/java/com/amihaiemil/eoyaml/StrictYamlMapping.java b/src/main/java/com/amihaiemil/eoyaml/StrictYamlMapping.java
index 9b8b0b8..6276a20 100644
--- a/src/main/java/com/amihaiemil/eoyaml/StrictYamlMapping.java
+++ b/src/main/java/com/amihaiemil/eoyaml/StrictYamlMapping.java
@@ -128,4 +128,15 @@ public final class StrictYamlMapping extends ComparableYamlMapping {
     public Set<YamlNode> keys() {
         return this.decorated.keys();
     }
+
+    @Override
+    public YamlNode value(final YamlNode key) {
+        YamlNode found = this.decorated.value(key);
+        if (found == null) {
+            throw new YamlNodeNotFoundException(
+                "No String found for key " + key
+            );
+        }
+        return found;
+    }
 }
diff --git a/src/main/java/com/amihaiemil/eoyaml/YamlMapping.java b/src/main/java/com/amihaiemil/eoyaml/YamlMapping.java
index 3e2033a..8b8c806 100644
--- a/src/main/java/com/amihaiemil/eoyaml/YamlMapping.java
+++ b/src/main/java/com/amihaiemil/eoyaml/YamlMapping.java
@@ -85,6 +85,14 @@ public interface YamlMapping extends YamlNode {
      */
     String string(final YamlNode key);
 
+    /**
+     * Get the YamlNode mapped to the specified key.
+     * @param key YamlNode key. Could be a simple scalar,
+     *  a YamlMapping or a YamlSequence.
+     * @return The found YamlNode or null if nothing is found.
+     */
+    YamlNode value(final YamlNode key);
+    
     /**
      * Return the keys' set of this mapping.<br><br>
      * <b>Pay attention: </b> the keys are ordered.


Test patch:
diff --git a/src/test/java/com/amihaiemil/eoyaml/ReadYamlMappingTest.java b/src/test/java/com/amihaiemil/eoyaml/ReadYamlMappingTest.java
index dcfd636..8c40f86 100644
--- a/src/test/java/com/amihaiemil/eoyaml/ReadYamlMappingTest.java
+++ b/src/test/java/com/amihaiemil/eoyaml/ReadYamlMappingTest.java
@@ -302,6 +302,80 @@ public final class ReadYamlMappingTest {
             third, Matchers.equalTo("something")
         );
     }
+
+    /**
+     * ReadYamlMapping can return the Scalar mapped to a
+     * Scalar key.
+     */
+    @Test
+    public void returnsScalarValueWithStringKey(){
+        final List<YamlLine> lines = new ArrayList<>();
+        lines.add(new RtYamlLine("first: somethingElse", 0));
+        lines.add(new RtYamlLine("second: ", 1));
+        lines.add(new RtYamlLine("  - some", 2));
+        lines.add(new RtYamlLine("  - sequence", 3));
+        lines.add(new RtYamlLine("third: something", 4));
+        final YamlMapping map = new ReadYamlMapping(new AllYamlLines(lines));
+        final YamlNode first = map.value(new Scalar("first"));
+        MatcherAssert.assertThat(first, Matchers.notNullValue());
+        MatcherAssert.assertThat(
+            first, Matchers.equalTo(new Scalar("somethingElse"))
+        );
+    }
+    
+    /**
+     * ReadYamlMapping can return the Sequence mapped to a
+     * Scalar key.
+     */
+    @Test
+    public void returnsSequenceValueWithStringKey(){
+        final List<YamlLine> lines = new ArrayList<>();
+        lines.add(new RtYamlLine("first: somethingElse", 0));
+        lines.add(new RtYamlLine("second: ", 1));
+        lines.add(new RtYamlLine("  - some", 2));
+        lines.add(new RtYamlLine("  - sequence", 3));
+        lines.add(new RtYamlLine("third: something", 4));
+        final YamlMapping map = new ReadYamlMapping(new AllYamlLines(lines));
+        final YamlNode second = map.value(new Scalar("second"));
+        MatcherAssert.assertThat(second, Matchers.notNullValue());
+        MatcherAssert.assertThat(
+            second, Matchers.instanceOf(YamlSequence.class)
+        );
+    }
+    
+    /**
+     * ReadYamlMapping can return the Mapping mapped to a
+     * Scalar key.
+     */
+    @Test
+    public void returnsMappingValueWithStringKey(){
+        final List<YamlLine> lines = new ArrayList<>();
+        lines.add(new RtYamlLine("first: somethingElse", 0));
+        lines.add(new RtYamlLine("second: ", 1));
+        lines.add(new RtYamlLine("  some: mapping", 2));
+        lines.add(new RtYamlLine("third: something", 3));
+        final YamlMapping map = new ReadYamlMapping(new AllYamlLines(lines));
+        final YamlNode second = map.value(new Scalar("second"));
+        MatcherAssert.assertThat(second, Matchers.notNullValue());
+        MatcherAssert.assertThat(
+            second, Matchers.instanceOf(YamlMapping.class)
+        );
+    }
+    
+    /**
+     * ReadYamlMapping can return null if value is missing.
+     */
+    @Test
+    public void returnsNullIfValueIsMissing(){
+        final List<YamlLine> lines = new ArrayList<>();
+        lines.add(new RtYamlLine("first: somethingElse", 0));
+        lines.add(new RtYamlLine("second: ", 1));
+        lines.add(new RtYamlLine("  some: mapping", 2));
+        lines.add(new RtYamlLine("third: something", 3));
+        final YamlMapping map = new ReadYamlMapping(new AllYamlLines(lines));
+        final YamlNode missing = map.value(new Scalar("notthere"));
+        MatcherAssert.assertThat(missing, Matchers.nullValue());
+    }
     
     /**
      * ReadYamlMapping.string(...) returns null if the queried
diff --git a/src/test/java/com/amihaiemil/eoyaml/RtYamlMappingTest.java b/src/test/java/com/amihaiemil/eoyaml/RtYamlMappingTest.java
index cc87382..299b082 100644
--- a/src/test/java/com/amihaiemil/eoyaml/RtYamlMappingTest.java
+++ b/src/test/java/com/amihaiemil/eoyaml/RtYamlMappingTest.java
@@ -377,6 +377,73 @@ public final class RtYamlMappingTest {
         MatcherAssert.assertThat(yaml.toString(), Matchers.isEmptyString());
     }
 
+    /**
+     * RtYamlMapping.value(YamlNode) can return a found Scalar value.
+     */
+    @Test
+    public void returnsScalarValue() {
+        Map<YamlNode, YamlNode> mappings = new HashMap<>();
+        Scalar value = new Scalar("value2");
+        Scalar key = new Scalar("key2");
+        mappings.put(new Scalar("key3"), Mockito.mock(YamlSequence.class));
+        mappings.put(key, value);
+        mappings.put(new Scalar("key1"), Mockito.mock(YamlMapping.class));
+        RtYamlMapping map = new RtYamlMapping(mappings);
+
+        MatcherAssert.assertThat(map.value(key), Matchers.equalTo(value));
+    }
+    
+    /**
+     * RtYamlMapping.value(YamlNode) can return a found YamlMapping value.
+     */
+    @Test
+    public void returnsYamlMappingValue() {
+        Map<YamlNode, YamlNode> mappings = new HashMap<>();
+        YamlMapping value = Mockito.mock(YamlMapping.class);
+        Scalar key = new Scalar("key2");
+        mappings.put(new Scalar("key3"), Mockito.mock(YamlSequence.class));
+        mappings.put(key, value);
+        mappings.put(new Scalar("key1"), Mockito.mock(YamlMapping.class));
+        RtYamlMapping map = new RtYamlMapping(mappings);
+
+        MatcherAssert.assertThat(map.value(key), Matchers.equalTo(value));
+    }
+    
+    /**
+     * RtYamlMapping.value(YamlNode) can return a found YamlSequence value.
+     */
+    @Test
+    public void returnsYamlSequenceValue() {
+        Map<YamlNode, YamlNode> mappings = new HashMap<>();
+        YamlSequence value = Mockito.mock(YamlSequence.class);
+        Scalar key = new Scalar("key2");
+        mappings.put(new Scalar("key3"), Mockito.mock(YamlSequence.class));
+        mappings.put(key, value);
+        mappings.put(new Scalar("key1"), Mockito.mock(YamlMapping.class));
+        RtYamlMapping map = new RtYamlMapping(mappings);
+
+        MatcherAssert.assertThat(map.value(key), Matchers.equalTo(value));
+    }
+    
+    /**
+     * RtYamlMapping.value(YamlNode) can return null if the value is not there.
+     */
+    @Test
+    public void returnsNullOnMissingValue() {
+        Map<YamlNode, YamlNode> mappings = new HashMap<>();
+        YamlSequence value = Mockito.mock(YamlSequence.class);
+        Scalar key = new Scalar("key2");
+        mappings.put(new Scalar("key3"), Mockito.mock(YamlSequence.class));
+        mappings.put(key, value);
+        mappings.put(new Scalar("key1"), Mockito.mock(YamlMapping.class));
+        RtYamlMapping map = new RtYamlMapping(mappings);
+
+        MatcherAssert.assertThat(
+            map.value(new Scalar("notthere")),
+            Matchers.nullValue()
+        );
+    }
+    
     /**
      * Read a test resource file's contents.
      * @param fileName File to read.
diff --git a/src/test/java/com/amihaiemil/eoyaml/StrictYamlMappingTest.java b/src/test/java/com/amihaiemil/eoyaml/StrictYamlMappingTest.java
index f6aa261..9eb0e85 100644
--- a/src/test/java/com/amihaiemil/eoyaml/StrictYamlMappingTest.java
+++ b/src/test/java/com/amihaiemil/eoyaml/StrictYamlMappingTest.java
@@ -110,6 +110,19 @@ public final class StrictYamlMappingTest {
         YamlMapping strict = new StrictYamlMapping(origin);
         strict.string("key");
     }
+    
+    /**
+     * StringYamlMapping can throw YamlNodeNotFoundException
+     * when the demanded value is not found.
+     */
+    @Test (expected = YamlNodeNotFoundException.class)
+    public void exceptionOnNullValue() {
+        Scalar key = new Scalar("key");
+        YamlMapping origin = Mockito.mock(YamlMapping.class);
+        Mockito.when(origin.value(key)).thenReturn(null);
+        YamlMapping strict = new StrictYamlMapping(origin);
+        strict.string(key);
+    }
 
     /**
      * StringYamlMapping can fetch a YamlMapping based in its key.
@@ -154,4 +167,19 @@ public final class StrictYamlMappingTest {
             strict.string("key"), Matchers.equalTo("found")
         );
     }
+    
+    /**
+     * StringYamlMapping can fetch a value based in its key.
+     */
+    @Test
+    public void returnsValue() {
+        YamlMapping origin = Mockito.mock(YamlMapping.class);
+        YamlNode key = new Scalar("key");
+        YamlNode value = new Scalar("value");
+        Mockito.when(origin.value(key)).thenReturn(value);
+        YamlMapping strict = new StrictYamlMapping(origin);
+        MatcherAssert.assertThat(
+            strict.value(key), Matchers.equalTo(value)
+        );
+    }
 }