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:09 UTC

[commons-collections] branch master updated (0bf44ae -> acff58d)

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

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


    from 0bf44ae  COLLECTIONS-697: correct changelog entry (ref #55)
     new 8f906c0  [COLLECTIONS-746] Add org.apache.commons.collections4.properties.PropertiesFactory.EMPTY_PROPERTIES.
     new 181fe9c  Merge branch 'master' of https://gitbox.apache.org/repos/asf/commons-collections.git
     new acff58d  [COLLECTIONS-746] Add org.apache.commons.collections4.properties.PropertiesFactory.EMPTY_PROPERTIES.

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 pom.xml                                            |  18 +-
 src/changes/changes.xml                            |   6 +
 .../collections4/properties/PropertiesFactory.java | 294 +++++++++++++++++
 .../properties/EmptyPropertiesTest.java            | 349 +++++++++++++++++++++
 4 files changed, 661 insertions(+), 6 deletions(-)
 create mode 100644 src/test/java/org/apache/commons/collections4/properties/EmptyPropertiesTest.java


[commons-collections] 02/03: Merge branch 'master' of https://gitbox.apache.org/repos/asf/commons-collections.git

Posted by gg...@apache.org.
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 181fe9c708624f9418777c885eb1653a05708294
Merge: 8f906c0 0bf44ae
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Sun Feb 9 11:40:54 2020 -0500

    Merge branch 'master' of https://gitbox.apache.org/repos/asf/commons-collections.git

 src/changes/changes.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)



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

Posted by gg...@apache.org.
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 acff58db5acbf0c6807cac01c316db643aef4836
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Sun Feb 9 11:42:05 2020 -0500

    [COLLECTIONS-746] Add
    org.apache.commons.collections4.properties.PropertiesFactory.EMPTY_PROPERTIES.
    
    Fix imports.
---
 .../org/apache/commons/collections4/properties/PropertiesFactory.java    | 1 -
 1 file changed, 1 deletion(-)

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 40f6359..baa9a45 100644
--- a/src/main/java/org/apache/commons/collections4/properties/PropertiesFactory.java
+++ b/src/main/java/org/apache/commons/collections4/properties/PropertiesFactory.java
@@ -28,7 +28,6 @@ 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;


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

Posted by gg...@apache.org.
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());
+    }
+}