1 /* 2 * Copyright (c) 2000, 2016, 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 * @bug 4018937 27 * @library /java/text/testlib 28 * @build FormatIteratorTest PParser IntlTest 29 * @run main FormatIteratorTest 30 * @summary Tests the formatToCharacterIterator method of SimpleDateFormat, 31 * MessageFormat and DecimalFormat. 32 */ 33 34 import java.io.*; 35 import java.lang.reflect.*; 36 import java.text.*; 37 import java.util.*; 38 import java.util.concurrent.atomic.AtomicInteger; 39 import java.util.concurrent.atomic.AtomicLong; 40 41 /** 42 * FormatTester creates Formats, and tests the resulting FieldPositions 43 * and AttributedCharacterIterator based on a file. The file is a hierarchical 44 * set of key/value pairs, where each value can also be an array or map. The 45 * top map must contain a tests entry, which will be an array consisting 46 * of pairs of maps. The first map specifies the Format that 47 * should be created, and consists of: 48 * <pre> 49 * class = className 50 * args = (arg1 arg2 ...) 51 * valueClass = className 52 * valueArgs = (arg1 arg2 ...) 53 * </pre> 54 * The second map dictates what to test, and should consist of the following: 55 * <pre> 56 * length = lengthOfFormattedString 57 * text = Result of Formatting 58 * 0...lengthOfFormattedString = (arg1 arg2 ...) 59 * limits = ( range1 range2 ...) 60 * fieldPositions = ( fp1 fp2 ...) 61 * </pre> 62 * <code>lengthOfFormattedString</code> indicate the total length of formatted 63 * string. <code>text</code> indicates the resulting string. 64 * <code>0...x</code> where x == <code>lengthOfFormattedString - 1</code> is 65 * an array of the attributes that should exist at the particular 66 * location. <code>limits</code> is an array of maps, where each map 67 * can be used to test the bounds of a set of attributes. Each map will 68 * consist of: 69 * <pre> 70 * attributes = array of attributes 71 * begin = start location 72 * begin2 = second start location 73 * end = limit location 74 * end2 = second limit location 75 * </pre> 76 * These are tested by iterating from begin to end in the CharacterIterator 77 * and doing the following at each index: 78 * <pre> 79 * getRunStart() == begin 80 * getRunStart(attributes) == begin2 81 * getRunLimit() == end 82 * getRunLimit(attributes) == end2 83 * </pre> 84 * <code>fieldPositions</code> is used to test the results of invoking 85 * <code>format</code> with a <code>FieldPosition</code>. 86 * <code>fieldPositions</code> is an array of maps, where each map contains 87 * the following: 88 * <pre> 89 * field = Integer field reference (optional) 90 * fieldID = Object reference 91 * begin = begin index of FieldPosition after formatting 92 * end = end index of FieldPosition after formatting 93 * </pre> 94 * Any lines starting with {@code '#'} are comment lines and ignored. 95 */ 96 public class FormatIteratorTest extends IntlTest { 97 private static HashMap attrs; 98 private Format format; 99 private Object value; 100 private String text; 101 102 public static final Object ARG0_FIELD_ID = MessageFormat. 103 Field.ARGUMENT; 104 public static final Object ARG1_FIELD_ID = MessageFormat. 105 Field.ARGUMENT; 106 public static final Object ARG2_FIELD_ID = MessageFormat. 107 Field.ARGUMENT; 108 public static final Object ARG3_FIELD_ID = MessageFormat. 109 Field.ARGUMENT; 110 111 public static void main(String[] args) throws Exception { 112 Locale reservedLocale = Locale.getDefault(); 113 TimeZone reservedTimeZone = TimeZone.getDefault(); 114 try { 115 // The current tests are only appropriate for US. If tests are 116 // added for other locales are added, then a property should be 117 // added to each file (test) to be able to specify the locale. 118 Locale.setDefault(Locale.US); 119 TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles")); 120 new FormatIteratorTest().run(args); 121 } finally { 122 // restore the reserved locale and time zone 123 Locale.setDefault(reservedLocale); 124 TimeZone.setDefault(reservedTimeZone); 125 } 126 } 127 128 public FormatIteratorTest() { 129 } 130 131 public void testDecimalFormat() { 132 _test(new File(System.getProperty("test.src", "."), 133 "decimalFormat.props")); 134 } 135 136 public void testMessageFormat() { 137 _test(new File(System.getProperty("test.src", "."), 138 "messageFormat.props")); 139 } 140 141 public void testDateFormat() { 142 _test(new File(System.getProperty("test.src", "."), 143 "dateFormat.props")); 144 } 145 146 private void _test(File file) { 147 try { 148 attrs = new HashMap(); 149 logln("testing: " + file); 150 PParser parser = new PParser(); 151 Hashtable contents = parser.parse(new BufferedReader( 152 new FileReader(file))); 153 Vector test = (Vector)contents.get("tests"); 154 155 for (int counter = 0; counter < test.size(); counter++) { 156 logln("creating: " + (counter / 2)); 157 158 AttributedCharacterIterator iterator = 159 create((Hashtable)test.get(counter)); 160 161 logln("verifying: " + (counter / 2)); 162 verify(iterator, (Hashtable)test.get(++counter)); 163 } 164 } catch (IOException ioe) { 165 errln("Error reading: " + ioe); 166 } 167 } 168 169 public void verify(AttributedCharacterIterator iterator,Hashtable table) { 170 int length = Integer.parseInt((String)table.get("length")); 171 172 // Verify the text 173 if (!getText(iterator).equals( 174 escapeIfNecessary((String)table.get("text")))) { 175 String text = getText(iterator); 176 177 errln("text doesn't match, got: " + getText(iterator)); 178 } 179 if (iterator.getBeginIndex() != 0) { 180 errln("Bogus start: " + iterator.getBeginIndex()); 181 } 182 if (iterator.getEndIndex() != length) { 183 errln("Bogus end: " + iterator.getEndIndex()); 184 } 185 for (int counter = 0; counter < length; counter++) { 186 iterator.setIndex(counter); 187 if (!verifyAttributes(iterator.getAttributes().keySet(), 188 makeAttributes((Vector)table.get(Integer. 189 toString(counter))))) { 190 errln("Attributes don't match at " + counter + " expecting " + 191 makeAttributes((Vector)table.get(Integer.toString 192 (counter))) + " got " + 193 iterator.getAttributes().keySet()); 194 } 195 } 196 for (int counter = length - 1; counter >= 0; counter--) { 197 iterator.setIndex(counter); 198 if (!verifyAttributes(iterator.getAttributes().keySet(), 199 makeAttributes((Vector)table.get(Integer. 200 toString(counter))))) { 201 errln("Attributes don't match at " + counter + " expecting " + 202 makeAttributes((Vector)table.get(Integer.toString 203 (counter))) + " got " + 204 iterator.getAttributes().keySet()); 205 } 206 } 207 verifyLimits(iterator, table); 208 209 text = escapeIfNecessary((String)table.get("text")); 210 Vector fps = (Vector)table.get("fieldPositions"); 211 212 if (fps != null) { 213 for (int counter = 0; counter < fps.size(); counter++) { 214 verifyFieldPosition(counter, (Hashtable)fps.get(counter)); 215 } 216 } 217 } 218 219 private void verifyLimits(AttributedCharacterIterator iterator, 220 Hashtable table) { 221 Vector limits = (Vector)table.get("limits"); 222 223 if (limits != null) { 224 for (int counter = 0; counter < limits.size(); counter++) { 225 verifyLimit(iterator, (Hashtable)limits.get(counter)); 226 } 227 } 228 } 229 230 private void verifyLimit(AttributedCharacterIterator iterator, 231 Hashtable table) { 232 int begin = Integer.parseInt((String)table.get("begin")); 233 int end = Integer.parseInt((String)table.get("end")); 234 Set attrs = makeAttributes((Vector)table.get("attributes")); 235 String begin2S = (String)table.get("begin2"); 236 int begin2 = (begin2S != null) ? Integer.parseInt(begin2S) : begin; 237 String end2S = (String)table.get("end2"); 238 int end2 = (end2S != null) ? Integer.parseInt(end2S) : end; 239 240 for (int counter = begin; counter < end; counter++) { 241 iterator.setIndex(counter); 242 if (iterator.getRunStart() != begin) { 243 errln("Begin doesn't match want " + begin + " got " + 244 iterator.getRunStart() + " at " + counter + " attrs " + 245 attrs); 246 } 247 if (iterator.getRunStart(attrs) != begin2) { 248 errln("Begin2 doesn't match want " + begin2 + " got " + 249 iterator.getRunStart(attrs) + " at " + counter + 250 " attrs " + attrs); 251 } 252 if (iterator.getRunLimit() != end) { 253 errln("End doesn't match want " + end + " got " + 254 iterator.getRunLimit() + " at " + counter + " attrs " + 255 attrs); 256 } 257 if (iterator.getRunLimit(attrs) != end2) { 258 errln("End2 doesn't match want " + end2 + " got " + 259 iterator.getRunLimit(attrs) + " at " + counter + 260 " attrs " + attrs); 261 } 262 } 263 } 264 265 private boolean verifyAttributes(Set a, Set b) { 266 boolean aEmpty = (a.size() == 0); 267 boolean bEmpty = (b.size() == 0); 268 269 if (aEmpty && bEmpty) { 270 return true; 271 } 272 else if (aEmpty || bEmpty) { 273 return false; 274 } 275 return a.equals(b); 276 } 277 278 private String getText(AttributedCharacterIterator iterator) { 279 StringBuffer buffer = new StringBuffer(); 280 281 for (int counter = 0; counter < iterator.getEndIndex(); counter++) { 282 buffer.append(iterator.setIndex(counter)); 283 } 284 return buffer.toString(); 285 } 286 287 private void verifyFieldPosition(int index, Hashtable table) { 288 Object o = table.get("field"); 289 int begin = Integer.parseInt((String)table.get("begin")); 290 int end = Integer.parseInt((String)table.get("end")); 291 292 if (o != null) { 293 FieldPosition fp = new FieldPosition(((Integer) 294 lookupField((String)o)).intValue()); 295 296 verifyFieldPosition(fp, begin, end, index); 297 } 298 o = table.get("fieldID"); 299 if (o != null) { 300 FieldPosition fp = new FieldPosition((Format.Field) 301 lookupField((String)o)); 302 verifyFieldPosition(fp, begin, end, index); 303 } 304 } 305 306 private void verifyFieldPosition(FieldPosition fp, int begin, int end, 307 int index) { 308 StringBuffer buffer = new StringBuffer(); 309 310 format.format(value, buffer, fp); 311 if (fp.getBeginIndex() != begin) { 312 errln("bogus begin want " + begin + " got " + fp.getBeginIndex() + 313 " for " + fp + " at " + index); 314 } 315 if (fp.getEndIndex() != end) { 316 errln("bogus end want " + end + " got " + fp.getEndIndex() + 317 " for " + fp + " at " + index); 318 } 319 if (!buffer.toString().equals(text)) { 320 errln("Text does not match, want !" + buffer.toString() + 321 "! got !" + text + "!"); 322 } 323 } 324 325 public AttributedCharacterIterator create(Hashtable table) { 326 format = (Format)createInstance((String)table.get("class"), 327 ((Vector)table.get("args")).toArray()); 328 value = createInstance((String)table.get("valueClass"), 329 ((Vector)table.get("valueArgs")).toArray()); 330 331 logln("Created format: " + format + " value " + value); 332 AttributedCharacterIterator aci = format. 333 formatToCharacterIterator(value); 334 335 logln("Obtained Iterator: " + aci); 336 return aci; 337 } 338 339 public Format.Field makeAttribute(String name) { 340 return (Format.Field)lookupField(name); 341 } 342 343 private Object createInstance(String className, Object[] args) { 344 if (className.equals("java.lang.reflect.Array")) { 345 for (int counter = 0; counter < args.length; counter++) { 346 if (args[counter] instanceof Vector) { 347 Vector v = (Vector)args[counter]; 348 349 args[counter] = createInstance((String)v.get(0), 350 ((Vector)v.get(1)).toArray()); 351 } 352 } 353 return args; 354 } 355 for (int counter = 0; counter < args.length; counter++) { 356 args[counter] = escapeIfNecessary((String)args[counter]); 357 } 358 try { 359 if (className.equals("java.util.concurrent.atomic.AtomicInteger")) { 360 return new AtomicInteger(Integer.valueOf((String)args[0])); 361 } else if (className.equals("java.util.concurrent.atomic.AtomicLong")) { 362 return new AtomicLong(Long.valueOf((String)args[0])); 363 } else { 364 Class klass = lookupClass(className); 365 Constructor cons = klass.getConstructor( 366 new Class[] { String.class }); 367 Object value = cons.newInstance(args); 368 369 return value; 370 } 371 } catch (Throwable th) { 372 errln("Error creating instance " + th); 373 return null; 374 } 375 } 376 377 private Class lookupClass(String name) throws ClassNotFoundException { 378 try { 379 Class klass = Class.forName(name); 380 381 return klass; 382 } catch (ClassNotFoundException e1) {} 383 384 try { 385 Class klass = Class.forName("java.lang." + name); 386 387 return klass; 388 } catch (ClassNotFoundException e1) {} 389 390 Class klass = Class.forName("java.text." + name); 391 392 return klass; 393 } 394 395 private Object lookupField(String name) { 396 Throwable error = null; 397 398 try { 399 int dotIndex = name.indexOf('.'); 400 Class klass = lookupClass(name.substring(0, dotIndex)); 401 String fieldName = name.substring(dotIndex + 1); 402 Field[] fields = klass.getFields(); 403 404 for (int counter = fields.length - 1; counter >= 0; counter--) { 405 if (fields[counter].getName().equals(fieldName)) { 406 return fields[counter].get(null); 407 } 408 } 409 } catch (Throwable th) { 410 error = th; 411 } 412 errln("Could not lookup field " + name + " " + error); 413 return null; 414 } 415 416 protected String escapeIfNecessary(String string) { 417 if (string != null) { 418 int index; 419 420 if ((index = string.indexOf("\\u")) != -1) { 421 StringBuffer sb = new StringBuffer(string.substring(0, index)); 422 423 sb.append((char)Integer.parseInt( 424 string.substring(index + 2, index + 6), 16)); 425 sb.append(string.substring(index + 6)); 426 string = sb.toString(); 427 } 428 } 429 return string; 430 } 431 432 public Set makeAttributes(Vector names) { 433 HashSet set = new HashSet(Math.max(1, names.size())); 434 435 for (int counter = 0; counter < names.size(); counter++) { 436 set.add(makeAttribute((String)names.get(counter))); 437 } 438 return set; 439 } 440 }