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.lang.reflect.Field;
023: import java.util.List;
024: import java.util.Vector;
025: import javax.swing.event.DocumentEvent.ElementChange;
026: import javax.swing.text.AbstractDocument.DefaultDocumentEvent;
027: import javax.swing.text.DefaultStyledDocument.ElementSpec;
028: import junit.framework.Assert;
029:
030: /**
031: * Contains "complex" <code>assert</code> methods as well as logging versions
032: * of <code>DefaultStyledDocument</code> and
033: * <code>DefaultStyledDocument.ElementBuffer</code> which facilitate testing
034: * and debugging.
035: *
036: */
037: public final class DefStyledDoc_Helpers extends Assert {
038: public static boolean logging = false;
039:
040: /**
041: * The version of <code>DefaultStyledDocument</code> which logs parameters
042: * passed to some methods to <code>stdout</code>.
043: */
044: public static class DefStyledDocWithLogging extends
045: DefaultStyledDocument {
046: private static final long serialVersionUID = 1L;
047:
048: public DefStyledDocWithLogging() {
049: super ();
050: }
051:
052: public DefStyledDocWithLogging(final Content content) {
053: super (content, new StyleContext());
054: }
055:
056: @Override
057: public void insertString(int offset, String text,
058: AttributeSet attrs) throws BadLocationException {
059: if (logging) {
060: System.out.println(">>>doc.insertString(" + offset
061: + ", '" + text + "', " + attrs + ")");
062: }
063: super .insertString(offset, text, attrs);
064: if (logging) {
065: System.out.println("<<<doc.insertString");
066: }
067: }
068:
069: @Override
070: public void remove(int offset, int length)
071: throws BadLocationException {
072: if (logging) {
073: System.out.println(">>>doc.remove(" + offset + ", "
074: + length + ")");
075: }
076: super .remove(offset, length);
077: if (logging) {
078: System.out.println("<<<doc.remove");
079: }
080: }
081:
082: @Override
083: protected void create(ElementSpec[] spec) {
084: if (logging) {
085: System.out.println(">>>doc.create");
086: printElementSpecs(spec);
087: }
088: super .create(spec);
089: if (logging) {
090: System.out.println("<<<doc.create");
091: }
092: }
093:
094: @Override
095: protected void insert(int offset, ElementSpec[] spec)
096: throws BadLocationException {
097: if (logging) {
098: System.out.println(">>>doc.insert(" + offset + ", "
099: + ")");
100: printElementSpecs(spec);
101: }
102: super .insert(offset, spec);
103: if (logging) {
104: System.out.println("<<<doc.insert");
105: }
106: }
107:
108: @Override
109: protected void insertUpdate(DefaultDocumentEvent event,
110: AttributeSet attrs) {
111: if (logging) {
112: System.out.println(">>>doc.insertUpdate(" + ", "
113: + attrs + ")");
114: }
115: super .insertUpdate(event, attrs);
116: if (logging) {
117: System.out.println("<<<doc.insertUpdate");
118: }
119: }
120:
121: @Override
122: protected void removeUpdate(DefaultDocumentEvent event) {
123: if (logging) {
124: System.out.println(">>>doc.removeUpdate");
125: }
126: super .removeUpdate(event);
127: if (logging) {
128: System.out.println("<<<doc.removeUpdate");
129: }
130: }
131:
132: @Override
133: protected void styleChanged(Style style) {
134: if (logging) {
135: System.out.println(">>>styleChanged(" + style + ")");
136: }
137: super .styleChanged(style);
138: if (logging) {
139: System.out.println("<<<styleChanged(" + style + ")");
140: }
141: }
142:
143: @Override
144: protected Element createBranchElement(Element parent,
145: AttributeSet as) {
146: if (logging) {
147: System.out
148: .println("createBranch("
149: + parent.getName()
150: + "["
151: + (parent.getElementCount() <= 0 ? "N/A"
152: : (parent.getStartOffset()
153: + ", " + parent
154: .getEndOffset()))
155: + "], "
156: + (as == null ? "null"
157: : new SimpleAttributeSet(as)
158: .toString()) + ")");
159: }
160: return super .createBranchElement(parent, as);
161: }
162:
163: @Override
164: protected Element createLeafElement(Element parent,
165: AttributeSet as, int start, int end) {
166: if (logging) {
167: System.out
168: .println("createLeaf("
169: + parent.getName()
170: + "["
171: + (parent.getElementCount() <= 0 ? "N/A"
172: : (parent.getStartOffset()
173: + ", " + parent
174: .getEndOffset()))
175: + "], "
176: + (as == null ? "null"
177: : new SimpleAttributeSet(as)
178: .toString()) + ", "
179: + start + ", " + end + ")");
180: }
181: return super .createLeafElement(parent, as, start, end);
182: }
183: }
184:
185: /**
186: * The version of <code>DefaultStyledDocument.ElementBuffer</code>
187: * which logs parameters passed to some methods to <code>stdout</code>.
188: */
189: public static class ElementBufferWithLogging extends
190: DefaultStyledDocument.ElementBuffer {
191: private static final long serialVersionUID = 1L;
192:
193: public ElementBufferWithLogging(
194: final DefaultStyledDocument doc, final Element root) {
195: doc.super (root);
196: }
197:
198: @Override
199: public void change(int offset, int length,
200: DefaultDocumentEvent event) {
201: if (logging) {
202: System.out.println("->buf.change(" + offset + ", "
203: + length + ", \n\t" + event + ")");
204: }
205: super .change(offset, length, event);
206: if (logging) {
207: System.out.println("<-buf.change");
208: }
209: }
210:
211: @Override
212: protected void changeUpdate() {
213: if (logging) {
214: System.out.println("->buf.changeUpdate");
215: }
216: super .changeUpdate();
217: if (logging) {
218: System.out.println("<-buf.changeUpdate");
219: }
220: }
221:
222: @Override
223: public Element clone(Element parent, Element clonee) {
224: if (logging) {
225: System.out
226: .println("clone("
227: + parent.getName()
228: + "["
229: + (parent.getElementCount() <= 0 ? "N/A"
230: : (parent.getStartOffset()
231: + ", " + parent
232: .getEndOffset()))
233: + "], "
234: + ", "
235: + clonee.getName()
236: + "["
237: + (!clonee.isLeaf()
238: && clonee.getElementCount() <= 0 ? "N/A"
239: : (clonee.getStartOffset()
240: + ", " + clonee
241: .getEndOffset()))
242: + "])");
243: }
244: return super .clone(parent, clonee);
245: }
246:
247: @Override
248: public void insert(int offset, int length, ElementSpec[] spec,
249: DefaultDocumentEvent event) {
250: if (logging) {
251: System.out.println("->buf.insert(" + offset + ", "
252: + length + ", " + ", " + ")");
253: printElementSpecs(spec);
254: System.out.println(event);
255: }
256: super .insert(offset, length, spec, event);
257: if (logging) {
258: System.out.println(event);
259: System.out.println("<-buf.insert");
260: }
261: }
262:
263: @Override
264: protected void insertUpdate(ElementSpec[] spec) {
265: if (logging) {
266: System.out.println("->buf.insertUpdate");
267: printElementSpecs(spec);
268: }
269: super .insertUpdate(spec);
270: if (logging) {
271: System.out.println("<-buf.insertUpdate");
272: }
273: }
274:
275: @Override
276: public void remove(int offset, int length,
277: DefaultDocumentEvent event) {
278: if (logging) {
279: System.out.println("->buf.remove(" + offset + ", "
280: + length + ")");
281: }
282: super .remove(offset, length, event);
283: if (logging) {
284: System.out.println("<-buf.remove");
285: }
286: }
287:
288: @Override
289: protected void removeUpdate() {
290: if (logging) {
291: System.out.println("->buf.removeUpdate");
292: }
293: super .removeUpdate();
294: if (logging) {
295: System.out.println("<-buf.removeUpdate");
296: }
297: }
298: }
299:
300: public static final AttributeSet bold;
301:
302: public static final AttributeSet italic;
303: static {
304: MutableAttributeSet attrs = new SimpleAttributeSet();
305: StyleConstants.setBold(attrs, true);
306: bold = attrs;
307: attrs = new SimpleAttributeSet();
308: StyleConstants.setItalic(attrs, true);
309: italic = attrs;
310: }
311:
312: /**
313: * Asserts that the expected number of children was removed and/or added
314: * to an element.
315: *
316: * @param object <code>ElementChange</code> implementation which stores
317: * the information.
318: * @param element the element modified.
319: * @param removed the number of children removed.
320: * @param added the number of children added
321: */
322: public static void assertChange(final Object object,
323: final Element element, final int removed, final int added) {
324: ElementChange change = (ElementChange) object;
325: assertSame("change.element", element, change.getElement());
326: assertEquals("change.removed.length", removed, change
327: .getChildrenRemoved().length);
328: assertEquals("change.added.length", added, change
329: .getChildrenAdded().length);
330: }
331:
332: /**
333: * Asserts that the removed and/or added children have the expected offsets.
334: *
335: * @param change the changes performed to an element.
336: * @param removedOffsets the offsets of children removed in the form
337: * <code>{start1, end1, start2, end2, ...}</code>.
338: * @param addedOffsets the offsets of children added in the same form as
339: * <code>removedOffsets</code>.
340: */
341: public static void assertChange(final ElementChange change,
342: final int[] removedOffsets, final int[] addedOffsets) {
343: final Element[] removed = change.getChildrenRemoved();
344: assertEquals("change.removed.length",
345: removedOffsets.length / 2, removed.length);
346: for (int i = 0, j = 0; i < removed.length; i++, j += 2) {
347: assertEquals("change.removed[" + i + "].start",
348: removedOffsets[j], removed[i].getStartOffset());
349: assertEquals("change.removed[" + i + "].end",
350: removedOffsets[j + 1], removed[i].getEndOffset());
351: }
352: final Element[] added = change.getChildrenAdded();
353: assertEquals("change.added.length", addedOffsets.length / 2,
354: added.length);
355: for (int i = 0, j = 0; i < added.length; i++, j += 2) {
356: assertEquals("change.added[" + i + "].start",
357: addedOffsets[j], added[i].getStartOffset());
358: assertEquals("change.added[" + i + "].end",
359: addedOffsets[j + 1], added[i].getEndOffset());
360: }
361: }
362:
363: /**
364: * Asserts that ElementChange has expected field values.
365: *
366: * @param change the change
367: * @param element element where the change occurred
368: * @param index index where the change occurred
369: * @param removed offsets of the elements removed
370: * @param added offsets of the elements added
371: */
372: public static void assertChange(final Object change,
373: final Element element, final int index,
374: final int[] removed, final int[] added) {
375: assertSame("change.element", element, ((ElementChange) change)
376: .getElement());
377: assertEquals("change.index", index, ((ElementChange) change)
378: .getIndex());
379: assertChange((ElementChange) change, removed, added);
380: }
381:
382: /**
383: * Asserts that an element has children with the expected offsets.
384: *
385: * @param element the element where to check children.
386: * @param offsets the expected offsets in the form
387: * <code>{start1, end1, start2, end2, ...}</code>.
388: */
389: public static void assertChildren(final Element element,
390: final int[] offsets) {
391: final int count = element.getElementCount();
392: assertEquals("element.children.length", offsets.length / 2,
393: count);
394: for (int i = 0, j = 0; i < count; i++, j += 2) {
395: final Element child = element.getElement(i);
396: assertEquals("element.children[" + i + "].start",
397: offsets[j], child.getStartOffset());
398: assertEquals("element.children[" + i + "].end",
399: offsets[j + 1], child.getEndOffset());
400: }
401: }
402:
403: /**
404: * Asserts that an element has children with the expected offsets and
405: * attributes.
406: *
407: * @param element the element where to check children.
408: * @param offsets the expected offsets.
409: * @param attributes the expected attributes; <code>null</code> if no
410: * attributes expected.
411: */
412: public static void assertChildren(final Element element,
413: final int[] offsets, final AttributeSet[] attributes) {
414: assertChildren(element, offsets);
415: assertEquals("element.attributes.length", attributes.length,
416: element.getElementCount());
417: for (int i = 0; i < attributes.length; i++) {
418: final Element child = element.getElement(i);
419: if (attributes[i] == null) {
420: assertEquals("element.children[" + i
421: + "].attributes.count", 0, child
422: .getAttributes().getAttributeCount());
423: } else {
424: assertTrue("element.child[" + i + "].attributes", child
425: .getAttributes().isEqual(attributes[i]));
426: }
427: }
428: }
429:
430: /**
431: * Asserts that an element spec is as expected.
432: *
433: * @param spec the spec to check.
434: * @param type the type of the spec.
435: * @param direction the direction of the spec.
436: * @param offset the offset of the spec.
437: * @param length the length of the spec.
438: */
439: public static void assertSpec(final ElementSpec spec,
440: final short type, final short direction, final int offset,
441: final int length, final boolean isNullArray) {
442: assertEquals("spec.type", type, spec.getType());
443: assertEquals("spec.direction", direction, spec.getDirection());
444: assertEquals("spec.offset", offset, spec.getOffset());
445: assertEquals("spec.length", length, spec.getLength());
446: assertEquals("spec.array", isNullArray, spec.getArray() == null);
447: }
448:
449: /**
450: * Asserts that an element spec is as expected.
451: *
452: * @param spec the spec to check.
453: * @param type the type of the spec.
454: * @param direction the direction of the spec.
455: * @param offset the offset of the spec.
456: * @param length the length of the spec.
457: */
458: public static void assertSpec(final ElementSpec spec,
459: final short type, final short direction, final int offset,
460: final int length) {
461: assertSpec(spec, type, direction, offset, length, true);
462: }
463:
464: /**
465: * Compares two <code>ElementSpec</code> objects.
466: *
467: * @param expected the expected spec.
468: * @param actual the actual spec.
469: */
470: public static void assertSpec(final ElementSpec expected,
471: final ElementSpec actual) {
472: assertSpec(actual, expected.getType(), expected.getDirection(),
473: expected.getOffset(), expected.getLength());
474: }
475:
476: /**
477: * Compares two arrays of <code>ElementSpec</code> objects.
478: *
479: * @param expected array with expected specs.
480: * @param actual array with the actual specs.
481: */
482: public static void assertSpecs(final ElementSpec[] expected,
483: final ElementSpec[] actual) {
484: assertEquals("specs.length", expected.length, actual.length);
485: for (int i = 0; i < expected.length; i++) {
486: assertSpec(expected[i], actual[i]);
487: }
488: }
489:
490: /**
491: * Returns the list of edits stored in <code>DefaultDocumentEvent</code>
492: * object.
493: *
494: * @param event the event from which to extract the field.
495: * @return returns the <code>edits</code> from
496: * <code>javax.swing.undo.CompoundEdit</code>, or <code>null</code>
497: * if something goes wrong.
498: */
499: public static Vector<?> getEdits(final DefaultDocumentEvent event) {
500: try {
501: Class<?> eventSuperClass = event.getClass().getSuperclass();
502: Field f = eventSuperClass.getDeclaredField("edits");
503: f.setAccessible(true);
504: return (Vector<?>) (f.get(event));
505: } catch (IllegalAccessException e) {
506: e.printStackTrace();
507: } catch (NoSuchFieldException e) {
508: e.printStackTrace();
509: }
510: return null;
511: }
512:
513: /**
514: * Dumps the changes stored in <code>change</code>.
515: *
516: * @param change the change to print removed and added children from.
517: */
518: public static void printChange(ElementChange change) {
519: System.out.print("@ " + change.getIndex() + ": "
520: + change.getElement());
521: System.out.println(" <<< Removed:");
522: printElements(change.getChildrenRemoved());
523: System.out.println(" >>> Added:");
524: printElements(change.getChildrenAdded());
525: }
526:
527: /**
528: * Prints all the changes to elements performed.
529: *
530: * @param edits the list extracted from a <code>DefaultDocumentEvet</code>
531: * object.
532: */
533: public static void printChanges(List<?> edits) {
534: for (int i = 0; i < edits.size(); i++) {
535: Object edit = edits.get(i);
536: if (edit instanceof ElementChange) {
537: printChange((ElementChange) edit);
538: System.out.println();
539: }
540: }
541: }
542:
543: /**
544: * Prints elements contained in an array.
545: *
546: * @param elems the array containing elements of interest.
547: */
548: public static void printElements(Element[] elems) {
549: for (int i = 0; i < elems.length; i++) {
550: System.out.print(" [" + i + "]" + elems[i]);
551: }
552: }
553:
554: /**
555: * Prints the specs contained in an array.
556: *
557: * @param spec the array containing specs of interest.
558: */
559: public static void printElementSpecs(ElementSpec[] spec) {
560: for (int i = 0; i < spec.length; i++) {
561: System.out.println("\t" + spec[i]
562: + (i != spec.length - 1 ? "," : ""));
563: }
564: }
565:
566: private DefStyledDoc_Helpers() {
567: }
568: }
|