View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.collections4.properties;
19  
20  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
21  import static org.junit.jupiter.api.Assertions.assertEquals;
22  import static org.junit.jupiter.api.Assertions.assertFalse;
23  import static org.junit.jupiter.api.Assertions.assertNotEquals;
24  import static org.junit.jupiter.api.Assertions.assertNull;
25  import static org.junit.jupiter.api.Assertions.assertThrows;
26  import static org.junit.jupiter.api.Assertions.assertTrue;
27  import static org.junit.jupiter.api.Assertions.fail;
28  
29  import java.io.ByteArrayInputStream;
30  import java.io.ByteArrayOutputStream;
31  import java.io.IOException;
32  import java.io.PrintStream;
33  import java.io.PrintWriter;
34  import java.io.UnsupportedEncodingException;
35  import java.nio.charset.StandardCharsets;
36  import java.util.HashMap;
37  import java.util.Properties;
38  
39  import org.apache.commons.io.input.NullReader;
40  import org.apache.commons.lang3.ArrayUtils;
41  import org.apache.commons.lang3.StringUtils;
42  import org.junit.jupiter.api.Test;
43  
44  public class EmptyPropertiesTest {
45  
46      /**
47       * Returns the first line from multi-lined string separated by a line separator character
48       *
49       * @param x the multi-lined String
50       * @return the first line from x
51       */
52      private String getFirstLine(final String x) {
53          return x.split("\\R", 2)[0];
54      }
55  
56      private PrintStream newPrintStream(final ByteArrayOutputStream baos) throws UnsupportedEncodingException {
57          return new PrintStream(baos, true, StandardCharsets.UTF_8.name());
58      }
59  
60      private String removeLine2(final ByteArrayOutputStream baos) {
61          return removeLine2(toString(baos));
62      }
63  
64      private String removeLine2(final String x) {
65          final String[] s = x.split("\\R", 2);
66          return s[0] + System.lineSeparator() + (s.length > 2 ? s[2] : StringUtils.EMPTY);
67      }
68  
69      @Test
70      public void testClear() {
71          PropertiesFactory.EMPTY_PROPERTIES.clear();
72          assertEquals(0, PropertiesFactory.EMPTY_PROPERTIES.size());
73      }
74  
75      @Test
76      public void testClone() {
77          // TODO Better test?
78          PropertiesFactory.EMPTY_PROPERTIES.clone();
79          assertEquals(0, PropertiesFactory.EMPTY_PROPERTIES.size());
80      }
81  
82      @Test
83      public void testCompute() {
84          assertThrows(UnsupportedOperationException.class, () -> PropertiesFactory.EMPTY_PROPERTIES.compute("key", (k, v) -> "foo"));
85      }
86  
87      @Test
88      public void testComputeIfAbsent() {
89          assertThrows(UnsupportedOperationException.class, () -> PropertiesFactory.EMPTY_PROPERTIES.computeIfAbsent("key", k -> "foo"));
90      }
91  
92      @Test
93      public void testComputeIfPresent() {
94          assertThrows(UnsupportedOperationException.class, () -> PropertiesFactory.EMPTY_PROPERTIES.computeIfPresent("key", (k, v) -> "foo"));
95      }
96  
97      @Test
98      public void testContains() {
99          assertFalse(PropertiesFactory.EMPTY_PROPERTIES.contains("foo"));
100     }
101 
102     @Test
103     public void testContainsKey() {
104         assertFalse(PropertiesFactory.EMPTY_PROPERTIES.containsKey("foo"));
105     }
106 
107     @Test
108     public void testContainsValue() {
109         assertFalse(PropertiesFactory.EMPTY_PROPERTIES.containsValue("foo"));
110     }
111 
112     @Test
113     public void testElements() {
114         assertFalse(PropertiesFactory.EMPTY_PROPERTIES.elements().hasMoreElements());
115     }
116 
117     @Test
118     public void testEntrySet() {
119         assertTrue(PropertiesFactory.EMPTY_PROPERTIES.entrySet().isEmpty());
120     }
121 
122     @Test
123     public void testEquals() {
124         assertEquals(PropertiesFactory.EMPTY_PROPERTIES, PropertiesFactory.EMPTY_PROPERTIES);
125         assertEquals(PropertiesFactory.EMPTY_PROPERTIES, new Properties());
126         assertEquals(new Properties(), PropertiesFactory.EMPTY_PROPERTIES);
127         assertNotEquals(null, PropertiesFactory.EMPTY_PROPERTIES);
128         final Properties p = new Properties();
129         p.put("Key", "Value");
130         assertNotEquals(PropertiesFactory.EMPTY_PROPERTIES, p);
131         assertNotEquals(p, PropertiesFactory.EMPTY_PROPERTIES);
132     }
133 
134     @Test
135     public void testForEach() {
136         PropertiesFactory.EMPTY_PROPERTIES.forEach((k, v) -> fail());
137     }
138 
139     @Test
140     public void testGet() {
141         assertNull(PropertiesFactory.EMPTY_PROPERTIES.get("foo"));
142     }
143 
144     @Test
145     public void testGetOrDefault() {
146         assertEquals("bar", PropertiesFactory.EMPTY_PROPERTIES.getOrDefault("foo", "bar"));
147     }
148 
149     @Test
150     public void testGetProperty() {
151         assertNull(PropertiesFactory.EMPTY_PROPERTIES.getProperty("foo"));
152     }
153 
154     @Test
155     public void testGetPropertyDefault() {
156         assertEquals("bar", PropertiesFactory.EMPTY_PROPERTIES.getProperty("foo", "bar"));
157     }
158 
159     @Test
160     public void testHashCode() {
161         assertEquals(PropertiesFactory.EMPTY_PROPERTIES.hashCode(), PropertiesFactory.EMPTY_PROPERTIES.hashCode());
162         // Should be equals?
163         // assertEquals(PropertiesFactory.EMPTY_PROPERTIES.hashCode(), new Properties().hashCode());
164     }
165 
166     @Test
167     public void testIsEmpty() {
168         assertTrue(PropertiesFactory.EMPTY_PROPERTIES.isEmpty());
169     }
170 
171     @Test
172     public void testKeys() {
173         assertFalse(PropertiesFactory.EMPTY_PROPERTIES.keys().hasMoreElements());
174     }
175 
176     @Test
177     public void testKeySet() {
178         assertTrue(PropertiesFactory.EMPTY_PROPERTIES.isEmpty());
179     }
180 
181     @Test
182     public void testListToPrintStream() {
183         // actual
184         final ByteArrayOutputStream actual = new ByteArrayOutputStream();
185         PropertiesFactory.EMPTY_PROPERTIES.list(new PrintStream(actual));
186         // expected
187         final ByteArrayOutputStream expected = new ByteArrayOutputStream();
188         PropertiesFactory.INSTANCE.createProperties().list(new PrintStream(expected));
189         assertArrayEquals(expected.toByteArray(), actual.toByteArray());
190         expected.reset();
191         new Properties().list(new PrintStream(expected));
192         assertArrayEquals(expected.toByteArray(), actual.toByteArray());
193     }
194 
195     @Test
196     public void testListToPrintWriter() {
197         // actual
198         final ByteArrayOutputStream actual = new ByteArrayOutputStream();
199         PropertiesFactory.EMPTY_PROPERTIES.list(new PrintWriter(actual));
200         // expected
201         final ByteArrayOutputStream expected = new ByteArrayOutputStream();
202         PropertiesFactory.INSTANCE.createProperties().list(new PrintWriter(expected));
203         assertArrayEquals(expected.toByteArray(), actual.toByteArray());
204         expected.reset();
205         new Properties().list(new PrintWriter(expected));
206         assertArrayEquals(expected.toByteArray(), actual.toByteArray());
207     }
208 
209     @Test
210     public void testLoadFromXML() {
211         assertThrows(UnsupportedOperationException.class,
212             () -> PropertiesFactory.EMPTY_PROPERTIES.loadFromXML(new ByteArrayInputStream(ArrayUtils.EMPTY_BYTE_ARRAY)));
213     }
214 
215     @Test
216     public void testLoadInputStream() {
217         assertThrows(UnsupportedOperationException.class, () -> PropertiesFactory.EMPTY_PROPERTIES.load(new ByteArrayInputStream(ArrayUtils.EMPTY_BYTE_ARRAY)));
218     }
219 
220     @Test
221     public void testLoadReader() throws IOException {
222         try (NullReader reader = new NullReader(0)) {
223             assertThrows(UnsupportedOperationException.class, () -> PropertiesFactory.EMPTY_PROPERTIES.load(reader));
224         }
225     }
226 
227     @Test
228     public void testMerge() {
229         assertThrows(UnsupportedOperationException.class, () -> PropertiesFactory.EMPTY_PROPERTIES.merge("key", "value", (k, v) -> "foo"));
230     }
231 
232     @Test
233     public void testPropertyName() {
234         assertFalse(PropertiesFactory.EMPTY_PROPERTIES.propertyNames().hasMoreElements());
235     }
236 
237     @Test
238     public void testPut() {
239         assertThrows(UnsupportedOperationException.class, () -> PropertiesFactory.EMPTY_PROPERTIES.put("Key", "Value"));
240     }
241 
242     @Test
243     public void testPutAll() {
244         assertThrows(UnsupportedOperationException.class, () -> PropertiesFactory.EMPTY_PROPERTIES.putAll(new HashMap<>()));
245     }
246 
247     @Test
248     public void testPutIfAbsent() {
249         assertThrows(UnsupportedOperationException.class, () -> PropertiesFactory.EMPTY_PROPERTIES.putIfAbsent("Key", "Value"));
250     }
251 
252     @Test
253     public void testRehash() {
254         // Can't really test without extending and casting to a currently private class
255         // PropertiesFactory.EMPTY_PROPERTIES.rehash();
256     }
257 
258     @Test
259     public void testRemove() {
260         assertThrows(UnsupportedOperationException.class, () -> PropertiesFactory.EMPTY_PROPERTIES.remove("key", "value"));
261     }
262 
263     @Test
264     public void testRemoveKey() {
265         assertThrows(UnsupportedOperationException.class, () -> PropertiesFactory.EMPTY_PROPERTIES.remove("key"));
266     }
267 
268     @Test
269     public void testReplace() {
270         assertThrows(UnsupportedOperationException.class, () -> PropertiesFactory.EMPTY_PROPERTIES.replace("key", "value1"));
271     }
272 
273     @Test
274     public void testReplaceAll() {
275         assertThrows(UnsupportedOperationException.class, () -> PropertiesFactory.EMPTY_PROPERTIES.replaceAll((k, v) -> "value1"));
276     }
277 
278     @Test
279     public void testReplaceOldValue() {
280         assertThrows(UnsupportedOperationException.class, () -> PropertiesFactory.EMPTY_PROPERTIES.replace("key", "value1", "value2"));
281     }
282 
283     @Test
284     public void testSave() throws IOException {
285         final String comments = "Hello world!";
286         try (ByteArrayOutputStream actual = new ByteArrayOutputStream(); ByteArrayOutputStream expected = new ByteArrayOutputStream()) {
287             // actual
288             PropertiesFactory.EMPTY_PROPERTIES.store(actual, comments);
289             // expected
290             PropertiesFactory.INSTANCE.createProperties().store(expected, comments);
291 
292             // Properties.store stores the specified comment appended with current time stamp in the next line
293             final String expectedComment = getFirstLine(expected.toString(StandardCharsets.UTF_8.name()));
294             final String actualComment = getFirstLine(actual.toString(StandardCharsets.UTF_8.name()));
295             assertEquals(expectedComment, actualComment,
296                 () -> String.format("Expected String '%s' with length '%s'", expectedComment, expectedComment.length()));
297             expected.reset();
298             try (PrintStream out = new PrintStream(expected)) {
299                 new Properties().store(out, comments);
300             }
301             final String[] expectedLines = expected.toString(StandardCharsets.UTF_8.displayName()).split("\\n");
302             final String[] actualLines = actual.toString(StandardCharsets.UTF_8.displayName()).split("\\n");
303             assertEquals(expectedLines.length, actualLines.length);
304             // The assertion below checks that the comment is the same in both files
305             assertEquals(expectedLines[0], actualLines[0]);
306             // N.B.: We must not expect expectedLines[1] and actualLines[1] to have the same value as
307             // it contains the timestamp of when the data was written to the stream, which makes
308             // this test brittle, causing intermitent failures, see COLLECTIONS-812
309         }
310     }
311 
312     @Test
313     public void testSetProperty() {
314         assertThrows(UnsupportedOperationException.class, () -> PropertiesFactory.EMPTY_PROPERTIES.setProperty("Key", "Value"));
315     }
316 
317     @Test
318     public void testSize() {
319         assertEquals(0, PropertiesFactory.EMPTY_PROPERTIES.size());
320     }
321 
322     @Test
323     public void testStoreToOutputStream() throws IOException {
324         // Note: The second line is always a comment with a timestamp.
325         final String comments = "Hello world!";
326         // actual
327         final ByteArrayOutputStream actual = new ByteArrayOutputStream();
328         try (PrintStream ps = newPrintStream(actual)) {
329             PropertiesFactory.EMPTY_PROPERTIES.store(ps, comments);
330         }
331         // expected
332         final ByteArrayOutputStream expected = new ByteArrayOutputStream();
333         try (PrintStream ps = newPrintStream(expected)) {
334             PropertiesFactory.INSTANCE.createProperties().store(ps, comments);
335         }
336         assertEquals(removeLine2(expected), removeLine2(actual));
337         expected.reset();
338         try (PrintStream ps = newPrintStream(expected)) {
339             new Properties().store(ps, comments);
340         }
341         assertEquals(removeLine2(expected), removeLine2(actual), () -> removeLine2(actual));
342     }
343 
344     @Test
345     public void testStoreToPrintWriter() throws IOException {
346         // Note: The second line is always a comment with a timestamp.
347         final String comments = "Hello world!";
348         // actual
349         final ByteArrayOutputStream actual = new ByteArrayOutputStream();
350         try (PrintStream ps = newPrintStream(actual)) {
351             PropertiesFactory.EMPTY_PROPERTIES.store(ps, comments);
352         }
353         // expected
354         final ByteArrayOutputStream expected = new ByteArrayOutputStream();
355         try (PrintStream ps = newPrintStream(expected)) {
356             PropertiesFactory.INSTANCE.createProperties().store(ps, comments);
357         }
358         assertEquals(removeLine2(expected), removeLine2(actual));
359         expected.reset();
360         try (PrintStream ps = newPrintStream(expected)) {
361             new Properties().store(ps, comments);
362         }
363         assertEquals(removeLine2(expected), removeLine2(actual));
364     }
365 
366     @Test
367     public void testStoreToXMLOutputStream() throws IOException {
368         // Note: The second line is always a comment with a timestamp.
369         final String comments = "Hello world!";
370         // actual
371         final ByteArrayOutputStream actual = new ByteArrayOutputStream();
372         try (PrintStream ps = newPrintStream(actual)) {
373             PropertiesFactory.EMPTY_PROPERTIES.storeToXML(ps, comments);
374         }
375         // expected
376         final ByteArrayOutputStream expected = new ByteArrayOutputStream();
377         try (PrintStream ps = newPrintStream(expected)) {
378             PropertiesFactory.INSTANCE.createProperties().storeToXML(ps, comments);
379         }
380         assertEquals(toString(expected), toString(actual));
381         expected.reset();
382         try (PrintStream ps = new PrintStream(expected)) {
383             new Properties().storeToXML(ps, comments);
384         }
385         assertEquals(removeLine2(expected), removeLine2(actual));
386     }
387 
388     @Test
389     public void testStoreToXMLOutputStreamWithEncoding() throws IOException {
390         // Note: The second line is always a comment with a timestamp.
391         final String comments = "Hello world!";
392         final String encoding = StandardCharsets.UTF_8.name();
393         // actual
394         final ByteArrayOutputStream actual = new ByteArrayOutputStream();
395         try (PrintStream ps = newPrintStream(actual)) {
396             PropertiesFactory.EMPTY_PROPERTIES.storeToXML(ps, comments, encoding);
397         }
398         // expected
399         final ByteArrayOutputStream expected = new ByteArrayOutputStream();
400         try (PrintStream ps = newPrintStream(expected)) {
401             PropertiesFactory.INSTANCE.createProperties().storeToXML(ps, comments, encoding);
402         }
403         assertEquals(removeLine2(expected), removeLine2(actual));
404         expected.reset();
405         try (PrintStream ps = newPrintStream(expected)) {
406             new Properties().storeToXML(ps, comments, encoding);
407         }
408         assertEquals(removeLine2(expected), removeLine2(actual));
409     }
410 
411     @Test
412     public void testStringPropertyName() {
413         assertTrue(PropertiesFactory.EMPTY_PROPERTIES.stringPropertyNames().isEmpty());
414     }
415 
416     @Test
417     public void testToString() {
418         assertEquals(new Properties().toString(), PropertiesFactory.EMPTY_PROPERTIES.toString());
419     }
420 
421     @Test
422     public void testValues() {
423         assertTrue(PropertiesFactory.EMPTY_PROPERTIES.isEmpty());
424     }
425 
426     private String toString(final ByteArrayOutputStream expected) {
427         return new String(expected.toByteArray(), StandardCharsets.UTF_8);
428     }
429 }