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