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