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