From 785642b6a724bc5605a89998ce56105a50b7a9a2 Mon Sep 17 00:00:00 2001 From: amihaiemil Date: Sat, 27 Aug 2022 12:41:20 +0300 Subject: [PATCH] #512 MutableYamlMappingBuilder implemented and tested --- .../eoyaml/MutableYamlMappingBuilder.java | 98 +++++++++ src/main/java/com/amihaiemil/eoyaml/Yaml.java | 10 +- .../eoyaml/MutableYamlMappingBuilderTest.java | 187 ++++++++++++++++++ .../java/com/amihaiemil/eoyaml/YamlTest.java | 24 ++- 4 files changed, 315 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/amihaiemil/eoyaml/MutableYamlMappingBuilder.java create mode 100644 src/test/java/com/amihaiemil/eoyaml/MutableYamlMappingBuilderTest.java diff --git a/src/main/java/com/amihaiemil/eoyaml/MutableYamlMappingBuilder.java b/src/main/java/com/amihaiemil/eoyaml/MutableYamlMappingBuilder.java new file mode 100644 index 00000000..5cd58ad0 --- /dev/null +++ b/src/main/java/com/amihaiemil/eoyaml/MutableYamlMappingBuilder.java @@ -0,0 +1,98 @@ +/** + * Copyright (c) 2016-2022, 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.LinkedHashMap; +import java.util.Map; + +/** + * YamlMappingBuilder mutable implementation, for better memory cosumption. + * This class is mutable and NOT thread-safe. + * @author Mihai Andronache (amihaiemil@gmail.com) + * @version $Id$ + * @since 6.1.0 + */ +final class MutableYamlMappingBuilder implements YamlMappingBuilder { + /** + * Added pairs. + */ + private final Map pairs; + + /** + * Default ctor. + */ + MutableYamlMappingBuilder() { + this(new LinkedHashMap<>()); + } + + /** + * Constructor. + * @param pairs Pairs used in building the YamlMapping. + */ + MutableYamlMappingBuilder(final Map pairs) { + this.pairs = pairs; + } + + @Override + public YamlMappingBuilder add(final String key, final String value) { + return this.add( + new PlainStringScalar(key), + new PlainStringScalar(value) + ); + } + + @Override + public YamlMappingBuilder add(final YamlNode key, final String value) { + return this.add(key, new PlainStringScalar(value)); + } + + @Override + public YamlMappingBuilder add(final String key, final YamlNode value) { + return this.add(new PlainStringScalar(key), value); + } + + @Override + public YamlMappingBuilder add(final YamlNode key, final YamlNode value) { + if(key == null || key.isEmpty()) { + throw new IllegalArgumentException( + "The key in YamlMapping cannot be null or empty!" + ); + } + this.pairs.put(key, value); + return this; + } + + @Override + public YamlMapping build(final String comment) { + YamlMapping mapping = new RtYamlMapping(this.pairs, comment); + if (pairs.isEmpty()) { + mapping = new EmptyYamlMapping(mapping); + } + return mapping; + } +} diff --git a/src/main/java/com/amihaiemil/eoyaml/Yaml.java b/src/main/java/com/amihaiemil/eoyaml/Yaml.java index 05fe6d17..daedbe28 100644 --- a/src/main/java/com/amihaiemil/eoyaml/Yaml.java +++ b/src/main/java/com/amihaiemil/eoyaml/Yaml.java @@ -47,13 +47,21 @@ public final class Yaml { private Yaml(){} /** - * Create a {@link YamlMappingBuilder}. + * Create an immutable, thread-safe, {@link YamlMappingBuilder}. * @return Builder of YamlMapping. */ public static YamlMappingBuilder createYamlMappingBuilder() { return new RtYamlMappingBuilder(); } + /** + * Create a mutable, NOT thread-safe, {@link YamlMappingBuilder}. + * @return Builder of YamlMapping. + */ + public static YamlMappingBuilder createMutableYamlMappingBuilder() { + return new MutableYamlMappingBuilder(); + } + /** * Create a {@link YamlSequenceBuilder}. * @return Builder of YamlMapping. diff --git a/src/test/java/com/amihaiemil/eoyaml/MutableYamlMappingBuilderTest.java b/src/test/java/com/amihaiemil/eoyaml/MutableYamlMappingBuilderTest.java new file mode 100644 index 00000000..9457ce0c --- /dev/null +++ b/src/test/java/com/amihaiemil/eoyaml/MutableYamlMappingBuilderTest.java @@ -0,0 +1,187 @@ +/** + * Copyright (c) 2016-2022, 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.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.ArrayList; +import java.util.List; + +/** + * Unit tests for {@link MutableYamlMappingBuilder}. + * @author Mihai Andronache (amihaiemil@gmail.com) + * @version $Id$ + * @since 6.1.0 + */ +public final class MutableYamlMappingBuilderTest { + /** + * MutableYamlMappingBuilder can add a K:V pair of Strings. + */ + @Test + public void addsPairOfStrings() { + YamlMappingBuilder mappingBuilder = new MutableYamlMappingBuilder(); + YamlMappingBuilder withAdded = mappingBuilder.add("key", "value"); + MatcherAssert.assertThat(withAdded, Matchers.notNullValue()); + MatcherAssert.assertThat( + mappingBuilder, Matchers.is(withAdded) + ); + } + + /** + * MutableYamlMappingBuilder can add a K:V pair of String and YamlNode. + */ + @Test + public void addsPairOfStringYamlNode() { + YamlMappingBuilder mappingBuilder = new MutableYamlMappingBuilder(); + YamlMappingBuilder withAdded = mappingBuilder.add( + "key", new PlainStringScalar("value") + ); + MatcherAssert.assertThat(withAdded, Matchers.notNullValue()); + MatcherAssert.assertThat( + mappingBuilder, Matchers.is(withAdded) + ); + } + + /** + * MutableYamlMappingBuilder can add a K:V pair of String and YamlNode. + */ + @Test + public void addsPairOfYamlNodeString() { + YamlMappingBuilder mappingBuilder = new MutableYamlMappingBuilder(); + YamlMappingBuilder withAdded = mappingBuilder.add( + new PlainStringScalar("key"), "value" + ); + MatcherAssert.assertThat(withAdded, Matchers.notNullValue()); + MatcherAssert.assertThat( + mappingBuilder, Matchers.is(withAdded) + ); + } + + /** + * MutableYamlMappingBuilder can add a K:V pair of YamlNode. + */ + @Test + public void addsPairOfYamlNodes() { + YamlMappingBuilder mappingBuilder = new MutableYamlMappingBuilder(); + YamlMappingBuilder withAdded = mappingBuilder.add( + new PlainStringScalar("key"), new PlainStringScalar("value") + ); + MatcherAssert.assertThat(withAdded, Matchers.notNullValue()); + MatcherAssert.assertThat( + mappingBuilder, Matchers.is(withAdded) + ); + } + + /** + * MutableYamlMappingBuilder can build a YamlMapping. + */ + @Test + public void buildsYamlMapping() { + YamlMappingBuilder mappingBuilder = new MutableYamlMappingBuilder(); + List devs = new ArrayList<>(); + devs.add(new PlainStringScalar("amihaiemil")); + devs.add(new PlainStringScalar("salikjan")); + YamlMapping mapping = mappingBuilder + .add("architect", "amihaiemil") + .add("developers", new RtYamlSequence(devs)) + .build(); + MatcherAssert.assertThat(mapping, Matchers.notNullValue()); + MatcherAssert.assertThat( + mapping.string("architect"), Matchers.equalTo("amihaiemil") + ); + MatcherAssert.assertThat( + mapping.yamlSequence("developers").values().size(), + Matchers.equalTo(2) + ); + } + + /** + * MutableYamlMappingBuilder can build a YamlMapping with a comment + * referring to it. + */ + @Test + public void buildsYamlMappingWithComment() { + final YamlMapping mapping = new MutableYamlMappingBuilder() + .add("key", "value") + .add("key1", "value1") + .build("some test mapping"); + final Comment com = mapping.comment(); + MatcherAssert.assertThat(com.yamlNode(), Matchers.is(mapping)); + MatcherAssert.assertThat( + com.value(), + Matchers.equalTo("some test mapping") + ); + } + + /** + * MutableYamlMappingBuilder should complain when a null key is provided. + */ + @Test + public void complainsOnNullKey() { + final YamlNode key = null; + try { + final YamlMapping mapping = new MutableYamlMappingBuilder() + .add(key, "value") + .build("some test mapping"); + Assert.fail("IAE was expected!"); + } catch (final IllegalArgumentException ex) { + MatcherAssert.assertThat( + ex.getMessage(), + Matchers.equalTo( + "The key in YamlMapping cannot be null or empty!" + ) + ); + } + } + + /** + * MutableYamlMappingBuilder should complain when an empty key is provided. + */ + @Test + public void complainsOnEmptyKey() { + final BaseYamlNode key = Mockito.mock(BaseYamlNode.class); + Mockito.when(key.isEmpty()).thenReturn(true); + try { + final YamlMapping mapping = new MutableYamlMappingBuilder() + .add(key, "value") + .build("some test mapping"); + Assert.fail("IAE was expected!"); + } catch (final IllegalArgumentException ex) { + MatcherAssert.assertThat( + ex.getMessage(), + Matchers.equalTo( + "The key in YamlMapping cannot be null or empty!" + ) + ); + } + } +} diff --git a/src/test/java/com/amihaiemil/eoyaml/YamlTest.java b/src/test/java/com/amihaiemil/eoyaml/YamlTest.java index e396f2ab..1e42e81b 100644 --- a/src/test/java/com/amihaiemil/eoyaml/YamlTest.java +++ b/src/test/java/com/amihaiemil/eoyaml/YamlTest.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2016-2020, Mihai Emil Andronache + * Copyright (c) 2016-2022, Mihai Emil Andronache * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -46,12 +46,30 @@ public final class YamlTest { /** - * Yaml can create a YamlMappingBuilder. + * Yaml can create an immutable YamlMappingBuilder. */ @Test public void createsYamlMappingBuilder() { MatcherAssert.assertThat( - Yaml.createYamlMappingBuilder(), Matchers.notNullValue() + Yaml.createYamlMappingBuilder(), + Matchers.allOf( + Matchers.notNullValue(), + Matchers.instanceOf(RtYamlMappingBuilder.class) + ) + ); + } + + /** + * Yaml can create a mutable YamlMappingBuilder. + */ + @Test + public void createsMutableYamlMappingBuilder() { + MatcherAssert.assertThat( + Yaml.createMutableYamlMappingBuilder(), + Matchers.allOf( + Matchers.notNullValue(), + Matchers.instanceOf(MutableYamlMappingBuilder.class) + ) ); }