001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Alexey A. Ivanov
019: * @version $Revision$
020: */package javax.swing.text;
021:
022: import java.awt.Color;
023: import java.awt.Font;
024: import java.lang.reflect.Field;
025: import java.util.Enumeration;
026: import java.util.Map;
027: import javax.swing.BasicSwingTestCase;
028: import javax.swing.event.ChangeEvent;
029: import javax.swing.event.ChangeListener;
030: import javax.swing.text.StyleContext.SmallAttributeSet;
031: import junit.framework.TestCase;
032:
033: public class StyleContextTest extends TestCase implements
034: ChangeListener {
035: /**
036: * Shared style context object
037: */
038: protected static StyleContext sc;
039:
040: /**
041: * The array of attribute key-value pair that is shared in the tests.
042: */
043: protected static final Object[] attr = { StyleConstants.Bold,
044: Boolean.TRUE, StyleConstants.Italic, Boolean.TRUE,
045: StyleConstants.Underline, Boolean.TRUE,
046: StyleConstants.StrikeThrough, Boolean.TRUE,
047: StyleConstants.Alignment, new Integer(1),
048: StyleConstants.Background, Color.WHITE,
049: StyleConstants.FirstLineIndent, new Float(0.75),
050: StyleConstants.FontFamily, new String("monospaced"),
051: StyleConstants.FontSize, new Integer(10),
052: StyleConstants.Foreground, Color.BLACK };
053:
054: /**
055: * Tracks that a change listener was been called.
056: */
057: private boolean bStateChanged;
058:
059: /**
060: * Adds some attributes from <code>attr</code> array.
061: *
062: * @param as old attribute set to add to, may be null
063: * @param start index of the first attribute in the array
064: * @param count the number of attributes to add
065: * @return new attribute set with attributes added
066: */
067: protected static AttributeSet addAttribute(AttributeSet as,
068: int start, int count) {
069: if (as == null) {
070: as = sc.getEmptySet();
071: }
072: start <<= 1;
073: count <<= 1;
074: count += start;
075: for (int i = start; i < count; i += 2) {
076: as = sc.addAttribute(as, attr[i], attr[i + 1]);
077: }
078: return as;
079: }
080:
081: /**
082: * Adds some attributes from <code>attr</code> array, starting at index 0.
083: *
084: * @param as old attribute set to add to, may be null
085: * @param count the number of attributes to add
086: * @return new attribute set with attributes added
087: * @see StyleContextTest#addAttribute(AttributeSet, int, int)
088: */
089: protected static AttributeSet addAttribute(final AttributeSet as,
090: final int count) {
091: return addAttribute(as, 0, count);
092: }
093:
094: /**
095: * Adds <code>count</code> attributes to a newly created attribute set
096: * from <code>attr</code> array, starting at index 0.
097: *
098: * @param count the number of attributes to add
099: * @return new attribute set with attributes added
100: * @see StyleContextTest#addAttribute(AttributeSet, int, int)
101: */
102: protected static AttributeSet addAttribute(final int count) {
103: return addAttribute(null, 0, count);
104: }
105:
106: /**
107: * Wrapper to access StyleContext.cache field.
108: * @return style context's cache
109: */
110: protected static Map<?, ?> getSCCache() {
111: try {
112: Field f = sc.getClass().getDeclaredField("cache");
113: f.setAccessible(true);
114: return (Map<?, ?>) (f.get(sc));
115: } catch (IllegalAccessException e) {
116: fail(e.getMessage());
117: } catch (NoSuchFieldException e) {
118: fail(e.getMessage());
119: }
120: return null;
121: }
122:
123: /**
124: * Wrapper to access StyleContext.fontCache field.
125: * @return style context's cache
126: */
127: protected static Map<?, ?> getSCFontCache() {
128: try {
129: Field f = sc.getClass().getDeclaredField("fontCache");
130: f.setAccessible(true);
131: return (Map<?, ?>) (f.get(sc));
132: } catch (IllegalAccessException e) {
133: fail(e.getMessage());
134: } catch (NoSuchFieldException e) {
135: fail(e.getMessage());
136: }
137: return null;
138: }
139:
140: /*
141: * @see TestCase#setUp()
142: */
143: @Override
144: protected void setUp() throws Exception {
145: sc = new StyleContext();
146: }
147:
148: /**
149: * Makes sure that after initialization, any style context will
150: * contain exactly one style (default).
151: */
152: public void testStyleContext() {
153: int count = 0;
154: Enumeration<?> names = sc.getStyleNames();
155: Object name = null;
156: while (names.hasMoreElements()) {
157: name = names.nextElement();
158: count++;
159: }
160: assertEquals(1, count);
161: assertEquals("default", (String) name);
162: }
163:
164: public void testCollectGarbageInCache() {
165: if (!BasicSwingTestCase.isHarmony()) {
166: // This is internal test only
167: return;
168: }
169: Map<?, ?> cache = getSCCache();
170: assertEquals(2, cache.size());
171: // Create an attribute set containing 10 items. This will
172: // create sets with items from 1 to 10
173: addAttribute(10);
174: // The sets with number of items from 1 up to 9 will be cached
175: // (Plus attribute set to support styles: the named style itself
176: // with "name" attribute and the reference to this style from
177: // the internal list of styles)
178: assertEquals(9 + 2, cache.size());
179: // Run the garbage collector several times
180: for (int i = 0; i < 20; i++) {
181: System.gc();
182: }
183: // Create an attribute set cotaining one and only item. This will
184: // lead to a call to collectGarbageInCache method
185: addAttribute(1);
186: // The cache has been cleared but the newly created set is cached
187: assertEquals(1 + 2, cache.size());
188: }
189:
190: public void testCollectGarbageInCacheFont() {
191: if (!BasicSwingTestCase.isHarmony()) {
192: // This is internal test only
193: return;
194: }
195: Map<?, ?> fontCache = getSCFontCache();
196: assertEquals(0, fontCache.size());
197: sc.getFont("Arial", Font.BOLD, 14);
198: sc.getFont("Tahoma", Font.PLAIN, 8);
199: assertEquals(2, fontCache.size());
200: // Run the garbage collector several times
201: for (int i = 0; i < 5; i++) {
202: System.gc();
203: }
204: // Create an attribute set cotaining one and only item. This will
205: // lead to a call to collectGarbageInCache method
206: addAttribute(1);
207: // The cache has been cleared but the newly created set is cached
208: assertEquals(0, fontCache.size());
209: }
210:
211: public void testAddStyle() {
212: Style aStyle = sc.addStyle("aStyle", null);
213: Style anotherStyle = sc.addStyle("anotherStyle", aStyle);
214: int count = 0;
215: boolean[] was = { false, false, false };
216: String styleNames = new String();
217: Enumeration<?> names = sc.getStyleNames();
218: while (names.hasMoreElements()) {
219: String name = (String) names.nextElement();
220: styleNames += name + " ";
221: if (name == "aStyle") {
222: assertSame(aStyle, sc.getStyle(name));
223: // Should contain only "name" attribute
224: assertEquals(1, aStyle.getAttributeCount());
225: assertNull(aStyle.getResolveParent());
226: was[0] = true;
227: } else if (name == "anotherStyle") {
228: assertSame(anotherStyle, sc.getStyle(name));
229: // Should contain "name" and "parent" attributes
230: assertEquals(2, anotherStyle.getAttributeCount());
231: assertNotNull(anotherStyle.getResolveParent());
232: assertSame(aStyle, anotherStyle.getResolveParent());
233: was[1] = true;
234: } else if (name == "default") {
235: sc.getStyle(name);
236: assertEquals(1, aStyle.getAttributeCount());
237: assertNull(aStyle.getResolveParent());
238: was[2] = true;
239: }
240: count++;
241: }
242: assertEquals(3, count);
243: for (int i = 0; i < was.length; i++) {
244: assertTrue("The style named '"
245: + (i == 0 ? "aStyle" : (i == 1 ? "anotherStyle"
246: : "default")) + "' was not in the list.",
247: was[i]);
248: }
249: }
250:
251: public void testAddStyleMisc() {
252: // Add styles with diff parameters
253: Object[] styles = { null, null, "one", null, null,
254: sc.new NamedStyle(), "two", sc.new NamedStyle() };
255: for (int i = 0; i < styles.length; i += 2) {
256: Style style = sc.addStyle((String) styles[i],
257: (Style) styles[i + 1]);
258: assertEquals("Iteration: " + i, (String) styles[i], style
259: .getName());
260: assertSame("Iteration: " + i, styles[i + 1], style
261: .getResolveParent());
262: }
263: }
264:
265: public void testAddStyleTwice() {
266: final String styleName = "styleName";
267: final Style style = sc.addStyle(styleName, null);
268: final Style another = sc.addStyle(styleName, null);
269: assertNotSame(style, another);
270: assertSame(another, sc.getStyle(styleName));
271: }
272:
273: public void testCreateSmallAttributeSet() {
274: AttributeSet as = sc.createSmallAttributeSet(sc.getEmptySet());
275: assertTrue(as instanceof SmallAttributeSet);
276: assertEquals(0, as.getAttributeCount());
277: assertEquals(sc.getEmptySet(), as);
278: }
279:
280: public void testGetStyle() {
281: Style style = sc.getStyle("default");
282: assertEquals("default", style.getName());
283: sc.addStyle("aStyle", style);
284: style = sc.getStyle("aStyle");
285: assertEquals("aStyle", style.getName());
286: assertEquals("default", ((Style) style.getResolveParent())
287: .getName());
288: }
289:
290: public void testCreateLargeAttributeSet() {
291: AttributeSet as = sc
292: .createLargeAttributeSet(new SimpleAttributeSet());
293: assertTrue(as instanceof SimpleAttributeSet);
294: }
295:
296: public void testGetEmptySet() {
297: assertSame(sc.getEmptySet(), sc.getEmptySet());
298: assertEquals(0, sc.getEmptySet().getAttributeCount());
299: }
300:
301: // test {add,remove}ChangeListener while adding styles
302: public void testChangeListenerAddStyle() {
303: bStateChanged = false;
304: sc.addStyle("one", null);
305: assertFalse(bStateChanged);
306: sc.addChangeListener(this );
307: bStateChanged = false;
308: sc.addStyle("two", null);
309: assertTrue(bStateChanged);
310: sc.removeChangeListener(this );
311: bStateChanged = false;
312: sc.addStyle("three", null);
313: assertFalse(bStateChanged);
314: }
315:
316: // test if a listener gets called when adding style with null name
317: public void testChangeListenerAddStyleNull() {
318: sc.addChangeListener(this );
319: bStateChanged = false;
320: sc.addStyle(null,
321: StyleContext.getDefaultStyleContext().new NamedStyle());
322: assertFalse(bStateChanged);
323: int count = 0;
324: boolean wasNull = false;
325: Enumeration<?> names = sc.getStyleNames();
326: while (names.hasMoreElements()) {
327: Object name = names.nextElement();
328: wasNull = wasNull || name == null;
329: count++;
330: }
331: assertEquals(1, count);
332: assertFalse(wasNull);
333: }
334:
335: // test {add,remove}ChangeListener while removing styles
336: public void testChangeListenerRemoveStyle() {
337: sc.addStyle("one", null);
338: sc.addStyle("two", null);
339: sc.addStyle("three", null);
340: bStateChanged = false;
341: sc.removeStyle("one");
342: assertFalse(bStateChanged);
343: sc.addChangeListener(this );
344: bStateChanged = false;
345: sc.removeStyle("two");
346: assertTrue(bStateChanged);
347: sc.removeChangeListener(this );
348: bStateChanged = false;
349: sc.removeStyle("three");
350: assertFalse(bStateChanged);
351: }
352:
353: public void testGetChangeListeners() {
354: ChangeListener[] listeners = sc.getChangeListeners();
355: assertEquals(0, listeners.length);
356: sc.addChangeListener(this );
357: listeners = sc.getChangeListeners();
358: assertEquals(1, listeners.length);
359: sc.removeChangeListener(this );
360: listeners = sc.getChangeListeners();
361: assertEquals(0, listeners.length);
362: }
363:
364: public void testGetStyleNamesDef() {
365: boolean wasDefault = false;
366: int count = 0;
367: Enumeration<?> names = sc.getStyleNames();
368: while (names.hasMoreElements()) {
369: String name = (String) names.nextElement();
370: wasDefault = name == "default";
371: count++;
372: }
373: assertEquals(1, count);
374: assertTrue(wasDefault);
375: }
376:
377: public void testGetStyleNames() {
378: sc.addStyle("style", null);
379: boolean wasDefault = false;
380: boolean wasStyle = false;
381: int count = 0;
382: Enumeration<?> names = sc.getStyleNames();
383: while (names.hasMoreElements()) {
384: String name = (String) names.nextElement();
385: wasDefault = wasDefault || name == "default";
386: wasStyle = wasStyle || name == "style";
387: count++;
388: }
389: assertEquals(2, count);
390: assertTrue(wasDefault);
391: assertTrue(wasStyle);
392: }
393:
394: public void testRemoveStyle() {
395: sc.addStyle("style", null);
396: sc.removeStyle("style");
397: boolean wasDefault = false;
398: boolean wasStyle = false;
399: int count = 0;
400: Enumeration<?> names = sc.getStyleNames();
401: while (names.hasMoreElements()) {
402: String name = (String) names.nextElement();
403: wasDefault = wasDefault || "default".equals(name);
404: wasStyle = wasStyle || "style".equals(name);
405: count++;
406: }
407: assertEquals(1, count);
408: assertTrue(wasDefault);
409: assertFalse(wasStyle);
410: }
411:
412: public void testToString() {
413: Style style = sc.getStyle(StyleContext.DEFAULT_STYLE);
414: style.addAttribute(StyleConstants.Bold, Boolean.TRUE);
415: style.addAttribute(StyleConstants.Italic, Boolean.FALSE);
416: style = sc.addStyle("aStyle", null);
417: style.addAttribute(StyleConstants.FontFamily, "Arial");
418: style.addAttribute(StyleConstants.FontSize, new Integer(14));
419: sc.getFont(style);
420: String[] asStr = new String[] {
421: "{family=Arial,name=aStyle,size=14,}",
422: "{default=AttributeSet,}",
423: "{family=Arial,name=aStyle,}",
424: "{aStyle=AttributeSet,default=AttributeSet,}",
425: "{italic=false,bold=true,name=default,}",
426: "{name=default,}", "{name=aStyle,}",
427: "{name=default,bold=true,}", };
428: String scStr = sc.toString();
429: assertNotNull(scStr);
430: String[] splitStrs = scStr.replaceAll("\r", "").split("\n");
431: assertEquals(asStr.length, splitStrs.length);
432: boolean[] met = new boolean[splitStrs.length];
433: for (int i = 0; i < splitStrs.length; i++) {
434: for (int j = 0; j < asStr.length; j++) {
435: if (asStr[j].length() == splitStrs[i].length()
436: && assertAttributes(trimEnds(asStr[j]).split(
437: ","), trimEnds(splitStrs[i]).split(","))) {
438: met[j] = true;
439: }
440: }
441: }
442: for (int i = 0; i < met.length; i++) {
443: assertTrue("asStr[" + i + "] is missing", met[i]);
444: }
445: }
446:
447: public static boolean assertAttributes(final String[] expAttrs,
448: final String[] realAttrs) {
449: if (expAttrs.length != realAttrs.length) {
450: return false;
451: }
452: boolean[] met = new boolean[expAttrs.length];
453: for (int i = 0; i < realAttrs.length; i++) {
454: for (int j = 0; j < expAttrs.length; j++) {
455: if (expAttrs[j].equals(realAttrs[i])) {
456: met[j] = true;
457: }
458: }
459: }
460: boolean result = true;
461: for (int i = 0; i < met.length && result; i++) {
462: result = met[i];
463: }
464: return result;
465: }
466:
467: public static String trimEnds(final String str) {
468: assertEquals('{', str.charAt(0));
469: final int len = str.length();
470: assertEquals('}', str.charAt(len - 1));
471: assertEquals(',', str.charAt(len - 2));
472: return str.substring(1, len - 2);
473: }
474:
475: public void testGetCompressionThreshold() {
476: assertEquals(9, sc.getCompressionThreshold());
477: }
478:
479: public void testGetDefaultStyleContext() {
480: StyleContext def;
481: assertSame(def = StyleContext.getDefaultStyleContext(),
482: StyleContext.getDefaultStyleContext());
483: int count = 0;
484: Enumeration<?> names = def.getStyleNames();
485: Object name = null;
486: while (names.hasMoreElements()) {
487: count++;
488: name = names.nextElement();
489: }
490: assertEquals(1, count);
491: assertEquals(StyleContext.DEFAULT_STYLE, (String) name);
492: }
493:
494: /**
495: * A class to test caching technique.
496: * Stores values returned by createSmallAttributeSet in array.
497: */
498: private static class StyleContextX extends StyleContext {
499: private static final long serialVersionUID = 1L;
500:
501: public int count;
502:
503: public AttributeSet[] attrSet;
504:
505: public StyleContextX() {
506: count = 0;
507: attrSet = new AttributeSet[20];
508: }
509:
510: @Override
511: public SmallAttributeSet createSmallAttributeSet(
512: final AttributeSet a) {
513: if (attrSet == null) {
514: // This condition is true in StyleContext's constructor
515: return super .createSmallAttributeSet(a);
516: }
517: attrSet[count] = super .createSmallAttributeSet(a);
518: return (SmallAttributeSet) attrSet[count++];
519: }
520:
521: @Override
522: public MutableAttributeSet createLargeAttributeSet(
523: final AttributeSet a) {
524: attrSet[count] = super .createLargeAttributeSet(a);
525: return (MutableAttributeSet) attrSet[count++];
526: }
527: }
528:
529: public void testCaching() {
530: StyleContextX sc = new StyleContextX();
531: int addStyle = sc.count;
532: sc.addStyle("aStyle", null);
533: int addAttr = sc.count;
534: AttributeSet as = sc.addAttribute(sc.getEmptySet(),
535: AttributeSet.NameAttribute, "aStyle");
536: assertFalse(addStyle == addAttr);
537: assertSame(sc.attrSet[addStyle], as);
538: }
539:
540: /*
541: public void testReclaim() {
542: }
543: */
544: public void stateChanged(final ChangeEvent event) {
545: bStateChanged = true;
546: }
547: }
|