1 /*
2  * Copyright (c) 1998, 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 /* @test
25  * @bug 4139771
26  * @summary test all aspects of AttributedString class
27  */
28 
29 package test.java.text.AttributedString;
30 
31 import java.text.Annotation;
32 import java.text.AttributedCharacterIterator;
33 import java.text.AttributedCharacterIterator.Attribute;
34 import java.text.AttributedString;
35 import java.text.CharacterIterator;
36 import java.util.HashSet;
37 import java.util.Iterator;
38 import java.util.Locale;
39 import java.util.Map;
40 import java.util.Map.Entry;
41 import java.util.Set;
42 
43 
44 public class AttributedStringTest {
45 
46     private static final String text = "Hello, world!";
47     private static final Annotation hi = new Annotation("hi");
48     private static final int[] array5_13 = {5, 13};
49     private static final int[] array3_9_13 = {3, 9, 13};
50     private static final int[] array5_9_13 = {5, 9, 13};
51     private static final int[] array3_5_9_13 = {3, 5, 9, 13};
52     private static final Attribute[] arrayLanguage = {Attribute.LANGUAGE};
53     private static final Attribute[] arrayLanguageReading = {Attribute.LANGUAGE, Attribute.READING};
54     private static final Set setLanguageReading = new HashSet();
55     static {
56         setLanguageReading.add(Attribute.LANGUAGE);
57         setLanguageReading.add(Attribute.READING);
58     }
59 
60 
main(String argv[])61     public static final void main(String argv[]) throws Exception {
62 
63 
64         AttributedString string;
65         AttributedCharacterIterator iterator;
66 
67         // create a string with text, but no attributes
68         string = new AttributedString(text);
69         iterator = string.getIterator();
70 
71         // make sure the text is there and attributes aren't
72         checkIteratorText(iterator, text);
73         if (!iterator.getAllAttributeKeys().isEmpty()) {
74             throwException(iterator, "iterator provides attributes where none are defined");
75         }
76 
77         // add an attribute to a subrange
78         string.addAttribute(Attribute.LANGUAGE, Locale.ENGLISH, 3, 9);
79         iterator = string.getIterator();
80 
81         // make sure the attribute is defined, and it's on the correct subrange
82         checkIteratorAttributeKeys(iterator, arrayLanguage);
83         checkIteratorSubranges(iterator, array3_9_13);
84         checkIteratorAttribute(iterator, 0, Attribute.LANGUAGE, null);
85         checkIteratorAttribute(iterator, 3, Attribute.LANGUAGE, Locale.ENGLISH);
86         checkIteratorAttribute(iterator, 9, Attribute.LANGUAGE, null);
87 
88         // add an attribute to a subrange
89         string.addAttribute(Attribute.READING, hi, 0, 5);
90         iterator = string.getIterator();
91 
92         // make sure the attribute is defined, and it's on the correct subrange
93         checkIteratorAttributeKeys(iterator, arrayLanguageReading);
94         checkIteratorSubranges(iterator, array3_5_9_13);
95         checkIteratorAttribute(iterator, 0, Attribute.READING, hi);
96         checkIteratorAttribute(iterator, 3, Attribute.READING, hi);
97         checkIteratorAttribute(iterator, 5, Attribute.READING, null);
98         checkIteratorAttribute(iterator, 9, Attribute.READING, null);
99 
100         // make sure the first attribute wasn't adversely affected
101         // in particular, we shouldn't see separate subranges (3,5) and (5,9).
102         checkIteratorSubranges(iterator, Attribute.LANGUAGE, array3_9_13);
103         checkIteratorAttribute(iterator, 0, Attribute.LANGUAGE, null);
104         checkIteratorAttribute(iterator, 3, Attribute.LANGUAGE, Locale.ENGLISH);
105         checkIteratorAttribute(iterator, 5, Attribute.LANGUAGE, Locale.ENGLISH);
106         checkIteratorAttribute(iterator, 9, Attribute.LANGUAGE, null);
107 
108         // for the entire set of attributes, we expect four subranges
109         checkIteratorSubranges(iterator, setLanguageReading, array3_5_9_13);
110 
111         // redefine the language attribute so that both language and reading are continuous from 0 to 5
112         string.addAttribute(Attribute.LANGUAGE, Locale.US, 0, 5);
113         iterator = string.getIterator();
114 
115         // make sure attributes got changed and merged correctly
116         checkIteratorAttributeKeys(iterator, arrayLanguageReading);
117         checkIteratorSubranges(iterator, array3_5_9_13);
118         checkIteratorSubranges(iterator, Attribute.LANGUAGE, array5_9_13);
119         checkIteratorSubranges(iterator, Attribute.READING, array5_13);
120         checkIteratorSubranges(iterator, setLanguageReading, array5_9_13);
121         checkIteratorAttribute(iterator, 0, Attribute.LANGUAGE, Locale.US);
122         checkIteratorAttribute(iterator, 3, Attribute.LANGUAGE, Locale.US);
123         checkIteratorAttribute(iterator, 5, Attribute.LANGUAGE, Locale.ENGLISH);
124         checkIteratorAttribute(iterator, 9, Attribute.LANGUAGE, null);
125 
126         // make sure an annotation is only returned if its range is contained in the iterator's range
127         iterator = string.getIterator(null, 3, 5);
128         checkIteratorAttribute(iterator, 3, Attribute.READING, null);
129         checkIteratorAttribute(iterator, 5, Attribute.READING, null);
130         iterator = string.getIterator(null, 0, 4);
131         checkIteratorAttribute(iterator, 0, Attribute.READING, null);
132         checkIteratorAttribute(iterator, 3, Attribute.READING, null);
133         iterator = string.getIterator(null, 0, 5);
134         checkIteratorAttribute(iterator, 0, Attribute.READING, hi);
135         checkIteratorAttribute(iterator, 4, Attribute.READING, hi);
136         checkIteratorAttribute(iterator, 5, Attribute.READING, null);
137 
138     }
139 
checkIteratorText(AttributedCharacterIterator iterator, String expectedText)140     private static final void checkIteratorText(AttributedCharacterIterator iterator, String expectedText) throws Exception {
141         if (iterator.getEndIndex() - iterator.getBeginIndex() != expectedText.length()) {
142             throwException(iterator, "text length doesn't match between original text and iterator");
143         }
144 
145         char c = iterator.first();
146         for (int i = 0; i < expectedText.length(); i++) {
147             if (c != expectedText.charAt(i)) {
148                 throwException(iterator, "text content doesn't match between original text and iterator");
149             }
150             c = iterator.next();
151         }
152         if (c != CharacterIterator.DONE) {
153             throwException(iterator, "iterator text doesn't end with DONE");
154         }
155     }
156 
checkIteratorAttributeKeys(AttributedCharacterIterator iterator, Attribute[] expectedKeys)157     private static final void checkIteratorAttributeKeys(AttributedCharacterIterator iterator, Attribute[] expectedKeys) throws Exception {
158          Set iteratorKeys = iterator.getAllAttributeKeys();
159          if (iteratorKeys.size() != expectedKeys.length) {
160              throwException(iterator, "number of keys returned by iterator doesn't match expectation");
161          }
162          for (int i = 0; i < expectedKeys.length; i++) {
163              if (!iteratorKeys.contains(expectedKeys[i])) {
164                  throwException(iterator, "expected key wasn't found in iterator's key set");
165              }
166          }
167     }
168 
checkIteratorSubranges(AttributedCharacterIterator iterator, int[] expectedLimits)169     private static final void checkIteratorSubranges(AttributedCharacterIterator iterator, int[] expectedLimits) throws Exception {
170         int previous = 0;
171         char c = iterator.first();
172         for (int i = 0; i < expectedLimits.length; i++) {
173              if (iterator.getRunStart() != previous || iterator.getRunLimit() != expectedLimits[i]) {
174                  throwException(iterator, "run boundaries are not as expected: " + iterator.getRunStart() + ", " + iterator.getRunLimit());
175              }
176              previous = expectedLimits[i];
177              c = iterator.setIndex(previous);
178         }
179         if (c != CharacterIterator.DONE) {
180             throwException(iterator, "iterator's run sequence doesn't end with DONE");
181         }
182     }
183 
checkIteratorSubranges(AttributedCharacterIterator iterator, Attribute key, int[] expectedLimits)184     private static final void checkIteratorSubranges(AttributedCharacterIterator iterator, Attribute key, int[] expectedLimits) throws Exception {
185         int previous = 0;
186         char c = iterator.first();
187         for (int i = 0; i < expectedLimits.length; i++) {
188              if (iterator.getRunStart(key) != previous || iterator.getRunLimit(key) != expectedLimits[i]) {
189                  throwException(iterator, "run boundaries are not as expected: " + iterator.getRunStart(key) + ", " + iterator.getRunLimit(key) + " for key " + key);
190              }
191              previous = expectedLimits[i];
192              c = iterator.setIndex(previous);
193         }
194         if (c != CharacterIterator.DONE) {
195             throwException(iterator, "iterator's run sequence doesn't end with DONE");
196         }
197     }
198 
checkIteratorSubranges(AttributedCharacterIterator iterator, Set keys, int[] expectedLimits)199     private static final void checkIteratorSubranges(AttributedCharacterIterator iterator, Set keys, int[] expectedLimits) throws Exception {
200         int previous = 0;
201         char c = iterator.first();
202         for (int i = 0; i < expectedLimits.length; i++) {
203              if (iterator.getRunStart(keys) != previous || iterator.getRunLimit(keys) != expectedLimits[i]) {
204                  throwException(iterator, "run boundaries are not as expected: " + iterator.getRunStart(keys) + ", " + iterator.getRunLimit(keys) + " for keys " + keys);
205              }
206              previous = expectedLimits[i];
207              c = iterator.setIndex(previous);
208         }
209         if (c != CharacterIterator.DONE) {
210             throwException(iterator, "iterator's run sequence doesn't end with DONE");
211         }
212     }
213 
checkIteratorAttribute(AttributedCharacterIterator iterator, int index, Attribute key, Object expectedValue)214     private static final void checkIteratorAttribute(AttributedCharacterIterator iterator, int index, Attribute key, Object expectedValue) throws Exception {
215         iterator.setIndex(index);
216         Object value = iterator.getAttribute(key);
217         if (!((expectedValue == null && value == null) || (expectedValue != null && expectedValue.equals(value)))) {
218             throwException(iterator, "iterator returns wrong attribute value - " + value + " instead of " + expectedValue);
219         }
220         value = iterator.getAttributes().get(key);
221         if (!((expectedValue == null && value == null) || (expectedValue != null && expectedValue.equals(value)))) {
222             throwException(iterator, "iterator's map returns wrong attribute value - " + value + " instead of " + expectedValue);
223         }
224     }
225 
throwException(AttributedCharacterIterator iterator, String details)226     private static final void throwException(AttributedCharacterIterator iterator, String details) throws Exception {
227         dumpIterator(iterator);
228         throw new Exception(details);
229     }
230 
dumpIterator(AttributedCharacterIterator iterator)231     private static final void dumpIterator(AttributedCharacterIterator iterator) {
232         Set attributeKeys = iterator.getAllAttributeKeys();
233         System.out.print("All attributes: ");
234         Iterator keyIterator = attributeKeys.iterator();
235         while (keyIterator.hasNext()) {
236             Attribute key = (Attribute) keyIterator.next();
237             System.out.print(key);
238         }
239         for(char c = iterator.first(); c != CharacterIterator.DONE; c = iterator.next()) {
240             if (iterator.getIndex() == iterator.getBeginIndex() ||
241                         iterator.getIndex() == iterator.getRunStart()) {
242                 System.out.println();
243                 Map attributes = iterator.getAttributes();
244                 Set entries = attributes.entrySet();
245                 Iterator attributeIterator = entries.iterator();
246                 while (attributeIterator.hasNext()) {
247                     Map.Entry entry = (Map.Entry) attributeIterator.next();
248                     System.out.print("<" + entry.getKey() + ": "
249                                 + entry.getValue() + ">");
250                 }
251             }
252             System.out.print(" ");
253             System.out.print(c);
254         }
255         System.out.println();
256         System.out.println("done");
257         System.out.println();
258     }
259 
260 }
261