You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2020/02/09 16:42:10 UTC

[commons-collections] 01/03: [COLLECTIONS-746] Add org.apache.commons.collections4.properties.PropertiesFactory.EMPTY_PROPERTIES.

This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-collections.git

commit 8f906c08fa0eaf34283f2dad8a508158c3332981
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Sun Feb 9 11:40:43 2020 -0500

    [COLLECTIONS-746] Add
    org.apache.commons.collections4.properties.PropertiesFactory.EMPTY_PROPERTIES.
    
    [build] Update Jacoco from 0.8.4 to 0.8.5.
---
 pom.xml                                            |  18 +-
 src/changes/changes.xml                            |   6 +
 .../collections4/properties/PropertiesFactory.java | 295 +++++++++++++++++
 .../properties/EmptyPropertiesTest.java            | 349 +++++++++++++++++++++
 4 files changed, 662 insertions(+), 6 deletions(-)

diff --git a/pom.xml b/pom.xml
index f9afc4e..9f08bdd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -463,10 +463,16 @@
       <scope>test</scope>
     </dependency>
     <dependency>
-    	<groupId>commons-codec</groupId>
-    	<artifactId>commons-codec</artifactId>
-    	<version>1.14</version>
-    	<optional>true</optional>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+      <version>2.6</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>commons-codec</groupId>
+      <artifactId>commons-codec</artifactId>
+      <version>1.14</version>
+      <optional>true</optional>
     </dependency>
   </dependencies>
 
@@ -534,10 +540,10 @@
 
     <!-- Override clirr version to enable clirr on Java 8 -->
     <commons.clirr.version>2.8</commons.clirr.version>
-    <commons.jacoco.version>0.8.4</commons.jacoco.version>
+    <commons.jacoco.version>0.8.5</commons.jacoco.version>
     
     <!--Commons Release Plugin -->
-    <commons.bc.version>4.3</commons.bc.version>
+    <commons.bc.version>4.4</commons.bc.version>
     <commons.release.isDistModule>true</commons.release.isDistModule>
     <commons.releaseManagerName>Gary Gregory</commons.releaseManagerName>    
     <commons.releaseManagerKey>86fdc7e2a11262cb</commons.releaseManagerKey>
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index bde17b3..ca6b387 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -120,6 +120,12 @@
     <action dev="ggregory" type="update" due-to="Gary Gregory">
       [build] Update Apache commons-parent from 48 to 50.
     </action>
+    <action issue="COLLECTIONS-746" dev="ggregory" type="add" due-to="Gary Gregory">
+      Add org.apache.commons.collections4.properties.PropertiesFactory.EMPTY_PROPERTIES.
+    </action>
+    <action dev="ggregory" type="update" due-to="Gary Gregory">
+      [build] Update Jacoco from 0.8.4 to 0.8.5.
+    </action>
   </release>
   <release version="4.4" date="2019-07-05" description="Maintenance release.">
     <action issue="COLLECTIONS-710" dev="ggregory" type="fix" due-to="Yu Shi, Gary Gregory">
diff --git a/src/main/java/org/apache/commons/collections4/properties/PropertiesFactory.java b/src/main/java/org/apache/commons/collections4/properties/PropertiesFactory.java
index 04de759..40f6359 100644
--- a/src/main/java/org/apache/commons/collections4/properties/PropertiesFactory.java
+++ b/src/main/java/org/apache/commons/collections4/properties/PropertiesFactory.java
@@ -17,7 +17,26 @@
 
 package org.apache.commons.collections4.properties;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.InvalidPropertiesFormatException;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
 import java.util.Properties;
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
 
 /**
  * Creates and loads {@link Properties}.
@@ -27,6 +46,282 @@ import java.util.Properties;
  */
 public class PropertiesFactory extends AbstractPropertiesFactory<Properties> {
 
+    private static class EmptyProperties extends Properties {
+
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        public synchronized void clear() {
+            // Noop
+        }
+
+        @Override
+        public synchronized Object compute(final Object key,
+            final BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) {
+            Objects.requireNonNull(key);
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public synchronized Object computeIfAbsent(final Object key,
+            final Function<? super Object, ? extends Object> mappingFunction) {
+            Objects.requireNonNull(key);
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public synchronized Object computeIfPresent(final Object key,
+            final BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) {
+            Objects.requireNonNull(key);
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public synchronized boolean contains(final Object value) {
+            return false;
+        }
+
+        @Override
+        public synchronized boolean containsKey(final Object key) {
+            return false;
+        }
+
+        @Override
+        public boolean containsValue(final Object value) {
+            return false;
+        }
+
+        @Override
+        public synchronized Enumeration<Object> elements() {
+            return Collections.emptyEnumeration();
+        }
+
+        @Override
+        public Set<Entry<Object, Object>> entrySet() {
+            return Collections.emptySet();
+        }
+
+        @Override
+        public synchronized boolean equals(final Object o) {
+            return (o instanceof Properties) && ((Properties) o).isEmpty();
+        }
+
+        @Override
+        public synchronized void forEach(final BiConsumer<? super Object, ? super Object> action) {
+            Objects.requireNonNull(action);
+        }
+
+        @Override
+        public synchronized Object get(final Object key) {
+            return null;
+        }
+
+        @Override
+        public synchronized Object getOrDefault(final Object key, final Object defaultValue) {
+            return defaultValue;
+        }
+
+        @Override
+        public String getProperty(final String key) {
+            return null;
+        }
+
+        @Override
+        public String getProperty(final String key, final String defaultValue) {
+            return defaultValue;
+        }
+
+        @Override
+        public synchronized int hashCode() {
+            return 0;
+        }
+
+        @Override
+        public synchronized boolean isEmpty() {
+            return true;
+        }
+
+        @Override
+        public synchronized Enumeration<Object> keys() {
+            return Collections.emptyEnumeration();
+        }
+
+        @Override
+        public Set<Object> keySet() {
+            return Collections.emptySet();
+        }
+
+        @Override
+        public void list(final PrintStream out) {
+            // Implement as super
+            super.list(out);
+        }
+
+        @Override
+        public void list(final PrintWriter out) {
+            // Implement as super
+            super.list(out);
+        }
+
+        @Override
+        public synchronized void load(final InputStream inStream) throws IOException {
+            Objects.requireNonNull(inStream);
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public synchronized void load(final Reader reader) throws IOException {
+            Objects.requireNonNull(reader);
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public synchronized void loadFromXML(final InputStream in)
+            throws IOException, InvalidPropertiesFormatException {
+            Objects.requireNonNull(in);
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public synchronized Object merge(final Object key, final Object value,
+            final BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) {
+            Objects.requireNonNull(key);
+            Objects.requireNonNull(value);
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Enumeration<?> propertyNames() {
+            return Collections.emptyEnumeration();
+        }
+
+        @Override
+        public synchronized Object put(final Object key, final Object value) {
+            Objects.requireNonNull(key);
+            Objects.requireNonNull(value);
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public synchronized void putAll(final Map<? extends Object, ? extends Object> t) {
+            Objects.requireNonNull(t);
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public synchronized Object putIfAbsent(final Object key, final Object value) {
+            Objects.requireNonNull(key);
+            Objects.requireNonNull(value);
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        protected void rehash() {
+            // Noop
+        }
+
+        @Override
+        public synchronized Object remove(final Object key) {
+            Objects.requireNonNull(key);
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public synchronized boolean remove(final Object key, final Object value) {
+            Objects.requireNonNull(key);
+            Objects.requireNonNull(value);
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public synchronized Object replace(final Object key, final Object value) {
+            Objects.requireNonNull(key);
+            Objects.requireNonNull(value);
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public synchronized boolean replace(final Object key, final Object oldValue, final Object newValue) {
+            Objects.requireNonNull(key);
+            Objects.requireNonNull(oldValue);
+            Objects.requireNonNull(newValue);
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public synchronized void replaceAll(
+            final BiFunction<? super Object, ? super Object, ? extends Object> function) {
+            Objects.requireNonNull(function);
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void save(final OutputStream out, final String comments) {
+            // Implement as super
+            super.save(out, comments);
+        }
+
+        @Override
+        public synchronized Object setProperty(final String key, final String value) {
+            Objects.requireNonNull(key);
+            Objects.requireNonNull(value);
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public synchronized int size() {
+            return 0;
+        }
+
+        @Override
+        public void store(final OutputStream out, final String comments) throws IOException {
+            // Implement as super
+            super.store(out, comments);
+        }
+
+        @Override
+        public void store(final Writer writer, final String comments) throws IOException {
+            // Implement as super
+            super.store(writer, comments);
+        }
+
+        @Override
+        public void storeToXML(final OutputStream os, final String comment) throws IOException {
+            // Implement as super
+            super.storeToXML(os, comment);
+        }
+
+        @Override
+        public void storeToXML(final OutputStream os, final String comment, final String encoding) throws IOException {
+            // Implement as super
+            super.storeToXML(os, comment, encoding);
+        }
+
+        @Override
+        public Set<String> stringPropertyNames() {
+            return Collections.emptySet();
+        }
+
+        @Override
+        public synchronized String toString() {
+            // Implement as super
+            return super.toString();
+        }
+
+        @Override
+        public Collection<Object> values() {
+            return Collections.emptyList();
+        }
+
+    }
+
+    /**
+     * The empty map (immutable). This map is serializable.
+     *
+     * @since 4.5
+     */
+    public static final Properties EMPTY_PROPERTIES = new EmptyProperties();
+
     /**
      * The singleton instance.
      */
diff --git a/src/test/java/org/apache/commons/collections4/properties/EmptyPropertiesTest.java b/src/test/java/org/apache/commons/collections4/properties/EmptyPropertiesTest.java
new file mode 100644
index 0000000..82d06c9
--- /dev/null
+++ b/src/test/java/org/apache/commons/collections4/properties/EmptyPropertiesTest.java
@@ -0,0 +1,349 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.collections4.properties;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Properties;
+
+import org.apache.commons.io.input.NullReader;
+import org.apache.commons.lang3.ArrayUtils;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class EmptyPropertiesTest {
+
+    @Test
+    public void testClear() {
+        PropertiesFactory.EMPTY_PROPERTIES.clear();
+        Assert.assertEquals(0, PropertiesFactory.EMPTY_PROPERTIES.size());
+    }
+
+    @Test
+    public void testClone() {
+        // TODO Better test?
+        PropertiesFactory.EMPTY_PROPERTIES.clone();
+        Assert.assertEquals(0, PropertiesFactory.EMPTY_PROPERTIES.size());
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testCompute() {
+        PropertiesFactory.EMPTY_PROPERTIES.compute("key", (k, v) -> "foo");
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testComputeIfAbsent() {
+        PropertiesFactory.EMPTY_PROPERTIES.computeIfAbsent("key", k -> "foo");
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testComputeIfPresent() {
+        PropertiesFactory.EMPTY_PROPERTIES.computeIfPresent("key", (k, v) -> "foo");
+    }
+
+    @Test
+    public void testContains() {
+        Assert.assertFalse(PropertiesFactory.EMPTY_PROPERTIES.contains("foo"));
+    }
+
+    @Test
+    public void testContainsKey() {
+        Assert.assertFalse(PropertiesFactory.EMPTY_PROPERTIES.containsKey("foo"));
+    }
+
+    @Test
+    public void testContainsValue() {
+        Assert.assertFalse(PropertiesFactory.EMPTY_PROPERTIES.containsValue("foo"));
+    }
+
+    @Test
+    public void testElements() {
+        Assert.assertFalse(PropertiesFactory.EMPTY_PROPERTIES.elements().hasMoreElements());
+    }
+
+    @Test
+    public void testEntrySet() {
+        Assert.assertTrue(PropertiesFactory.EMPTY_PROPERTIES.entrySet().isEmpty());
+    }
+
+    @Test
+    public void testEquals() {
+        Assert.assertTrue(PropertiesFactory.EMPTY_PROPERTIES.equals(PropertiesFactory.EMPTY_PROPERTIES));
+        Assert.assertTrue(PropertiesFactory.EMPTY_PROPERTIES.equals(new Properties()));
+        Assert.assertTrue(new Properties().equals(PropertiesFactory.EMPTY_PROPERTIES));
+        Assert.assertFalse(PropertiesFactory.EMPTY_PROPERTIES.equals(null));
+        final Properties p = new Properties();
+        p.put("Key", "Value");
+        Assert.assertFalse(PropertiesFactory.EMPTY_PROPERTIES.equals(p));
+        Assert.assertFalse(p.equals(PropertiesFactory.EMPTY_PROPERTIES));
+    }
+
+    public void testForEach() {
+        PropertiesFactory.EMPTY_PROPERTIES.forEach((k, v) -> Assert.fail());
+    }
+
+    @Test
+    public void testGet() {
+        Assert.assertNull(PropertiesFactory.EMPTY_PROPERTIES.get("foo"));
+    }
+
+    @Test
+    public void testGetOrDefault() {
+        Assert.assertEquals("bar", PropertiesFactory.EMPTY_PROPERTIES.getOrDefault("foo", "bar"));
+    }
+
+    @Test
+    public void testGetProperty() {
+        Assert.assertNull(PropertiesFactory.EMPTY_PROPERTIES.getProperty("foo"));
+    }
+
+    @Test
+    public void testGetPropertyDefault() {
+        Assert.assertEquals("bar", PropertiesFactory.EMPTY_PROPERTIES.getProperty("foo", "bar"));
+    }
+
+    @Test
+    public void testHashCode() {
+        Assert.assertEquals(PropertiesFactory.EMPTY_PROPERTIES.hashCode(),
+            PropertiesFactory.EMPTY_PROPERTIES.hashCode());
+        // Should be equals?
+        // Assert.assertEquals(PropertiesFactory.EMPTY_PROPERTIES.hashCode(), new Properties().hashCode());
+    }
+
+    @Test
+    public void testIsEmpty() {
+        Assert.assertTrue(PropertiesFactory.EMPTY_PROPERTIES.isEmpty());
+    }
+
+    @Test
+    public void testKeys() {
+        Assert.assertFalse(PropertiesFactory.EMPTY_PROPERTIES.keys().hasMoreElements());
+    }
+
+    @Test
+    public void testKeySet() {
+        Assert.assertTrue(PropertiesFactory.EMPTY_PROPERTIES.keySet().isEmpty());
+    }
+
+    @Test
+    public void testListToPrintStream() {
+        // actual
+        final ByteArrayOutputStream actual = new ByteArrayOutputStream();
+        PropertiesFactory.EMPTY_PROPERTIES.list(new PrintStream(actual));
+        // expected
+        final ByteArrayOutputStream expected = new ByteArrayOutputStream();
+        PropertiesFactory.INSTANCE.createProperties().list(new PrintStream(expected));
+        Assert.assertArrayEquals(expected.toByteArray(), actual.toByteArray());
+        expected.reset();
+        new Properties().list(new PrintStream(expected));
+        Assert.assertArrayEquals(expected.toByteArray(), actual.toByteArray());
+    }
+
+    @Test
+    public void testListToPrintWriter() {
+        // actual
+        final ByteArrayOutputStream actual = new ByteArrayOutputStream();
+        PropertiesFactory.EMPTY_PROPERTIES.list(new PrintWriter(actual));
+        // expected
+        final ByteArrayOutputStream expected = new ByteArrayOutputStream();
+        PropertiesFactory.INSTANCE.createProperties().list(new PrintWriter(expected));
+        Assert.assertArrayEquals(expected.toByteArray(), actual.toByteArray());
+        expected.reset();
+        new Properties().list(new PrintWriter(expected));
+        Assert.assertArrayEquals(expected.toByteArray(), actual.toByteArray());
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testLoadFromXML() throws IOException {
+        PropertiesFactory.EMPTY_PROPERTIES.loadFromXML(new ByteArrayInputStream(ArrayUtils.EMPTY_BYTE_ARRAY));
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testLoadInputStream() throws IOException {
+        PropertiesFactory.EMPTY_PROPERTIES.load(new ByteArrayInputStream(ArrayUtils.EMPTY_BYTE_ARRAY));
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testLoadReader() throws IOException {
+        try (final NullReader reader = new NullReader(0)) {
+            PropertiesFactory.EMPTY_PROPERTIES.load(reader);
+        }
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testMerge() {
+        PropertiesFactory.EMPTY_PROPERTIES.merge("key", "value", (k, v) -> "foo");
+    }
+
+    @Test
+    public void testPropertyName() {
+        Assert.assertFalse(PropertiesFactory.EMPTY_PROPERTIES.propertyNames().hasMoreElements());
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testPut() {
+        PropertiesFactory.EMPTY_PROPERTIES.put("Key", "Value");
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testPutAll() {
+        PropertiesFactory.EMPTY_PROPERTIES.putAll(new HashMap<>());
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testPutIfAbsent() {
+        PropertiesFactory.EMPTY_PROPERTIES.putIfAbsent("Key", "Value");
+    }
+
+    @Test
+    public void testRehash() {
+        // Can't really test without extending and casting to a currently private class
+        // PropertiesFactory.EMPTY_PROPERTIES.rehash();
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testRemove() {
+        PropertiesFactory.EMPTY_PROPERTIES.remove("key", "value");
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testRemoveKey() {
+        PropertiesFactory.EMPTY_PROPERTIES.remove("key");
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testReplace() {
+        PropertiesFactory.EMPTY_PROPERTIES.replace("key", "value1");
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testReplaceAll() {
+        PropertiesFactory.EMPTY_PROPERTIES.replaceAll((k, v) -> "value1");
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testReplaceOldValue() {
+        PropertiesFactory.EMPTY_PROPERTIES.replace("key", "value1", "value2");
+    }
+
+    @Test
+    public void testSave() {
+        final String comments = "Hello world!";
+        // actual
+        final ByteArrayOutputStream actual = new ByteArrayOutputStream();
+        PropertiesFactory.EMPTY_PROPERTIES.save(new PrintStream(actual), comments);
+        // expected
+        final ByteArrayOutputStream expected = new ByteArrayOutputStream();
+        PropertiesFactory.INSTANCE.createProperties().save(new PrintStream(expected), comments);
+        Assert.assertArrayEquals(expected.toByteArray(), actual.toByteArray());
+        expected.reset();
+        new Properties().save(new PrintStream(expected), comments);
+        Assert.assertArrayEquals(expected.toByteArray(), actual.toByteArray());
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testSetProperty() {
+        PropertiesFactory.EMPTY_PROPERTIES.setProperty("Key", "Value");
+    }
+
+    @Test
+    public void testSize() {
+        Assert.assertEquals(0, PropertiesFactory.EMPTY_PROPERTIES.size());
+    }
+
+    @Test
+    public void testStoreToOutputStream() throws IOException {
+        final String comments = "Hello world!";
+        // actual
+        final ByteArrayOutputStream actual = new ByteArrayOutputStream();
+        PropertiesFactory.EMPTY_PROPERTIES.store(new PrintStream(actual), comments);
+        // expected
+        final ByteArrayOutputStream expected = new ByteArrayOutputStream();
+        PropertiesFactory.INSTANCE.createProperties().store(new PrintStream(expected), comments);
+        Assert.assertArrayEquals(expected.toByteArray(), actual.toByteArray());
+        expected.reset();
+        new Properties().store(new PrintStream(expected), comments);
+        Assert.assertArrayEquals(expected.toByteArray(), actual.toByteArray());
+    }
+
+    @Test
+    public void testStoreToPrintWriter() throws IOException {
+        final String comments = "Hello world!";
+        // actual
+        final ByteArrayOutputStream actual = new ByteArrayOutputStream();
+        PropertiesFactory.EMPTY_PROPERTIES.store(new PrintWriter(actual), comments);
+        // expected
+        final ByteArrayOutputStream expected = new ByteArrayOutputStream();
+        PropertiesFactory.INSTANCE.createProperties().store(new PrintWriter(expected), comments);
+        Assert.assertArrayEquals(expected.toByteArray(), actual.toByteArray());
+        expected.reset();
+        new Properties().store(new PrintWriter(expected), comments);
+        Assert.assertArrayEquals(expected.toByteArray(), actual.toByteArray());
+    }
+
+    @Test
+    public void testStoreToXMLOutputStream() throws IOException {
+        final String comments = "Hello world!";
+        // actual
+        final ByteArrayOutputStream actual = new ByteArrayOutputStream();
+        PropertiesFactory.EMPTY_PROPERTIES.storeToXML(new PrintStream(actual), comments);
+        // expected
+        final ByteArrayOutputStream expected = new ByteArrayOutputStream();
+        PropertiesFactory.INSTANCE.createProperties().storeToXML(new PrintStream(expected), comments);
+        Assert.assertArrayEquals(expected.toByteArray(), actual.toByteArray());
+        expected.reset();
+        new Properties().storeToXML(new PrintStream(expected), comments);
+        Assert.assertArrayEquals(expected.toByteArray(), actual.toByteArray());
+    }
+
+    @Test
+    public void testStoreToXMLOutputStreamWithEncoding() throws IOException {
+        final String comments = "Hello world!";
+        final String encoding = StandardCharsets.UTF_8.name();
+        // actual
+        final ByteArrayOutputStream actual = new ByteArrayOutputStream();
+        PropertiesFactory.EMPTY_PROPERTIES.storeToXML(new PrintStream(actual), comments, encoding);
+        // expected
+        final ByteArrayOutputStream expected = new ByteArrayOutputStream();
+        PropertiesFactory.INSTANCE.createProperties().storeToXML(new PrintStream(expected), comments, encoding);
+        Assert.assertArrayEquals(expected.toByteArray(), actual.toByteArray());
+        expected.reset();
+        new Properties().storeToXML(new PrintStream(expected), comments, encoding);
+        Assert.assertArrayEquals(expected.toByteArray(), actual.toByteArray());
+    }
+
+    @Test
+    public void testStringPropertyName() {
+        Assert.assertTrue(PropertiesFactory.EMPTY_PROPERTIES.stringPropertyNames().isEmpty());
+    }
+
+    @Test
+    public void testToString() {
+        Assert.assertEquals(new Properties().toString(), PropertiesFactory.EMPTY_PROPERTIES.toString());
+    }
+
+    @Test
+    public void testValues() {
+        Assert.assertTrue(PropertiesFactory.EMPTY_PROPERTIES.values().isEmpty());
+    }
+}