001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.spi.editor.highlighting.support;
043:
044: import java.util.ArrayList;
045: import java.util.Enumeration;
046: import java.util.Random;
047: import javax.swing.text.AttributeSet;
048: import javax.swing.text.PlainDocument;
049: import javax.swing.text.Position;
050: import javax.swing.text.SimpleAttributeSet;
051: import org.netbeans.api.editor.settings.AttributesUtilities;
052: import org.netbeans.junit.NbTestCase;
053: import org.netbeans.spi.editor.highlighting.*;
054:
055: /**
056: *
057: * @author Vita Stejskal
058: */
059: public class PositionsBagRandomTest extends NbTestCase {
060:
061: private static final int START = 0;
062: private static final int END = 100;
063:
064: private final Random RAND = new Random();
065: private String[] layerNames;
066: private HighlightsContainer[] containers;
067:
068: public PositionsBagRandomTest(String testName) {
069: super (testName);
070: }
071:
072: protected void setUp() {
073: RAND.setSeed(System.currentTimeMillis());
074:
075: layerNames = new String[] { "layer-A", "layer-B", "layer-C", };
076:
077: containers = new HighlightsContainer[layerNames.length];
078:
079: for (int i = 0; i < layerNames.length; i++) {
080: containers[i] = createRandomBag(layerNames[i]);
081: }
082:
083: }
084:
085: public void testMerging() {
086: HighlightsContainer composite = mergeContainers(true,
087: layerNames, containers);
088:
089: for (int pointer = START; pointer <= END; pointer++) {
090: String failMsg = null;
091: Highlight[] highestPair = new Highlight[] { null, null };
092: Highlight[] compositePair = new Highlight[] { null, null };
093:
094: try {
095: highestPair = new Highlight[] { null, null };
096: compositePair = new Highlight[] { null, null };
097:
098: // Find all highlights at the position
099: ArrayList<AttributeSet> leftHighlights = new ArrayList<AttributeSet>();
100: ArrayList<AttributeSet> rightHighlights = new ArrayList<AttributeSet>();
101: for (int i = 0; i < containers.length; i++) {
102: Highlight[] containerPair = findPair(pointer,
103: containers[i].getHighlights(START, END));
104: if (containerPair[0] != null) {
105: leftHighlights.add(containerPair[0]
106: .getAttributes());
107: }
108: if (containerPair[1] != null) {
109: rightHighlights.add(containerPair[1]
110: .getAttributes());
111: }
112: }
113:
114: if (!leftHighlights.isEmpty()) {
115: highestPair[0] = new Highlight(
116: pointer,
117: pointer,
118: AttributesUtilities
119: .createComposite(leftHighlights
120: .toArray(new AttributeSet[leftHighlights
121: .size()])));
122: }
123: if (!rightHighlights.isEmpty()) {
124: highestPair[1] = new Highlight(
125: pointer,
126: pointer,
127: AttributesUtilities
128: .createComposite(rightHighlights
129: .toArray(new AttributeSet[rightHighlights
130: .size()])));
131: }
132:
133: // Find the composite container highlight at the position
134: compositePair = findPair(pointer, composite
135: .getHighlights(START, END));
136:
137: for (int i = 0; i < 2; i++) {
138: if (highestPair[i] != null
139: && compositePair[i] != null) {
140: // Both highlights exist -> check they are the same
141: if (!highestPair[i].getAttributes().isEqual(
142: compositePair[i].getAttributes())) {
143: failMsg = (i == 0 ? "Left" : "Right")
144: + "pair attributes do not match";
145: }
146: } else if (highestPair[i] != null
147: || compositePair[i] != null) {
148: // Both highlights should be null otherwise they would not match
149: failMsg = (i == 0 ? "Left" : "Right")
150: + " highlight doesn't match";
151: }
152: }
153: } catch (Throwable e) {
154: failMsg = e.getMessage();
155: }
156:
157: if (failMsg != null) {
158: dumpAll(pointer, layerNames, containers, composite);
159:
160: // Dump the pair that failed
161: System.out.println("highest pair (pos = " + pointer
162: + ") : " + dumpHighlight(highestPair[0]) + ", "
163: + dumpHighlight(highestPair[1]));
164: System.out.println(" proxy pair (pos = " + pointer
165: + ") : " + dumpHighlight(compositePair[0])
166: + ", " + dumpHighlight(compositePair[1]));
167:
168: fail(failMsg + " (position = " + pointer + ")");
169: }
170: }
171: }
172:
173: public void testTrimming() {
174: HighlightsContainer composite = mergeContainers(false,
175: layerNames, containers);
176:
177: for (int pointer = START; pointer <= END; pointer++) {
178: String failMsg = null;
179: Highlight[] highestPair = new Highlight[] { null, null };
180: Highlight[] compositePair = new Highlight[] { null, null };
181:
182: try {
183: highestPair = new Highlight[] { null, null };
184: compositePair = new Highlight[] { null, null };
185:
186: // Find the highest highlight at the position
187: for (int i = containers.length - 1; i >= 0; i--) {
188: Highlight[] containerPair = findPair(pointer,
189: containers[i].getHighlights(START, END));
190: if (highestPair[0] == null) {
191: highestPair[0] = containerPair[0];
192: }
193: if (highestPair[1] == null) {
194: highestPair[1] = containerPair[1];
195: }
196: }
197:
198: // Find the composite container highlight at the position
199: compositePair = findPair(pointer, composite
200: .getHighlights(START, END));
201:
202: for (int i = 0; i < 2; i++) {
203: if (highestPair[i] != null
204: && compositePair[i] != null) {
205: // Both highlights exist -> check they are the same
206: if (!highestPair[i].getAttributes().isEqual(
207: compositePair[i].getAttributes())) {
208: failMsg = (i == 0 ? "Left" : "Right")
209: + "pair attributes do not match";
210: }
211: } else if (highestPair[i] != null
212: || compositePair[i] != null) {
213: // Both highlights should be null otherwise they would not match
214: failMsg = (i == 0 ? "Left" : "Right")
215: + " highlight doesn't match";
216: }
217: }
218: } catch (Throwable e) {
219: failMsg = e.getMessage();
220: }
221:
222: if (failMsg != null) {
223: dumpAll(pointer, layerNames, containers, composite);
224:
225: // Dump the pair that failed
226: System.out.println("highest pair (pos = " + pointer
227: + ") : " + dumpHighlight(highestPair[0]) + ", "
228: + dumpHighlight(highestPair[1]));
229: System.out.println(" proxy pair (pos = " + pointer
230: + ") : " + dumpHighlight(compositePair[0])
231: + ", " + dumpHighlight(compositePair[1]));
232:
233: fail(failMsg + " (position = " + pointer + ")");
234: }
235: }
236: }
237:
238: private Highlight[] findPair(int offset,
239: HighlightsSequence highlights) {
240: Highlight left = null;
241: Highlight right = null;
242:
243: for (; highlights.moveNext();) {
244: if (highlights.getStartOffset() == highlights
245: .getEndOffset()) {
246: // ignore empty offsets
247: continue;
248: }
249:
250: if (offset > highlights.getStartOffset()
251: && offset < highlights.getEndOffset()) {
252: left = right = copyCurrentHighlight(highlights);
253: } else if (offset == highlights.getEndOffset()) {
254: left = copyCurrentHighlight(highlights);
255: } else if (offset == highlights.getStartOffset()) {
256: right = copyCurrentHighlight(highlights);
257: }
258: }
259:
260: return new Highlight[] { left, right };
261: }
262:
263: private Highlight copyCurrentHighlight(HighlightsSequence iterator) {
264: return new Highlight(iterator.getStartOffset(), iterator
265: .getEndOffset(), iterator.getAttributes());
266: }
267:
268: private String dumpHighlight(Highlight h) {
269: if (h == null) {
270: return "< , , >";
271: } else {
272: StringBuilder sb = new StringBuilder();
273:
274: sb.append("<");
275: sb.append(h.getStartOffset());
276: sb.append(",");
277: sb.append(h.getEndOffset());
278: sb.append(",");
279:
280: Enumeration en = h.getAttributes().getAttributeNames();
281: while (en.hasMoreElements()) {
282: Object attrName = en.nextElement();
283: Object attrValue = h.getAttributes().getAttribute(
284: attrName);
285:
286: sb.append("'");
287: sb.append(attrName.toString());
288: sb.append("' = '");
289: sb.append(attrValue == null ? "null" : attrValue
290: .toString());
291: sb.append("'");
292: if (en.hasMoreElements()) {
293: sb.append(", ");
294: }
295: }
296:
297: sb.append(">");
298:
299: return sb.toString();
300: }
301: }
302:
303: private void dumpAll(int position, String[] layerNames,
304: HighlightsContainer[] containers,
305: HighlightsContainer composite) {
306: // Dump the layers
307: System.out.println("Dumping containers:");
308: for (int i = 0; i < containers.length; i++) {
309: System.out.println(" containers[" + i + "] "
310: + layerNames[i] + " {");
311: for (HighlightsSequence highlights = containers[i]
312: .getHighlights(START, END); highlights.moveNext();) {
313: Highlight h = copyCurrentHighlight(highlights);
314: System.out.println(" " + dumpHighlight(h));
315: }
316: System.out.println(" } End of containers[" + i + "] "
317: + layerNames[i] + " -------------------------");
318: }
319: System.out.println("Dumping composite container: {");
320: for (HighlightsSequence proxyHighlights = composite
321: .getHighlights(START, END); proxyHighlights.moveNext();) {
322: Highlight h = copyCurrentHighlight(proxyHighlights);
323: System.out.println(" " + dumpHighlight(h));
324: }
325: System.out
326: .println("} End of composite container -----------------------");
327: }
328:
329: private PositionsBag createRandomBag(String bagId) {
330:
331: PositionsBag bag = new PositionsBag(new PlainDocument(), false);
332:
333: int attrIdx = 0;
334: int startOffset = START;
335: int endOffset = END;
336:
337: int maxGapSize = Math.max((int) (endOffset - startOffset) / 10,
338: 1);
339: int maxHighlightSize = Math.max(
340: (int) (endOffset - startOffset) / 2, 1);
341:
342: for (int pointer = startOffset + RAND.nextInt(maxGapSize); pointer <= endOffset;) {
343: int highlightSize = RAND.nextInt(maxHighlightSize);
344: SimpleAttributeSet attributes = new SimpleAttributeSet();
345: attributes.addAttribute(
346: "AttrName-" + bagId + "-" + attrIdx, "AttrValue");
347: attrIdx++;
348:
349: if (pointer + highlightSize < endOffset) {
350: bag.addHighlight(new SimplePosition(pointer),
351: new SimplePosition(pointer + highlightSize),
352: attributes);
353: } else {
354: bag.addHighlight(new SimplePosition(pointer),
355: new SimplePosition(endOffset), attributes);
356: }
357:
358: // move the pointer
359: pointer += highlightSize + RAND.nextInt(maxGapSize);
360: }
361:
362: return bag;
363: }
364:
365: private PositionsBag mergeContainers(boolean merge,
366: String[] layerNames, HighlightsContainer[] containers) {
367: PositionsBag bag = new PositionsBag(new PlainDocument(), merge);
368:
369: for (int i = 0; i < containers.length; i++) {
370: HighlightsSequence layerHighlights = containers[i]
371: .getHighlights(START, END);
372:
373: for (; layerHighlights.moveNext();) {
374: bag.addHighlight(new SimplePosition(layerHighlights
375: .getStartOffset()), new SimplePosition(
376: layerHighlights.getEndOffset()),
377: layerHighlights.getAttributes());
378: }
379: }
380:
381: return bag;
382: }
383:
384: private static final class Highlight {
385: private int startOffset;
386: private int endOffset;
387: private AttributeSet attributes;
388:
389: public Highlight(int startOffset, int endOffset,
390: AttributeSet attributes) {
391: this .startOffset = startOffset;
392: this .endOffset = endOffset;
393: this .attributes = attributes;
394: }
395:
396: public int getStartOffset() {
397: return startOffset;
398: }
399:
400: public void setStartOffset(int startOffset) {
401: this .startOffset = startOffset;
402: }
403:
404: public int getEndOffset() {
405: return endOffset;
406: }
407:
408: public void setEndOffset(int endOffset) {
409: this .endOffset = endOffset;
410: }
411:
412: public AttributeSet getAttributes() {
413: return attributes;
414: }
415:
416: public void setAttributes(AttributeSet attributes) {
417: this .attributes = attributes;
418: }
419:
420: } // End of H class
421:
422: private static final class SimplePosition implements Position {
423: private int offset;
424:
425: public SimplePosition(int offset) {
426: this .offset = offset;
427: }
428:
429: public int getOffset() {
430: return offset;
431: }
432: } // End of SimplePosition class
433:
434: }
|