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