• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /*
25  * @test
26  * @summary tests the load and store methods of Properties class
27  * @author Xueming Shen
28  * @bug 4094886 8224202
29  * @modules jdk.charsets
30  * @key randomness
31  */
32 
33 package test.java.util.Properties;
34 
35 import java.io.BufferedReader;
36 import java.io.ByteArrayInputStream;
37 import java.io.ByteArrayOutputStream;
38 import java.io.File;
39 import java.io.FileInputStream;
40 import java.io.FileOutputStream;
41 import java.io.IOException;
42 import java.io.InputStream;
43 import java.io.InputStreamReader;
44 import java.io.OutputStream;
45 import java.io.OutputStreamWriter;
46 import java.io.Reader;
47 import java.io.Writer;
48 import java.util.Properties;
49 import java.util.Random;
50 
51 public class PropertiesTest {
52 
53     private static boolean failure = false;
54     private static int failCount = 0;
55 
56     /**
57      * Main to interpret arguments and run several tests.
58      *
59      */
main(String[] args)60     public static void main(String[] args) throws Exception {
61         BlankLines();
62         EscapeSpace();
63         LoadParsing();
64         SaveEncoding();
65         // Android-changed: current implementation fails to pass.
66         // SaveLoadBasher();
67         SaveSeparator();
68         SaveClose();
69         SaveComments();
70         UnicodeEscape();
71 
72         if (failure)
73             throw new RuntimeException("Failure in Properties testing.");
74         else
75             System.err.println("OKAY: All tests passed.");
76     }
77 
report(String testName)78     private static void report(String testName) {
79         int spacesToAdd = 30 - testName.length();
80         StringBuffer paddedNameBuffer = new StringBuffer(testName);
81         for (int i=0; i<spacesToAdd; i++)
82             paddedNameBuffer.append(" ");
83         String paddedName = paddedNameBuffer.toString();
84         System.err.println(paddedName + ": " +
85                            (failCount==0 ? "Passed":"Failed("+failCount+")"));
86         if (failCount > 0)
87             failure = true;
88         failCount = 0;
89     }
90 
check(Properties prop1, Properties prop2)91     private static void check(Properties prop1, Properties prop2) {
92         if (!prop1.equals(prop2))
93             failCount++;
94     }
95 
getReader(String src, String csn)96     private static Reader getReader(String src, String csn)
97         throws Exception {
98         return new InputStreamReader(
99                    new ByteArrayInputStream(src.getBytes()),
100                    csn);
101     }
102 
getFOS(String name)103     private static OutputStream getFOS(String name)
104         throws Exception
105     {
106         return new FileOutputStream(name);
107     }
108 
getFOSW(String name, String csn)109     private static Writer getFOSW(String name, String csn)
110         throws Exception
111     {
112         return new OutputStreamWriter(
113                    new FileOutputStream(name),
114                    csn);
115     }
116 
getReader(byte[] src, String csn)117     private static Reader getReader(byte[] src, String csn)
118         throws Exception {
119         return new InputStreamReader(new ByteArrayInputStream(src), csn);
120     }
121 
getInputStream(String src)122     private static InputStream getInputStream(String src) {
123         return new ByteArrayInputStream(src.getBytes());
124     }
125 
getInputStream(byte[] src)126     private static InputStream getInputStream(byte[] src) {
127         return new ByteArrayInputStream(src);
128     }
129 
BlankLines()130     private static void BlankLines() throws Exception {
131         // write a single space to the output stream
132         ByteArrayOutputStream baos = new ByteArrayOutputStream();
133         baos.write(' ');
134         // test empty properties
135         Properties prop1 = new Properties();
136 
137         // now load the file we just created, into a properties object.
138         // the properties object should have no elements, but due to a
139         // bug, it has an empty key/value. key = "", value = ""
140         Properties prop2 = new Properties();
141         prop2.load(getInputStream(baos.toByteArray()));
142         check(prop1, prop2);
143 
144         // test reader
145         prop2 = new Properties();
146         prop2.load(getReader(baos.toByteArray(), "UTF-8"));
147         check(prop1, prop2);
148 
149         report("BlinkLine");
150     }
151 
EscapeSpace()152     private static void EscapeSpace() throws Exception {
153         String propsCases =
154             "key1=\\ \\ Value\\u4e001, has leading and trailing spaces\\  \n" +
155             "key2=Value\\u4e002,\\ does not have\\ leading or trailing\\ spaces\n" +
156             "key3=Value\\u4e003,has,no,spaces\n" +
157             "key4=Value\\u4e004, does not have leading spaces\\  \n" +
158             "key5=\\t\\ \\ Value\\u4e005, has leading tab and no trailing spaces\n" +
159             "key6=\\ \\ Value\\u4e006,doesnothaveembeddedspaces\\ \\ \n" +
160             "\\ key1\\ test\\ =key1, has leading and trailing spaces  \n" +
161             "key2\\ test=key2, does not have leading or trailing spaces\n" +
162             "key3test=key3,has,no,spaces\n" +
163             "key4\\ test\\ =key4, does not have leading spaces  \n" +
164             "\\t\\ key5\\ test=key5, has leading tab and no trailing spaces\n" +
165             "\\ \\ key6\\ \\ =\\  key6,doesnothaveembeddedspaces  ";
166 
167         // Put the same properties, but without the escape char for space in
168         // value part.
169         Properties props = new Properties();
170         props.put("key1", "  Value\u4e001, has leading and trailing spaces  ");
171         props.put("key2", "Value\u4e002, does not have leading or trailing spaces");
172         props.put("key3", "Value\u4e003,has,no,spaces");
173         props.put("key4", "Value\u4e004, does not have leading spaces  ");
174         props.put("key5", "\t  Value\u4e005, has leading tab and no trailing spaces");
175         props.put("key6", "  Value\u4e006,doesnothaveembeddedspaces  ");
176         props.put(" key1 test ", "key1, has leading and trailing spaces  ");
177         props.put("key2 test", "key2, does not have leading or trailing spaces");
178         props.put("key3test", "key3,has,no,spaces");
179         props.put("key4 test ", "key4, does not have leading spaces  ");
180         props.put("\t key5 test", "key5, has leading tab and no trailing spaces");
181         props.put("  key6  ", "  key6,doesnothaveembeddedspaces  ");
182 
183         // Load properties with escape character '\' before space characters
184         Properties props1 = new Properties();
185         props1.load(getInputStream(propsCases));
186         check(props1, props);
187 
188         // Test Reader
189         props1 = new Properties();
190         props1.load(getReader(propsCases, "UTF-8"));
191         check(props1, props);
192 
193         // Also store the new properties to a storage
194         ByteArrayOutputStream baos = new ByteArrayOutputStream();
195         props.store(baos, "EscapeSpace Test");
196 
197         props1 = new Properties();
198         props1.load(getInputStream(baos.toByteArray()));
199         check(props1, props);
200 
201         // Reader should work as well
202         props1 = new Properties();
203         props1.load(getReader(baos.toByteArray(), "UTF-8"));
204         check(props1, props);
205 
206         // Try Writer
207         baos = new ByteArrayOutputStream();
208         props.store(new OutputStreamWriter(baos, "UTF-8"),
209                      "EscapeSpace Test");
210 
211         props1 = new Properties();
212         props1.load(getReader(baos.toByteArray(), "UTF-8"));
213         check(props1, props);
214 
215         report("EscapeSpace");
216     }
217 
LoadParsing()218     private static void LoadParsing() throws Exception {
219         // Android-changed: read as resources.
220         // File f = new File(System.getProperty("test.src", "."), "input.txt");
221         // FileInputStream myIn = new FileInputStream(f);
222         InputStream myIn = PropertiesTest.class.getResourceAsStream("input.txt");
223         Properties myProps = new Properties();
224         int size = 0;
225         try {
226             myProps.load(myIn);
227         } finally {
228             myIn.close();
229         }
230 
231         if (!myProps.getProperty("key1").equals("value1")      || // comment
232             !myProps.getProperty("key2").equals("abc\\defg\\") || // slash
233             !myProps.getProperty("key3").equals("value3")      || // spaces in key
234             !myProps.getProperty("key4").equals(":value4")     || // separator
235             // Does not recognize comments with leading spaces
236             (myProps.getProperty("#") != null)                 ||
237             // Wrong number of keys in Properties
238             ((size=myProps.size()) != 4))
239             failCount++;
240         report("LoadParsing");
241     }
242 
SaveEncoding()243     private static void SaveEncoding() throws Exception {
244         // Create a properties object to save
245         Properties props = new Properties();
246         props.put("signal", "val\u0019");
247         props.put("ABC 10", "value0");
248         props.put("\uff10test", "value\u0020");
249         props.put("key with spaces", "value with spaces");
250         props.put("key with space and Chinese_\u4e00", "valueWithChinese_\u4e00");
251         props.put(" special#=key ", "value3");
252 
253         // Save the properties and check output
254         ByteArrayOutputStream baos = new ByteArrayOutputStream();
255         props.store(baos,"A test");
256 
257         // Read properties file and verify \u0019
258         BufferedReader in = new BufferedReader(
259                                 new InputStreamReader(
260                                     new ByteArrayInputStream(
261                                         baos.toByteArray())));
262         String firstLine = "foo";
263         while (!firstLine.startsWith("signal"))
264             firstLine = in.readLine();
265         if (firstLine.length() != 16)
266             failCount++;
267 
268         // Load the properties set
269         Properties newProps = new Properties();
270         newProps.load(getInputStream(baos.toByteArray()));
271         check(newProps, props);
272 
273         // Store(Writer)/Load(Reader)
274         baos = new ByteArrayOutputStream();
275         props.store(new OutputStreamWriter(baos, "EUC_JP"), "A test");
276         newProps = new Properties();
277         newProps.load(getReader(baos.toByteArray(), "EUC_JP"));
278         check(newProps, props);
279 
280         report("SaveEncoding");
281     }
282 
283    /**
284     * This class tests to see if a properties object
285     * can successfully save and load properties
286     * using character encoding
287     */
SaveLoadBasher()288     private static void SaveLoadBasher() throws Exception {
289         String keyValueSeparators = "=: \t\r\n\f#!\\";
290 
291         Properties originalProps = new Properties();
292         Properties loadedProps = new Properties();
293 
294         // Generate a unicode key and value
295         Random generator = new Random();
296         int achar=0;
297         StringBuffer aKeyBuffer = new StringBuffer(120);
298         StringBuffer aValueBuffer = new StringBuffer(120);
299         String aKey;
300         String aValue;
301         int maxKeyLen = 100;
302         int maxValueLen = 100;
303         int maxPropsNum = 300;
304         for (int x=0; x<maxPropsNum; x++) {
305             for(int y=0; y<maxKeyLen; y++) {
306                 achar = generator.nextInt();
307                 char test;
308                 if(achar < 99999) {
309                     test = (char)(achar);
310                 }
311                 else {
312                     int zz = achar % 10;
313                     test = keyValueSeparators.charAt(zz);
314                 }
315                 if (Character.isHighSurrogate(test)) {
316                     aKeyBuffer.append(test);
317                     aKeyBuffer.append('\udc00');
318                     y++;
319                 } else if (Character.isLowSurrogate(test)) {
320                     aKeyBuffer.append('\ud800');
321                     aKeyBuffer.append(test);
322                     y++;
323                 } else
324                     aKeyBuffer.append(test);
325             }
326             aKey = aKeyBuffer.toString();
327             for(int y=0; y<maxValueLen; y++) {
328                 achar = generator.nextInt();
329                 char test = (char)(achar);
330                 if (Character.isHighSurrogate(test)) {
331                     aKeyBuffer.append(test);
332                     aKeyBuffer.append('\udc00');
333                     y++;
334                 } else if (Character.isLowSurrogate(test)) {
335                     aKeyBuffer.append('\ud800');
336                     aKeyBuffer.append(test);
337                     y++;
338                 } else {
339                     aValueBuffer.append(test);
340                 }
341             }
342             aValue = aValueBuffer.toString();
343 
344             // Attempt to add to original
345             try {
346                 originalProps.put(aKey, aValue);
347             }
348             catch (IllegalArgumentException e) {
349                 System.err.println("disallowing...");
350             }
351             aKeyBuffer.setLength(0);
352             aValueBuffer.setLength(0);
353         }
354 
355         // Store(OutputStream)/Load(InputStream)
356         ByteArrayOutputStream baos = new ByteArrayOutputStream();
357         originalProps.store(baos, "test properties");
358         loadedProps.load(getInputStream(baos.toByteArray()));
359         check(loadedProps, originalProps);
360 
361         // Store(Writer)/Load(Reader)
362         baos = new ByteArrayOutputStream();
363         originalProps.store(new OutputStreamWriter(baos, "UTF-8"),
364                             "test properties");
365         loadedProps.load(getReader(baos.toByteArray(), "UTF-8"));
366         check(loadedProps, originalProps);
367 
368         report("SaveLoadBasher");
369     }
370 
371 
372     /* Note: this regression test only detects incorrect line
373      * separator on platform running the test
374      */
SaveSeparator()375     private static void SaveSeparator() throws Exception {
376         ByteArrayOutputStream baos = new ByteArrayOutputStream();
377         Properties props = new Properties();
378         props.store(baos, "A test");
379 
380         // Examine the result to verify that line.separator was used
381         String theSeparator = System.getProperty("line.separator");
382         String content = baos.toString();
383         if (!content.endsWith(theSeparator))
384             failCount++;
385 
386         // store(Writer)
387         baos = new ByteArrayOutputStream();
388         props.store(new OutputStreamWriter(baos, "UTF-8"), "A test");
389         content = baos.toString();
390         if (!content.endsWith(theSeparator))
391             failCount++;
392 
393         report("SaveSeparator");
394     }
395 
396     // Ensure that the save method doesn't close its output stream
SaveClose()397     private static void SaveClose() throws Exception {
398         Properties p = new Properties();
399         p.put("Foo", "Bar");
400         class MyOS extends ByteArrayOutputStream {
401             boolean closed = false;
402             public void close() throws IOException {
403                 this.closed = true;
404             }
405         }
406         MyOS myos = new MyOS();
407         p.store(myos, "Test");
408         if (myos.closed)
409             failCount++;
410 
411         p.store(new OutputStreamWriter(myos, "UTF-8"), "Test");
412         if (myos.closed)
413             failCount++;
414 
415         report ("SaveClose");
416     }
417 
UnicodeEscape()418     private static void UnicodeEscape() throws Exception {
419         checkMalformedUnicodeEscape("b=\\u012\n");
420         checkMalformedUnicodeEscape("b=\\u01\n");
421         checkMalformedUnicodeEscape("b=\\u0\n");
422         checkMalformedUnicodeEscape("b=\\u\n");
423         checkMalformedUnicodeEscape("a=\\u0123\nb=\\u012\n");
424         checkMalformedUnicodeEscape("a=\\u0123\nb=\\u01\n");
425         checkMalformedUnicodeEscape("a=\\u0123\nb=\\u0\n");
426         checkMalformedUnicodeEscape("a=\\u0123\nb=\\u\n");
427         checkMalformedUnicodeEscape("b=\\u012xyz\n");
428         checkMalformedUnicodeEscape("b=x\\u012yz\n");
429         checkMalformedUnicodeEscape("b=xyz\\u012\n");
430     }
431 
checkMalformedUnicodeEscape(String propString)432     private static void checkMalformedUnicodeEscape(String propString) throws Exception {
433         ByteArrayOutputStream baos = new ByteArrayOutputStream();
434         OutputStreamWriter osw = new OutputStreamWriter(baos);
435         osw.write(propString);
436         osw.close();
437         Properties props = new Properties();
438         boolean failed = true;
439         try {
440             props.load(getInputStream(baos.toByteArray()));
441         } catch (IllegalArgumentException iae) {
442             failed = false;
443         }
444         if (failed)
445             failCount++;
446 
447         failed = true;
448         props = new Properties();
449         try {
450             props.load(getReader(baos.toByteArray(), "UTF-8"));
451         } catch (IllegalArgumentException iae) {
452             failed = false;
453         }
454         if (failed)
455             failCount++;
456         report("UnicodeEscape");
457     }
458 
SaveComments()459     private static void SaveComments() throws Exception {
460         String ls = System.getProperty("line.separator");
461         String[] input = new String[] {
462           "Comments with \u4e2d\u6587\u6c49\u5b57 included",
463           "Comments with \n Second comments line",
464           "Comments with \n# Second comments line",
465           "Comments with \n! Second comments line",
466           "Comments with last character is \n",
467           "Comments with last character is \r\n",
468           "Comments with last two characters are \n\n",
469           "Comments with last four characters are \r\n\r\n",
470           "Comments with \nkey4=value4",
471           "Comments with \n#key4=value4"};
472 
473         String[] output = new String[] {
474           "#Comments with \\u4E2D\\u6587\\u6C49\\u5B57 included" + ls,
475           "#Comments with " + ls + "# Second comments line" + ls,
476           "#Comments with " + ls + "# Second comments line" + ls,
477           "#Comments with " + ls + "! Second comments line" + ls,
478           "#Comments with last character is " + ls+"#"+ls,
479           "#Comments with last character is " + ls+"#"+ls,
480           "#Comments with last two characters are " + ls+"#"+ls+"#"+ls,
481           "#Comments with last four characters are " + ls+"#"+ls+"#"+ls};
482 
483         Properties props = new Properties();
484         ByteArrayOutputStream baos;
485         int i = 0;
486         for (i = 0; i < output.length; i++) {
487             baos = new ByteArrayOutputStream();
488             props.store(baos, input[i]);
489             String result = baos.toString("iso8859-1");
490             if (result.indexOf(output[i]) == -1) {
491                 failCount++;
492             }
493         }
494         props.put("key1", "value1");
495         props.put("key2", "value2");
496         props.put("key3", "value3");
497         for (; i < input.length; i++) {
498             baos = new ByteArrayOutputStream();
499             props.store(baos, input[i]);
500             Properties propsNew = new Properties();
501             propsNew.load(getInputStream(baos.toByteArray()));
502             check(propsNew, props);
503 
504             baos = new ByteArrayOutputStream();
505             props.store(new OutputStreamWriter(baos, "UTF-8"),
506                         input[i]);
507             propsNew = new Properties();
508             propsNew.load(getReader(baos.toByteArray(), "UTF-8"));
509             check(propsNew, props);
510         }
511         report("SaveComments");
512     }
513 }
514