From 1732485c3dea1dd39d7b71e684b19b2c8ea03f75 Mon Sep 17 00:00:00 2001 From: Alan Liu Date: Mon, 24 Apr 2000 20:38:00 +0000 Subject: [PATCH] Moved to test packages X-SVN-Rev: 1232 --- .../com/ibm/richtext/test/unit/TestAll.java | 55 ++ .../richtext/test/unit/TestAttributeMap.java | 409 ++++++++++ .../richtext/test/unit/TestAttributeSet.java | 91 +++ .../ibm/richtext/test/unit/TestFormatter.java | 250 ++++++ .../com/ibm/richtext/test/unit/TestMText.java | 721 ++++++++++++++++++ .../test/unit/TestMTextStreaming.java | 162 ++++ .../test/unit/TestParagraphStyles.java | 339 ++++++++ icu4j/src/com/ibm/test/richtext/TestAll.java | 55 ++ .../ibm/test/richtext/TestAttributeMap.java | 409 ++++++++++ .../ibm/test/richtext/TestAttributeSet.java | 91 +++ .../com/ibm/test/richtext/TestFormatter.java | 250 ++++++ .../src/com/ibm/test/richtext/TestMText.java | 721 ++++++++++++++++++ .../ibm/test/richtext/TestMTextStreaming.java | 162 ++++ .../test/richtext/TestParagraphStyles.java | 339 ++++++++ 14 files changed, 4054 insertions(+) create mode 100755 icu4j/src/com/ibm/richtext/test/unit/TestAll.java create mode 100755 icu4j/src/com/ibm/richtext/test/unit/TestAttributeMap.java create mode 100755 icu4j/src/com/ibm/richtext/test/unit/TestAttributeSet.java create mode 100755 icu4j/src/com/ibm/richtext/test/unit/TestFormatter.java create mode 100755 icu4j/src/com/ibm/richtext/test/unit/TestMText.java create mode 100755 icu4j/src/com/ibm/richtext/test/unit/TestMTextStreaming.java create mode 100755 icu4j/src/com/ibm/richtext/test/unit/TestParagraphStyles.java create mode 100755 icu4j/src/com/ibm/test/richtext/TestAll.java create mode 100755 icu4j/src/com/ibm/test/richtext/TestAttributeMap.java create mode 100755 icu4j/src/com/ibm/test/richtext/TestAttributeSet.java create mode 100755 icu4j/src/com/ibm/test/richtext/TestFormatter.java create mode 100755 icu4j/src/com/ibm/test/richtext/TestMText.java create mode 100755 icu4j/src/com/ibm/test/richtext/TestMTextStreaming.java create mode 100755 icu4j/src/com/ibm/test/richtext/TestParagraphStyles.java diff --git a/icu4j/src/com/ibm/richtext/test/unit/TestAll.java b/icu4j/src/com/ibm/richtext/test/unit/TestAll.java new file mode 100755 index 00000000000..0c815806c70 --- /dev/null +++ b/icu4j/src/com/ibm/richtext/test/unit/TestAll.java @@ -0,0 +1,55 @@ +/* + * @(#)$RCSfile: TestAll.java,v $ $Revision: 1.1 $ $Date: 2000/04/24 20:38:00 $ + * + * (C) Copyright IBM Corp. 1998-1999. All Rights Reserved. + * + * The program is provided "as is" without any warranty express or + * implied, including the warranty of non-infringement and the implied + * warranties of merchantibility and fitness for a particular purpose. + * IBM will not be liable for any damages suffered by you as a result + * of using the Program. In no event will IBM be liable for any + * special, indirect or consequential damages or lost profits even if + * IBM has been advised of the possibility of their occurrence. IBM + * will not be liable for any third party claims against you. + */ +package com.ibm.richtext.tests; + +import com.ibm.test.TestFmwk; + +public class TestAll extends TestFmwk { + + static final String COPYRIGHT = + "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved"; + + public static void main(String[] args) throws Exception { + new TestAll().run(args); + } + + public void TestAttributeSet() throws Exception { + run(new TestAttributeSet()); + } + + public void TestAttributeMap() throws Exception { + run(new TestAttributeMap()); + } + + public void TestFormatter() throws Exception { + run(new TestFormatter()); + } + + public void TestMText() throws Exception { + run(new TestMText()); + } + + public void TestParagraphStyles() throws Exception { + run(new TestParagraphStyles()); + } + + public void TestMTextStreaming() throws Exception { + run(new TestMTextStreaming()); + } + + public void TestTextPanel() throws Exception { + run(new TestTextPanel()); + } +} \ No newline at end of file diff --git a/icu4j/src/com/ibm/richtext/test/unit/TestAttributeMap.java b/icu4j/src/com/ibm/richtext/test/unit/TestAttributeMap.java new file mode 100755 index 00000000000..cc8f7f44f6f --- /dev/null +++ b/icu4j/src/com/ibm/richtext/test/unit/TestAttributeMap.java @@ -0,0 +1,409 @@ +/* + * @(#)$RCSfile: TestAttributeMap.java,v $ $Revision: 1.1 $ $Date: 2000/04/24 20:38:00 $ + * + * (C) Copyright IBM Corp. 1998-1999. All Rights Reserved. + * + * The program is provided "as is" without any warranty express or + * implied, including the warranty of non-infringement and the implied + * warranties of merchantibility and fitness for a particular purpose. + * IBM will not be liable for any damages suffered by you as a result + * of using the Program. In no event will IBM be liable for any + * special, indirect or consequential damages or lost profits even if + * IBM has been advised of the possibility of their occurrence. IBM + * will not be liable for any third party claims against you. + */ +package com.ibm.richtext.tests; + +import com.ibm.test.TestFmwk; + +import com.ibm.textlayout.attributes.AttributeSet; +import com.ibm.textlayout.attributes.TextAttribute; +import com.ibm.textlayout.attributes.Map; +import com.ibm.textlayout.attributes.AttributeMap; +import java.util.Enumeration; + +// Java2 imports +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; +import java.util.Map.Entry; + + +public class TestAttributeMap extends TestFmwk { + + static final String COPYRIGHT = + "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved"; + + + // There are JDK 1.1 versions of AttributeMap and AttributeSet. + // Some of the tests in this class require Java 2 API's. I have + // tried to isolate these tests by conditionalizing them on + // this static variable. If you are back-porting to 1.1, remove + // the Java 2 tests ONLY. + private static final boolean gJDK11 = false; + + public static void main(String[] args) throws Exception { + + new TestAttributeMap().run(args); + } + + private AttributeSet maps; // A Set of AttributeMaps + private AttributeSet sets; // A Set of Sets + + private static final class TestAttribute extends TextAttribute { + + TestAttribute(String name) { + super(name); + } + } + + private static final TestAttribute[] attributes = { + new TestAttribute("0"), new TestAttribute("1"), new TestAttribute("2") + }; + + private static final Object[] values = { + "Hello world", new Float(-42), new Object(), new AttributeMap(new TestAttribute("3"), "HH") + }; + + /** + * Returns lhs.equals(rhs) - but also checks for symmetry, and + * consistency with hashCode(). + */ + private boolean equalMaps(AttributeMap lhs, Object rhs) { + + boolean equal = lhs.equals(rhs); + if (equal != (rhs.equals(lhs))) { + errln("AttributeMap.equals is not symetric"); + } + if (equal) { + if (lhs.hashCode() != rhs.hashCode()) { + errln("AttributeMaps are equal but hashCodes differ"); + } + } + return equal; + } + + public TestAttributeMap() { + + maps = AttributeSet.EMPTY_SET; + maps = maps.addElement(AttributeMap.EMPTY_ATTRIBUTE_MAP); + maps.addElement(new AttributeMap(TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUB)); + maps.addElement(new AttributeMap(TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUPER)); + + for (int i=0; i < attributes.length; i++) { + for (int j=0; j < values.length; j++) { + maps = maps.addElement(new AttributeMap(attributes[i], values[j])); + } + } + + AttributeMap bigMap = new AttributeMap(new TestAttribute("4"), "value"); + for (int i=0; i < Math.min(attributes.length, values.length); i++) { + bigMap = bigMap.addAttribute(attributes[i], values[values.length-i-1]); + } + maps = maps.addElement(bigMap); + + sets = AttributeSet.EMPTY_SET; + + sets = new AttributeSet(AttributeSet.EMPTY_SET); + + for (int i=0; i < attributes.length; i++) { + AttributeSet newSet = new AttributeSet(attributes[i]); + sets = sets.addElement(newSet); + } + + AttributeSet allAttrs = AttributeSet.EMPTY_SET; + for (int i=0; i < attributes.length; i++) { + allAttrs = allAttrs.addElement(attributes[i]); + } + + sets = sets.addElement(allAttrs); + } + + /** + * Run tests on AttributeMap. If a test fails an exception will propogate out + * of this method. + */ + public void test() { + + easyTests(); + + Enumeration mapIter = maps.elements(); + while (mapIter.hasMoreElements()) { + + AttributeMap testMap = (AttributeMap) mapIter.nextElement(); + + _testModifiers(testMap); + _testViews(testMap); + + Enumeration unionIter = maps.elements(); + while (unionIter.hasMoreElements()) { + _testUnionWith(testMap, (AttributeMap) unionIter.nextElement()); + } + + Enumeration setIter = sets.elements(); + while (setIter.hasMoreElements()) { + AttributeSet testSet = (AttributeSet) setIter.nextElement(); + _testIntersectWith(testMap, testSet); + _testRemoveAttributes(testMap, testSet); + } + } + } + + /** + * Invoke modifiers on map. All should throw + * UnsupportedOperationException, and leave map unmodified. + */ + void _testModifiers(AttributeMap map) { + + if (gJDK11) { + return; + } + + AttributeMap originalMap = new AttributeMap(map); + + try { + map.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); + errln("Put should throw UnsupportedOperationException."); + } + catch(UnsupportedOperationException e) { + } + + try { + Object key = TextAttribute.WEIGHT; + Iterator iter = map.keySet().iterator(); + if (iter.hasNext()) { + key = iter.next(); + } + map.remove(key); + errln("Set should throw UnsupportedOperationException."); + } + catch(UnsupportedOperationException e) { + } + + try { + map.putAll(map); + errln("putAll should throw UnsupportedOperationException."); + } + catch(UnsupportedOperationException e) { + } + + try { + map.clear(); + errln("clear should throw UnsupportedOperationException."); + } + catch(UnsupportedOperationException e) { + } + + if (!originalMap.equals(map)) { + errln("Modifiers changed map."); + } + } + + /** + * Ensure that map.addAttributes(addMap) is equivalent to calling + * map.add on all of addMap's entries. + */ + void _testUnionWith(AttributeMap map, AttributeMap addMap) { + + AttributeMap lhs = map.addAttributes(addMap); + + AttributeMap rhs = map; + + Enumeration iter = addMap.getKeySet().elements(); + while (iter.hasMoreElements()) { + Object attr = iter.nextElement(); + Object value = addMap.get(attr); + rhs = rhs.addAttribute(attr, value); + } + + if (!equalMaps(lhs, rhs)) { + errln("Maps are not equal."); + } + } + + /** + * Ensure that map.removeAttributes(remove) is equivalent to calling + * map.removeAttribute on remove's elements. + */ + void _testRemoveAttributes(AttributeMap map, AttributeSet remove) { + + AttributeMap lhs = map.removeAttributes(remove); + + AttributeMap rhs = map; + + Enumeration iter = remove.elements(); + while (iter.hasMoreElements()) { + Object attr = iter.nextElement(); + rhs = rhs.removeAttribute(attr); + } + + if (!equalMaps(lhs, rhs)) { + errln("Maps are not equal."); + } + } + + /** + * Ensure that map.intersectWith(intersect) is equivalent to + * map.removeAttributes(map.keySet() - intersect); + */ + void _testIntersectWith(AttributeMap map, AttributeSet intersect) { + + AttributeMap lhs = map.intersectWith(intersect); + + AttributeSet keySet = map.getKeySet(); + AttributeSet removeSet = keySet.subtract(intersect); + AttributeMap rhs = map.removeAttributes(removeSet); + + if (!equalMaps(lhs, rhs)) { + map.intersectWith(intersect); + logln("intersect: " + intersect); + logln("keySet: " + keySet); + logln("removeSet: " + removeSet); + logln("map: " + map); + logln("lhs: " + lhs); + logln("rhs: " + rhs); + errln("Maps are not equal."); + } + } + + /** + * Ensure that: + * map, map.keySet(), and map.entrySet() are the same size; + * map.containsKey() is true for every key in keySet(); + * map.containsValue() is true for every value in values; + * every entry key is in keySet, every entry value is in map.values(); + * map.get() is consistent with entry's key, value; + * sum of hashcodes of entries equals map.hashCode(). + */ + void _testViews(AttributeMap map) { + + AttributeSet keySet = map.getKeySet(); + + Enumeration keyIter = keySet.elements(); + while (keyIter.hasMoreElements()) { + if (!map.containsKey(keyIter.nextElement())) { + errln("keySet contains key not in map"); + } + } + + if (gJDK11) { + return; + } + + Collection values = map.values(); + Set entrySet = map.entrySet(); + + if (keySet.size() != map.size() || entrySet.size() != map.size()) { + errln("Set sizes are inconsistent with map size."); + } + + int hashCode = 0; + + Iterator valueIter = values.iterator(); + while (valueIter.hasNext()) { + if (!map.containsValue(valueIter.next())) { + errln("value set contains value not in map"); + } + } + + Iterator entryIter = entrySet.iterator(); + while (entryIter.hasNext()) { + + Entry entry = (Entry) entryIter.next(); + + Object key = entry.getKey(); + if (!keySet.contains(key)) { + errln("Entry key is not in key set."); + } + + Object value = map.get(entry.getKey()); + if (!values.contains(value)) { + errln("Entry value is not in value set."); + } + + if (map.get(key) != value) { + errln("map.get did not return entry value."); + } + + hashCode += entry.hashCode(); + } + + if (hashCode != map.hashCode()) { + errln("map hashcode is not sum of entry hashcodes."); + } + } + + /** + * Look for correct behavior in obvious cases. + */ + void easyTests() { + + AttributeMap map = new AttributeMap(); + if (!map.equals(AttributeMap.EMPTY_ATTRIBUTE_MAP)) { + errln("Default-constructed map is not equal to empty map."); + } + + map = map.addAttribute(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); + Object otherMap = new AttributeMap(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); + if (!map.equals(otherMap)) { + errln("Maps are inconsistent after map.add"); + } + + otherMap = map.addAttributes(map); + if (!equalMaps(map,otherMap)) { + errln("Maps are inconsistent after addAttributes"); + } + + map = map.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); + + if (map.size() != 2) { + errln("Map size is wrong. map="+map); + } + + if (equalMaps(map,otherMap)) { + errln("Maps should not be equal"); + } + + Object posture = new Float(0); + map = map.addAttribute(TextAttribute.POSTURE, posture); + + if (map.size() != 2) { + errln("Map size is wrong"); + } + + if (!map.get(TextAttribute.POSTURE).equals(posture)) { + errln("Map element is wrong"); + } + + map = map.removeAttribute(TextAttribute.UNDERLINE); + + if (map.size() != 1) { + errln("Map size is wrong"); + } + + if (map.get(TextAttribute.UNDERLINE) != null) { + errln("Map should not have element"); + } + + // map has POSTURE_REGULAR. If we addAttributes a map with + // POSTURE_ITALIC the new map should have POSTURE_ITALIC + + map = map.addAttributes(new AttributeMap(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE)); + if (map.get(TextAttribute.POSTURE) != TextAttribute.POSTURE_OBLIQUE) { + errln("Map element is wrong"); + } + + _testModifiers(map); + _testViews(map); + + Enumeration mapIter = maps.elements(); + while (mapIter.hasMoreElements()) { + AttributeMap testMap = (AttributeMap) mapIter.nextElement(); + Object newValue = new Object(); + AttributeMap newMap = testMap.addAttribute(attributes[0], newValue); + if (newMap.get(attributes[0]) != newValue) { + errln("Did not get expected value back. map=" + map); + } + } + } +} \ No newline at end of file diff --git a/icu4j/src/com/ibm/richtext/test/unit/TestAttributeSet.java b/icu4j/src/com/ibm/richtext/test/unit/TestAttributeSet.java new file mode 100755 index 00000000000..497e62024fe --- /dev/null +++ b/icu4j/src/com/ibm/richtext/test/unit/TestAttributeSet.java @@ -0,0 +1,91 @@ +/* + * @(#)$RCSfile: TestAttributeSet.java,v $ $Revision: 1.1 $ $Date: 2000/04/24 20:38:00 $ + * + * (C) Copyright IBM Corp. 1998-1999. All Rights Reserved. + * + * The program is provided "as is" without any warranty express or + * implied, including the warranty of non-infringement and the implied + * warranties of merchantibility and fitness for a particular purpose. + * IBM will not be liable for any damages suffered by you as a result + * of using the Program. In no event will IBM be liable for any + * special, indirect or consequential damages or lost profits even if + * IBM has been advised of the possibility of their occurrence. IBM + * will not be liable for any third party claims against you. + */ +package com.ibm.richtext.tests; + +import com.ibm.test.TestFmwk; +import com.ibm.textlayout.attributes.AttributeSet; +import java.util.Enumeration; + +public class TestAttributeSet extends TestFmwk { + + static final String COPYRIGHT = + "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved"; + + public static void main(String[] args) throws Exception { + + new TestAttributeSet().run(args); + } + + public void test() { + + final Object elem1 = new Object(); + final Object elem2 = new Float(4); + final Object elem3 = "String"; + final Object elem4 = Boolean.FALSE; + + AttributeSet set1 = new AttributeSet(new Object[] {elem1, elem2, elem3}); + if (set1.size() != 3) { + errln("Size is wrong."); + } + + if (set1.contains(elem4)){ + errln("Set contents are wrong."); + } + + if (!set1.contains(elem1)) { + errln("Set contents are wrong."); + } + + AttributeSet set2 = new AttributeSet(elem4); + + if (set2.size() != 1) { + errln("Size is wrong."); + } + + if (!set2.contains(elem4)){ + errln("Set contents are wrong."); + } + + if (set2.contains(elem1)) { + errln("Set contents are wrong."); + } + + Enumeration iter = set2.elements(); + if (!iter.nextElement().equals(elem4)) { + errln("Invalid object in iterator."); + } + + AttributeSet union = set2.unionWith(set1); + if (!set1.unionWith(set2).equals(union)) { + errln("unionWith is not commutative."); + } + + if (!union.contains(elem1) || !union.contains(elem4)) { + errln("Set contents are wrong."); + } + + if (!set1.addElement(elem4).equals(union)) { + errln("addElement is wrong."); + } + + if (!union.intersectWith(set1).equals(set1)) { + errln("intersectWith is wrong."); + } + + if (!union.subtract(set1).equals(set2)) { + errln("subtract is wrong."); + } + } +} \ No newline at end of file diff --git a/icu4j/src/com/ibm/richtext/test/unit/TestFormatter.java b/icu4j/src/com/ibm/richtext/test/unit/TestFormatter.java new file mode 100755 index 00000000000..8f264fc1974 --- /dev/null +++ b/icu4j/src/com/ibm/richtext/test/unit/TestFormatter.java @@ -0,0 +1,250 @@ +/* + * @(#)$RCSfile: TestFormatter.java,v $ $Revision: 1.1 $ $Date: 2000/04/24 20:38:00 $ + * + * (C) Copyright IBM Corp. 1998-1999. All Rights Reserved. + * + * The program is provided "as is" without any warranty express or + * implied, including the warranty of non-infringement and the implied + * warranties of merchantibility and fitness for a particular purpose. + * IBM will not be liable for any damages suffered by you as a result + * of using the Program. In no event will IBM be liable for any + * special, indirect or consequential damages or lost profits even if + * IBM has been advised of the possibility of their occurrence. IBM + * will not be liable for any third party claims against you. + */ +package com.ibm.richtext.tests; + +import com.ibm.test.TestFmwk; + +import com.ibm.textlayout.attributes.AttributeMap; +import com.ibm.textlayout.attributes.TextAttribute; +import com.ibm.richtext.styledtext.MText; +import com.ibm.richtext.styledtext.MConstText; +import com.ibm.richtext.styledtext.StandardTabRuler; +import com.ibm.richtext.styledtext.StyledText; + +import com.ibm.richtext.textformat.TextOffset; +import com.ibm.richtext.textformat.MFormatter; + +import java.awt.Color; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.image.BufferedImage; + +import java.util.Hashtable; + +public final class TestFormatter extends TestFmwk { + + static final String COPYRIGHT = + "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved"; + public static void main(String[] args) throws Exception { + + new TestFormatter().run(args); + } + + private static final Point ORIGIN = new Point(0, 0); + + private static final AttributeMap DEFAULTS; + static { + final Float floatZero = new Float(0.0f); + + Hashtable defaults = new Hashtable(); + defaults.put(TextAttribute.FAMILY, "Serif"); + defaults.put(TextAttribute.WEIGHT, new Float(1.0f)); + defaults.put(TextAttribute.POSTURE, floatZero); + defaults.put(TextAttribute.SIZE, new Float(18.0f)); + defaults.put(TextAttribute.SUPERSCRIPT, new Integer(0)); + defaults.put(TextAttribute.FOREGROUND, Color.black); + defaults.put(TextAttribute.UNDERLINE, new Integer(-1)); + defaults.put(TextAttribute.STRIKETHROUGH, Boolean.FALSE); + + defaults.put(TextAttribute.EXTRA_LINE_SPACING, floatZero); + defaults.put(TextAttribute.FIRST_LINE_INDENT, floatZero); + defaults.put(TextAttribute.MIN_LINE_SPACING, floatZero); + defaults.put(TextAttribute.LINE_FLUSH, TextAttribute.FLUSH_LEADING); + defaults.put(TextAttribute.LEADING_MARGIN, floatZero); + defaults.put(TextAttribute.TRAILING_MARGIN, floatZero); + defaults.put(TextAttribute.TAB_RULER, new StandardTabRuler()); + + DEFAULTS = new AttributeMap(defaults); + } + + // arg to testLineExceptions + private static final int UNKNOWN = -1; + + private Graphics fGraphics; + + public TestFormatter() { + + fGraphics = new BufferedImage(100, 100, BufferedImage.TYPE_3BYTE_BGR).getGraphics(); + + //JDK 1.1: + //Frame f = new Frame(); + //f.show(); + //fGraphics = f.getGraphics(); + } + + private String fiveLines = "a\nb\nc\nd\ne"; + private String twelveLines = fiveLines + "\n" + fiveLines + "\nf\n"; + AttributeMap PLAIN = AttributeMap.EMPTY_ATTRIBUTE_MAP; + + public void test() { + + MConstText text = new StyledText(fiveLines, PLAIN); + _testLineExceptions(makeFormatter(text, 100, true), 5); + _testLineAccess(makeFormatter(text, 100, true), 5); + + text = new StyledText(twelveLines, PLAIN); + _testLineExceptions(makeFormatter(text, 3, false), 12); + _testLineAccess(makeFormatter(text, 100, true), 12); + + _testWithModification(); + } + + private void _testWithModification() { + + MText text = new StyledText(fiveLines, PLAIN); + MFormatter formatter = makeFormatter(text, 100, true); + Rectangle viewRect = new Rectangle(0, 0, 100, Integer.MAX_VALUE); + + formatter.stopBackgroundFormatting(); + text.append(new StyledText("\n", PLAIN)); + formatter.updateFormat(text.length()-1, 1, viewRect, ORIGIN); + + _testLineAccess(formatter, 6); + + formatter.stopBackgroundFormatting(); + text.append(new StyledText("ad", PLAIN)); + formatter.updateFormat(text.length()-2, 2, viewRect, ORIGIN); + _testLineAccess(formatter, 6); + _testLineExceptions(formatter, 6); + + formatter.stopBackgroundFormatting(); + text.remove(0, 1); + formatter.updateFormat(0, 0, viewRect, ORIGIN); + _testLineAccess(formatter, 6); + _testLineExceptions(formatter, 6); + } + + + private MFormatter makeFormatter(MConstText text, + int lineBound, + boolean wrap) { + + return MFormatter.createFormatter(text, + DEFAULTS, + lineBound, + wrap, + fGraphics); + } + + private void _testLineExceptions(MFormatter formatter, + int numLines) { + + if (numLines == UNKNOWN) { + numLines = formatter.getLineCount(); + } + + boolean caught = false; + + try { + formatter.lineRangeLow(numLines); + } + catch(IllegalArgumentException e) { + caught = true; + } + + if (!caught) { + errln("Didn't get exception"); + } + caught = false; + + try { + formatter.lineRangeLimit(numLines); + } + catch(IllegalArgumentException e) { + caught = true; + } + + if (!caught) { + errln("Didn't get exception"); + } + caught = false; + + try { + formatter.lineGraphicStart(numLines+1); + } + catch(IllegalArgumentException e) { + caught = true; + } + + if (!caught) { + errln("Didn't get exception"); + } + caught = false; + } + + private void _testLineAccess(MFormatter formatter, + int numLines) { + + if (numLines == UNKNOWN) { + numLines = formatter.getLineCount(); + } + + if (formatter.lineGraphicStart(0) != 0) { + errln("Line 0 doesn't start at height 0"); + } + if (formatter.lineRangeLow(0) != 0) { + errln("Line 0 doesn't start at character 0"); + } + + int lastLimit = formatter.lineRangeLimit(0); + final int lineBound = formatter.lineBound(); + int[] hitX = new int[] { -1, 1, lineBound + 2 }; + + TextOffset offset = new TextOffset(); + + for (int i=1; i < numLines; i++) { + + int height = formatter.lineGraphicStart(i); + if (lastLimit != formatter.lineRangeLow(i)) { + errln("lastLine limit is not current line start"); + } + int limit = formatter.lineRangeLimit(i); + + if (limit < lastLimit || (limit == lastLimit && i != numLines-1)) { + errln("line has negative or 0 length"); + } + + int nextHeight = formatter.lineGraphicStart(i+1); + if (nextHeight <= height) { + errln("0-height line"); + } + int incAmount = Math.max((nextHeight-height)/4, 1); + for (int hitY = height; hitY < nextHeight; hitY += incAmount) { + + if (formatter.lineAtHeight(hitY) != i) { + errln("lineAtHeight is wrong"); + } + + for (int j=0; j < hitX.length; j++) { + offset = formatter.pointToTextOffset(offset, + hitX[j], hitY, ORIGIN, null, false); + if (offset.fOffset < lastLimit || offset.fOffset > limit) { + errln("Inconsistent offset from pointToTextOffset"); + } + //if (formatter.lineContaining(offset) != i) { + // int debug = formatter.lineContaining(offset); + // errln("lineContaining is incorrect"); + //} + } + } + + lastLimit = limit; + } + } +} \ No newline at end of file diff --git a/icu4j/src/com/ibm/richtext/test/unit/TestMText.java b/icu4j/src/com/ibm/richtext/test/unit/TestMText.java new file mode 100755 index 00000000000..413f97aaf2d --- /dev/null +++ b/icu4j/src/com/ibm/richtext/test/unit/TestMText.java @@ -0,0 +1,721 @@ +/* + * @(#)$RCSfile: TestMText.java,v $ $Revision: 1.1 $ $Date: 2000/04/24 20:38:00 $ + * + * (C) Copyright IBM Corp. 1998-1999. All Rights Reserved. + * + * The program is provided "as is" without any warranty express or + * implied, including the warranty of non-infringement and the implied + * warranties of merchantibility and fitness for a particular purpose. + * IBM will not be liable for any damages suffered by you as a result + * of using the Program. In no event will IBM be liable for any + * special, indirect or consequential damages or lost profits even if + * IBM has been advised of the possibility of their occurrence. IBM + * will not be liable for any third party claims against you. + */ +package com.ibm.richtext.tests; + +import com.ibm.test.TestFmwk; + +import com.ibm.textlayout.attributes.AttributeMap; +import com.ibm.textlayout.attributes.TextAttribute; + +import com.ibm.richtext.styledtext.MConstText; +import com.ibm.richtext.styledtext.MText; +import com.ibm.richtext.styledtext.StyledText; +import com.ibm.richtext.styledtext.StyleModifier; + +import java.text.CharacterIterator; +import java.util.Random; + +import java.io.*; + +public class TestMText extends TestFmwk { + + static final String COPYRIGHT = + "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved"; + public static void main(String[] args) throws Exception { + + new TestMText().run(args); + } + + private static final int TEST_ITERATIONS = 5000; + private static final int STYLE_TEST_ITERATIONS = 5000; + private static final long RAND_SEED = 598436; + + private static final int NOT_IN_MONKEY_TEST = -5000; + private int testIteration = NOT_IN_MONKEY_TEST; + private int theCase = NOT_IN_MONKEY_TEST; + + private static StyleModifier createMinusModifier(final Object attr) { + return new StyleModifier() { + public AttributeMap modifyStyle(AttributeMap style) { + return style.removeAttribute(attr); + } + }; + } + + public void test() { + + simpleTest(); + styleTest(); + monkeyTest(true); + } + + public void simpleTest() { + + AttributeMap boldStyle = new AttributeMap(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); + AttributeMap italicStyle = new AttributeMap(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); + + MConstText allBold = new StyledText("bbbbb", boldStyle); + MConstText allItalic = new StyledText("iii", italicStyle); + MConstText plain = new StyledText("pppppp", AttributeMap.EMPTY_ATTRIBUTE_MAP); + + { + MText buf = new StyledText(); + int ts = buf.getTimeStamp(); + buf.append(allBold); + buf.append(allItalic); + + if (ts == buf.getTimeStamp()) { + errln("Time stamp not incremented"); + } + + // should be bbbbbiii now + + if (buf.length() != allBold.length() + allItalic.length()) { + errln("Length is wrong."); + } + + for (int i=0; i < buf.length(); i++) { + + char rightChar; + AttributeMap rightStyle; + + if (i < allBold.length()) { + rightChar = allBold.at(0); + rightStyle = boldStyle; + } + else { + rightChar = allItalic.at(0); + rightStyle = italicStyle; + } + + if (buf.at(i) != rightChar) { + errln("Character is wrong."); + } + if (!buf.characterStyleAt(i).equals(rightStyle)) { + errln("Style is wrong."); + } + } + + int pos = 0; + + if (!buf.characterStyleAt(pos).equals(boldStyle)) { + errln("First style is wrong."); + } + if (buf.characterStyleLimit(pos) != allBold.length()) { + errln("Run length is wrong."); + } + + pos = allBold.length(); + + if (!buf.characterStyleAt(pos).equals(italicStyle)) { + errln("Second style is wrong."); + } + if (buf.characterStyleLimit(pos) != buf.length()) { + errln("Run length is wrong."); + } + + { + buf.resetDamagedRange(); + int oldLength = buf.length(); + buf.replace(buf.length(), buf.length(), allBold, 0, allBold.length()); + // bbbbbiiibbbbb + + if (buf.damagedRangeStart() != oldLength) { + errln("Damaged range start is incorrect"); + } + if (buf.damagedRangeLimit() != buf.length()) { + errln("Damaged range limit is incorrect"); + } + } + + int start = allBold.length(); + int limit = start + allItalic.length(); + buf.remove(start, limit); + // bbbbbbbbbb + + if (buf.length() != 2 * allBold.length()) { + errln("Text should be twice the length of bold text."); + } + + pos = buf.length() / 2; + if (buf.characterStyleStart(pos) != 0 || + buf.characterStyleLimit(pos) != buf.length()) { + errln("Run range is wrong."); + } + if (!buf.characterStyleAt(pos).equals(boldStyle)) { + errln("Run style is wrong."); + } + + ts = buf.getTimeStamp(); + CharacterIterator cIter = buf.createCharacterIterator(); + for (char ch = cIter.first(); ch != cIter.DONE; ch = cIter.next()) { + if (ch != allBold.at(0)) { + errln("Character is wrong."); + } + } + + if (ts != buf.getTimeStamp()) { + errln("Time stamp should not have changed"); + } + + buf.replace(0, 1, plain, 0, plain.length()); + + if (ts == buf.getTimeStamp()) { + errln("Time stamp not incremented"); + } + + // ppppppbbbbbbbbb + buf.replace(plain.length(), buf.length(), allItalic, 0, allItalic.length()); + // ppppppiii + + if (buf.length() != allItalic.length()+plain.length()) { + errln("Length is wrong."); + } + + pos = 0; + if (buf.characterStyleLimit(pos) != plain.length()) { + errln("Run limit is wrong."); + } + + pos = plain.length(); + if (buf.characterStyleLimit(pos) != buf.length()) { + errln("Run limit is wrong."); + } + + buf.replace(plain.length(), plain.length(), allBold, 0, allBold.length()); + // ppppppbbbbbiii + + AttributeMap st = buf.characterStyleAt(1); + if (!st.equals(AttributeMap.EMPTY_ATTRIBUTE_MAP)) { + errln("Style is wrong."); + } + if (buf.characterStyleStart(1) != 0 || buf.characterStyleLimit(1) != plain.length()) { + errln("Style start is wrong."); + } + + st = buf.characterStyleAt(buf.length() - 1); + if (!st.equals(italicStyle)) { + errln("Style is wrong."); + } + if (buf.characterStyleStart(buf.length() - 1) != plain.length()+allBold.length()) { + errln("Style start is wrong."); + } + + if (buf.characterStyleLimit(buf.length() - 1) != buf.length()) { + errln("Style limit is wrong."); + } + } + } + + private static int randInt(Random rand, int limit) { + + return randInt(rand, 0, limit); + } + + private static int randInt(Random rand, int start, int limit) { + + if (start > limit) { + throw new IllegalArgumentException("Range length is negative."); + } + else if (start == limit) { + return start; + } + + return start + (Math.abs(rand.nextInt())%(limit-start)) ; + } + + public void styleTest() { + + MText text = new StyledText("0123456789", AttributeMap.EMPTY_ATTRIBUTE_MAP); + + AttributeMap[] styles = new AttributeMap[text.length()]; + for (int i=0; i < styles.length; i++) { + styles[i] = AttributeMap.EMPTY_ATTRIBUTE_MAP; + } + AttributeMap[] oldStyles = new AttributeMap[styles.length]; + System.arraycopy(styles, 0, oldStyles, 0, styles.length); + + AttributeMap bigStyle = new AttributeMap(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON). + addAttribute(TextAttribute.SIZE, new Float(23.0f)); + + StyleModifier[] modifiers = { + StyleModifier.createReplaceModifier(new AttributeMap(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD)), + StyleModifier.createAddModifier(new AttributeMap(TextAttribute.WEIGHT, new Float(1.0f))), + createMinusModifier(TextAttribute.WEIGHT), + + StyleModifier.createAddModifier(new AttributeMap(TextAttribute.POSTURE, new Float(0.0f))), + StyleModifier.createReplaceModifier(new AttributeMap(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE)), + createMinusModifier(TextAttribute.POSTURE), + + StyleModifier.createAddModifier(bigStyle), + StyleModifier.createReplaceModifier(bigStyle), + createMinusModifier(bigStyle.getKeySet()) + }; + + Random rand = new Random(RAND_SEED); + final int stopAt = 4; + + for (int testIteration=0; testIteration < STYLE_TEST_ITERATIONS + 1; testIteration++) { + + System.arraycopy(styles, 0, oldStyles, 0, styles.length); + + int startingAt = Integer.MAX_VALUE; + int endingAt = Integer.MIN_VALUE; + int oldTs = text.getTimeStamp(); + + // hack way to do an invariant check before starting... + if (testIteration != 0) { + // modify styles + text.resetDamagedRange(); + startingAt = randInt(rand, styles.length+1); + endingAt = randInt(rand, startingAt, styles.length+1); + StyleModifier modifier = modifiers[randInt(rand, modifiers.length)]; + + if (testIteration == stopAt) { + testIteration = stopAt; + } + text.modifyCharacterStyles(startingAt, endingAt, modifier); + + for (int j=startingAt; j < endingAt; j++) { + styles[j] = modifier.modifyStyle(styles[j]); + } + } + + // check invariants + AttributeMap oldStyle = null; + int textLength = text.length(); + for (int runStart = 0; runStart < textLength;) { + + AttributeMap currentStyle = text.characterStyleAt(runStart); + int runLimit = text.characterStyleLimit(runStart); + if (runStart >= runLimit) { + errln("Run length is not positive"); + } + if (currentStyle.equals(oldStyle)) { + errln("Styles didn't merge"); + } + + for (int pos=runStart; pos < runLimit; pos++) { + AttributeMap charStyleAtPos = text.characterStyleAt(pos); + if (currentStyle != charStyleAtPos) { + errln("Iterator style is not equal to text style at " + pos + "."); + } + AttributeMap expected = styles[pos]; + if (!currentStyle.equals(expected)) { + errln("Iterator style doesn't match expected style at " + pos + "."); + } + if (!(text.characterStyleStart(pos) == runStart) || + !(text.characterStyleLimit(pos) == runLimit)) { + errln("style run start / limit is not consistent"); + } + } + runStart = runLimit; + } + if (textLength > 0) { + if (text.characterStyleAt(textLength) != + text.characterStyleAt(textLength-1)) { + errln("Character styles at end aren't the same"); + } + } + + // check damaged range: + int damageStart = Integer.MAX_VALUE; + int damageLimit = Integer.MIN_VALUE; + for (int i=0; i < textLength; i++) { + if (!styles[i].equals(oldStyles[i])) { + damageStart = Math.min(i, damageStart); + damageLimit = Math.max(i+1, damageLimit); + } + } + if (damageStart != text.damagedRangeStart() || + damageLimit != text.damagedRangeLimit()) { + logln("Test iteration: " + testIteration); + logln("startingAt: " + startingAt + "; endingAt: " + endingAt); + logln("damageStart: " + damageStart + "; damageLimit: " + damageLimit); + logln("text.rangeStart: " + text.damagedRangeStart() + + "text.rangeLimit: " + text.damagedRangeLimit()); + errln("Damage range start or limit is not expected value"); + } + + if ((damageLimit == Integer.MIN_VALUE) != (oldTs == text.getTimeStamp())) { + + errln("timeStamp is incorrect"); + } + } + } + + protected void err(String message) { + + if (testIteration != NOT_IN_MONKEY_TEST) { + message = "testIteration="+testIteration+"; testCase="+theCase+message; + } + super.err(message); + } + + /** + * Perform a random series of operations on an MText and + * check the result of each operation against a set of invariants. + */ + public void monkeyTest(boolean streaming) { + + /* + You can add any operation to the switch statement provided it + preserves the following invariants: + - The String plainText contains the same text as the StyledStringBuffer. + Obviously, for the test to be meaningful plainText must be computed + independently of the buffer (ie don't write: plainText = buf.getStyledString().toString()). + - Every 'b' is bold, every 'i' is italic, every 'p' is plain, and + no other characters appear in the text. + */ + + AttributeMap boldAttrs = new AttributeMap(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); + AttributeMap italicAttrs = new AttributeMap(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); + AttributeMap emptyAttrs = AttributeMap.EMPTY_ATTRIBUTE_MAP; + + final String bold1Str_getString = "b"; + MConstText bold1Str = new StyledText(bold1Str_getString, boldAttrs); + + final String italic1Str_getString = "i"; + MConstText italic1Str = new StyledText(italic1Str_getString, italicAttrs); + + final String plain1Str_getString = "p"; + MConstText plain1Str = new StyledText(plain1Str_getString, emptyAttrs); + + StyledText temp = new StyledText(); + temp.append(bold1Str); + temp.append(italic1Str); + final String boldItalicStr_getString = bold1Str_getString.concat(italic1Str_getString); + MConstText boldItalicStr = temp; + + temp = new StyledText(); + temp.append(bold1Str); + temp.append(bold1Str); + temp.append(bold1Str); + final String bold3Str_getString = "bbb"; + MConstText bold3Str = temp; + + MText buf = new StyledText(); + String plainText = new String(); + //int testIteration=0; - now instance variables so errln can report it + //int theCase=0; + + final int NUM_CASES = 14; + boolean[] casesExecuted = new boolean[NUM_CASES]; + final int stopAt = -1; + Random rand = new Random(RAND_SEED); + + final String ALWAYS_DIFFERENT = "\uFEFF"; + + for (testIteration=0; testIteration < TEST_ITERATIONS; testIteration++) { + + theCase = randInt(rand, NUM_CASES); + + casesExecuted[theCase] = true; + + if (testIteration == stopAt) { + testIteration = stopAt; // Convenient place to put breakpoint + } + + int timeStamp = buf.getTimeStamp(); + String oldPlainText = plainText; + if (oldPlainText == null) { + errln("oldPlainText is null!"); + } + + switch (theCase) { + + case 0: + // create new string; replace chars at start with different style + buf = new StyledText(); + buf.append(bold3Str); + buf.replace(0, 1, italic1Str, 0, italic1Str.length()); + buf.replace(0, 0, italic1Str, 0, italic1Str.length()); + + plainText = bold3Str_getString.substring(1, bold3Str.length()); + plainText = italic1Str_getString.concat(plainText); + plainText = italic1Str_getString.concat(plainText); + oldPlainText = null; + break; + + case 1: + // delete the last character from the string + if (buf.length() == 0) { + buf.replace(0, 0, italic1Str, 0, italic1Str.length()); + plainText = italic1Str_getString; + oldPlainText = ALWAYS_DIFFERENT; + } + buf.remove(buf.length()-1, buf.length()); + plainText = plainText.substring(0, plainText.length()-1); + break; + + case 2: + // replace some of the buffer with boldItalicStr + int rStart = randInt(rand, buf.length()+1); + int rStop = randInt(rand, rStart, buf.length()+1); + buf.replace(rStart, rStop, boldItalicStr); + { + String newString = (rStart>0)? plainText.substring(0, rStart) : new String(); + newString = newString.concat(boldItalicStr_getString); + if (rStop < plainText.length()) + newString = newString.concat(plainText.substring(rStop, plainText.length())); + oldPlainText = ALWAYS_DIFFERENT; + plainText = newString; + } + break; + + case 3: + // repeatedly insert strings into the center of the buffer + { + int insPos = buf.length() / 2; + String prefix = plainText.substring(0, insPos); + String suffix = plainText.substring(insPos, plainText.length()); + String middle = new String(); + for (int ii=0; ii<4; ii++) { + MConstText which = (ii%2==0)? boldItalicStr : bold3Str; + String whichString = (ii%2==0)? boldItalicStr_getString : bold3Str_getString; + int tempPos = insPos+middle.length(); + buf.insert(tempPos, which); + middle = middle.concat(whichString); + } + plainText = prefix.concat(middle).concat(suffix); + oldPlainText = ALWAYS_DIFFERENT; + } + break; + + case 4: + // insert bold1Str at end + buf.append(bold1Str); + plainText = plainText.concat(bold1Str_getString); + break; + + case 5: + // delete a character from the string + if (buf.length() > 0) { + int delPos = randInt(rand, buf.length()-1); + buf.remove(delPos, delPos+1); + plainText = plainText.substring(0, delPos).concat(plainText.substring(delPos+1)); + } + else { + buf.replace(0, 0, plain1Str, 0, plain1Str.length()); + plainText = plain1Str_getString; + } + break; + + case 6: + // replace the contents of the buffer (except the first character) with itself + { + int start = buf.length() > 1? 1 : 0; + buf.replace(start, buf.length(), buf); + plainText = plainText.substring(0, start).concat(plainText); + if (buf.length() > 0) { + oldPlainText = ALWAYS_DIFFERENT; + } + } + break; + + case 7: + // append the contents of the buffer to itself + { + MConstText content = buf; + buf.insert(buf.length(), content); + plainText = plainText.concat(plainText); + } + break; + + case 8: + // replace the buffer with boldItalicStr+bold3Str + { + MText replacement = new StyledText(); + replacement.append(boldItalicStr); + replacement.append(bold3Str); + buf.replace(0, buf.length(), replacement, 0, replacement.length()); + plainText = boldItalicStr_getString.concat(bold3Str_getString); + oldPlainText = ALWAYS_DIFFERENT; + } + break; + + case 9: + // insert bold1Str at end - same as 4 but uses different API + buf.replace(buf.length(), + buf.length(), + bold1Str_getString.toCharArray(), + 0, + bold1Str_getString.length(), + boldAttrs); + plainText = plainText.concat(bold1Str_getString); + break; + + case 10: + // remove all + buf.remove(); + plainText = ""; + oldPlainText = ALWAYS_DIFFERENT; + break; + + case 11: + // remove all - different way + buf.remove(0, buf.length()); + plainText = ""; + break; + + case 12: + // insert 'i' at 3rd character (or last, if fewer than 3 chars) + { + int insPos = Math.min(buf.length(), 3); + buf.replace(insPos, insPos, 'i', italicAttrs); + plainText = (plainText.substring(0, insPos)). + concat(italic1Str_getString). + concat(plainText.substring(insPos)); + } + break; + + case 13: + if (streaming) { + Throwable error = null; + try { + ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); + ObjectOutputStream objOut = new ObjectOutputStream(bytesOut); + objOut.writeObject(buf); + + ByteArrayInputStream bytesIn = + new ByteArrayInputStream(bytesOut.toByteArray()); + ObjectInputStream objIn = new ObjectInputStream(bytesIn); + buf = (MText) objIn.readObject(); + oldPlainText = null; + } + catch(IOException e) { + error = e; + } + catch(ClassNotFoundException e) { + error = e; + } + if (error != null) { + error.printStackTrace(); + errln("Streaming problem: " + error); + } + } + break; + + default: + errln("Invalid case."); + } + + // Check time stamp if oldPlainText != null. + // Time stamp should be different iff + // oldPlainText == plainText + if (oldPlainText != null) { + if ((timeStamp==buf.getTimeStamp()) != + oldPlainText.equals(plainText)) { + logln("plainText hashCode: " + plainText.hashCode()); + logln("oldPlainText hashCode: " + oldPlainText.hashCode()); + errln("Time stamp is incorrect"); + } + } + + // now check invariants: + if (plainText.length() != buf.length()) { + errln("Lengths don't match"); + } + + for (int j=0; j < buf.length(); j++) { + if (buf.at(j) != plainText.charAt(j)) { + errln("Characters don't match."); + } + } + + int start; + for (start = 0; start < buf.length();) { + + if (start != buf.characterStyleStart(start)) { + errln("style start is wrong"); + } + int limit = buf.characterStyleLimit(start); + if (start >= limit) { + errln("start >= limit"); + } + char current = plainText.charAt(start); + + AttributeMap comp = null; + if (current == 'p') { + comp = emptyAttrs; + } + else if (current == 'b') { + comp = boldAttrs; + } + else if (current == 'i') { + comp = italicAttrs; + } + else { + errln("An invalid character snuck in!"); + } + + AttributeMap startStyle = buf.characterStyleAt(start); + if (!comp.equals(startStyle)) { + errln("Style is not expected style."); + } + + for (int j = start; j < limit; j++) { + if (plainText.charAt(j) != current) { + errln("Character doesn't match style."); + } + if (buf.characterStyleAt(j) != startStyle) { + errln("Incorrect style in run"); + } + } + + if (limit < buf.length()) { + if (plainText.charAt(limit) == current) { + errln("Style run ends too soon."); + } + } + start = limit; + } + if (start != buf.length()) { + errln("Last limit is not buffer length."); + } + + // won't try to compute and check damaged range; however, + // if nonempty it should always be within text + int damageStart = buf.damagedRangeStart(); + int damageLimit = buf.damagedRangeLimit(); + if (damageStart == Integer.MAX_VALUE) { + if (damageLimit != Integer.MIN_VALUE) { + errln("Invalid empty interval"); + } + } + else { + if (damageStart > damageLimit) { + errln("Damage range inverted"); + } + if (damageStart < 0 || damageLimit > buf.length()) { + errln("Damage range endpoint out of bounds"); + } + } + } + + testIteration = NOT_IN_MONKEY_TEST; + + boolean allCasesExecuted = true; + for (int index=0; index < NUM_CASES; index++) { + allCasesExecuted &= casesExecuted[index]; + if (casesExecuted[index] == false) { + logln("Case " + index + " not executed."); + } + } + //if (allCasesExecuted) { + // logln("All cases executed."); + //} + } +} \ No newline at end of file diff --git a/icu4j/src/com/ibm/richtext/test/unit/TestMTextStreaming.java b/icu4j/src/com/ibm/richtext/test/unit/TestMTextStreaming.java new file mode 100755 index 00000000000..c45cff51fc0 --- /dev/null +++ b/icu4j/src/com/ibm/richtext/test/unit/TestMTextStreaming.java @@ -0,0 +1,162 @@ +/* + * @(#)$RCSfile: TestMTextStreaming.java,v $ $Revision: 1.1 $ $Date: 2000/04/24 20:38:00 $ + * + * (C) Copyright IBM Corp. 1998-1999. All Rights Reserved. + * + * The program is provided "as is" without any warranty express or + * implied, including the warranty of non-infringement and the implied + * warranties of merchantibility and fitness for a particular purpose. + * IBM will not be liable for any damages suffered by you as a result + * of using the Program. In no event will IBM be liable for any + * special, indirect or consequential damages or lost profits even if + * IBM has been advised of the possibility of their occurrence. IBM + * will not be liable for any third party claims against you. + */ +package com.ibm.richtext.tests; + +import com.ibm.test.TestFmwk; + +import java.io.*; +import java.awt.Color; + +import com.ibm.richtext.styledtext.MText; +import com.ibm.richtext.styledtext.StandardTabRuler; +import com.ibm.richtext.styledtext.StyledText; +import com.ibm.richtext.styledtext.StyleModifier; + +import com.ibm.textlayout.attributes.AttributeMap; +import com.ibm.textlayout.attributes.TextAttribute; + +public class TestMTextStreaming extends TestFmwk { + + static final String COPYRIGHT = + "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved"; + + public static void main(String[] args) throws Exception { + + new TestMTextStreaming().run(args); + } + + public TestMTextStreaming() { + } + + public void test() { + + simpleTest(); + allAttributesTest(); + } + + private void simpleTest() { + + AttributeMap style = AttributeMap.EMPTY_ATTRIBUTE_MAP; + MText text = new StyledText("Hello world!", style); + + streamAndCompare(text); + } + + private static class TestModifier extends StyleModifier { + + private Object fKey; + private Object fValue; + + public AttributeMap modifyStyle(AttributeMap style) { + + return style.addAttribute(fKey, fValue); + } + + TestModifier(Object key, Object value) { + + fKey = key; + fValue = value; + } + } + + private void allAttributesTest() { + + AttributeMap style = AttributeMap.EMPTY_ATTRIBUTE_MAP; + MText text = new StyledText("Hello world!", style); + + int length = text.length(); + + final boolean CHARACTER = true; + final boolean PARAGRAPH = false; + + addStyle(text, 0, length/2, TextAttribute.FAMILY, "Times", CHARACTER); + addStyle(text, length/2, length, TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD, CHARACTER); + addStyle(text, 0, length/2, TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE, CHARACTER); + addStyle(text, 0, length/2, TextAttribute.SIZE, new Float(13.7f), CHARACTER); + addStyle(text, length/2, length, TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUB, CHARACTER); + addStyle(text, 0, length/2, TextAttribute.FOREGROUND, Color.blue, CHARACTER); + addStyle(text, 0, length/2, TextAttribute.BACKGROUND, Color.red, CHARACTER); + addStyle(text, 0, length-1, TextAttribute.STRIKETHROUGH, Boolean.TRUE, CHARACTER); + + addStyle(text, 0, length, TextAttribute.EXTRA_LINE_SPACING, new Float(4), PARAGRAPH); + addStyle(text, 0, length, TextAttribute.FIRST_LINE_INDENT, new Float(6), PARAGRAPH); + addStyle(text, 0, length, TextAttribute.MIN_LINE_SPACING, new Float(7), PARAGRAPH); + addStyle(text, 0, length, TextAttribute.LINE_FLUSH, TextAttribute.FLUSH_TRAILING, PARAGRAPH); + addStyle(text, 0, length, TextAttribute.LEADING_MARGIN, new Float(9), PARAGRAPH); + addStyle(text, 0, length, TextAttribute.TRAILING_MARGIN, new Float(9), PARAGRAPH); + addStyle(text, 0, length, TextAttribute.TAB_RULER, new StandardTabRuler(), PARAGRAPH); + + streamAndCompare(text); + } + + private static void addStyle(MText text, + int start, + int limit, + Object key, + Object value, + boolean character) { + + StyleModifier modifier = new TestModifier(key, value); + + if (character) { + text.modifyCharacterStyles(start, limit, modifier); + } + else { + text.modifyParagraphStyles(start, limit, modifier); + } + } + + public void streamAndCompare(MText text) { + + Throwable error = null; + + try { + ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); + ObjectOutputStream objOut = new ObjectOutputStream(bytesOut); + objOut.writeObject(text); + + ByteArrayInputStream bytesIn = + new ByteArrayInputStream(bytesOut.toByteArray()); + ObjectInputStream objIn = new ObjectInputStream(bytesIn); + MText streamedText = (MText) objIn.readObject(); + if (!isEqual(text, streamedText)) { + isEqual(text, streamedText); + errln("Streamed text is not equal"); + } + } +/* catch(OptionalDataException e) { + error = e; + } + catch(StreamCorruptedException e) { + error = e; + }*/ + catch(IOException e) { + error = e; + } + catch(ClassNotFoundException e) { + error = e; + } + + if (error != null) { + error.printStackTrace(); + errln("Serialization failed."); + } + } + + public static boolean isEqual(MText lhs, MText rhs) { + + return lhs.equals(rhs); + } +} \ No newline at end of file diff --git a/icu4j/src/com/ibm/richtext/test/unit/TestParagraphStyles.java b/icu4j/src/com/ibm/richtext/test/unit/TestParagraphStyles.java new file mode 100755 index 00000000000..cc8bdc2396b --- /dev/null +++ b/icu4j/src/com/ibm/richtext/test/unit/TestParagraphStyles.java @@ -0,0 +1,339 @@ +/* + * @(#)$RCSfile: TestParagraphStyles.java,v $ $Revision: 1.1 $ $Date: 2000/04/24 20:38:00 $ + * + * (C) Copyright IBM Corp. 1998-1999. All Rights Reserved. + * + * The program is provided "as is" without any warranty express or + * implied, including the warranty of non-infringement and the implied + * warranties of merchantibility and fitness for a particular purpose. + * IBM will not be liable for any damages suffered by you as a result + * of using the Program. In no event will IBM be liable for any + * special, indirect or consequential damages or lost profits even if + * IBM has been advised of the possibility of their occurrence. IBM + * will not be liable for any third party claims against you. + */ +package com.ibm.richtext.tests; + +import com.ibm.test.TestFmwk; + +import com.ibm.richtext.styledtext.StyledText; +import com.ibm.richtext.styledtext.MConstText; +import com.ibm.richtext.styledtext.MText; +import com.ibm.textlayout.attributes.AttributeMap; +import com.ibm.richtext.styledtext.StyleModifier; +import java.util.Random; + +public final class TestParagraphStyles extends TestFmwk { + + static final String COPYRIGHT = + "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved"; + + public static void main(String[] args) throws Exception { + + new TestParagraphStyles().run(args); + } + + private static final int RAND_SEED = 1234; + private static final int NUM_TESTS = 2500; + + private static final boolean isParagraphBreak(char c) { + + return c =='\u2029' || c == '\n'; + } + + private static final Object KEY = "KEY"; + private static final AttributeMap PLAIN = AttributeMap.EMPTY_ATTRIBUTE_MAP; + private static final AttributeMap A_STYLE = new AttributeMap(KEY, new Character('a')); + private static final StyleModifier A_MOD = + StyleModifier.createReplaceModifier(A_STYLE); + private static final AttributeMap B_STYLE = new AttributeMap(KEY, new Character('b')); + private static final StyleModifier B_MOD = + StyleModifier.createReplaceModifier(B_STYLE); + private static final AttributeMap C_STYLE = new AttributeMap(KEY, new Character('c')); + private static final StyleModifier C_MOD = + StyleModifier.createReplaceModifier(C_STYLE); + private static final AttributeMap D_STYLE = new AttributeMap(KEY, new Character('d')); + private static final StyleModifier D_MOD = + StyleModifier.createReplaceModifier(D_STYLE); + private static final AttributeMap E_STYLE = new AttributeMap(KEY, new Character('e')); + private static final StyleModifier E_MOD = + StyleModifier.createReplaceModifier(E_STYLE); + + public void test() { + + easyTests(); + randomTest(); + } + + private void easyTests() { + + MText text = new StyledText("a\nb\nc\nd\n", PLAIN); + text.modifyParagraphStyles(0, text.length(), A_MOD); + verifyParagraphCount(text); + + MText src = new StyledText("XXX\nYYY", PLAIN); + src.modifyParagraphStyles(0, src.length(), B_MOD); + verifyParagraphCount(src); + + MText temp = text.extractWritable(0, text.length()); + temp.append(src); + verifyParagraphCount(temp); + for (int i=0; i < text.length(); i++) { + if (!temp.paragraphStyleAt(i).equals(text.paragraphStyleAt(i))) { + errln("Paragraph styles are wrong"); + } + } + for (int i=0; i < src.length(); i++) { + if (!temp.paragraphStyleAt(i+text.length()).equals(src.paragraphStyleAt(i))) { + errln("Paragraph styles are wrong"); + } + } + + temp = text.extractWritable(0, text.length()); + temp.replace(0, 1, src, 0, src.length()); + verifyParagraphCount(temp); + if (temp.paragraphLimit(0) != 4) { + errln("Paragraph limit is wrong"); + } + if (!temp.paragraphStyleAt(0).equals(B_STYLE)) { + errln("First style is wrong"); + } + if (!temp.paragraphStyleAt(4).equals(A_STYLE)) { + errln("Style after insert is wrong"); + } + + // test append + MConstText newSrc = src.extract(4, 7); + MText initC = new StyledText("cccccc", PLAIN); + initC.modifyParagraphStyles(0, initC.length(), C_MOD); + initC.append(newSrc); + // now initC should be one paragraph with style B + if (initC.paragraphLimit(0) != initC.length()) { + errln("Should only be one paragraph"); + } + if (initC.paragraphStyleAt(0) != initC.paragraphStyleAt(initC.length())) { + errln("Two different paragraph styles"); + } + if (!initC.paragraphStyleAt(initC.length()/2).equals(B_STYLE)) { + errln("Incorrect paragraph style"); + } + + text = new StyledText("aaa\n", PLAIN); + text.modifyParagraphStyles(0, text.length(), A_MOD); + text.modifyParagraphStyles(text.length(), text.length(), B_MOD); + if (text.paragraphStyleAt(text.length()) != B_STYLE) { + errln("0-length paragraph at end has incorrect style"); + } + } + + private static int randInt(Random rand, int limit) { + + return randInt(rand, 0, limit); + } + + private static int randInt(Random rand, int start, int limit) { + + if (start > limit) { + throw new IllegalArgumentException("Range is 0-length."); + } + else if (start == limit) { + return start; + } + + return start + (Math.abs(rand.nextInt())%(limit-start)) ; + } + + private void randomTest() { + + MText noParagraph = new StyledText("zzzz", PLAIN); + noParagraph.modifyParagraphStyles(0, noParagraph.length(), A_MOD); + MText twoParagraphs = new StyledText("aaa\nbbb", PLAIN); + twoParagraphs.modifyParagraphStyles(0, twoParagraphs.paragraphLimit(0), B_MOD); + MText threeParagraphs = new StyledText("cc\ndd\nee", PLAIN); + threeParagraphs.modifyParagraphStyles(0, 3, C_MOD); + threeParagraphs.modifyParagraphStyles(3, 6, D_MOD); + threeParagraphs.modifyParagraphStyles(6, 8, E_MOD); + MText trailingP1 = new StyledText("hhhh\n", PLAIN); + trailingP1.modifyParagraphStyles(0, trailingP1.paragraphLimit(0), C_MOD); + MText trailingP2 = new StyledText("iii\n", PLAIN); + trailingP2.modifyParagraphStyles(0, 0, D_MOD); + trailingP2.modifyParagraphStyles(trailingP2.length(), trailingP2.length(), B_MOD); + + if (!trailingP2.paragraphStyleAt(trailingP2.length()-1).equals(D_STYLE)) { + errln("Style incorrect in trailingP2"); + } + if (!trailingP2.paragraphStyleAt(trailingP2.length()).equals(B_STYLE)) { + errln("Ending style incorrect in trailingP2"); + } + + MConstText[] tests = { noParagraph, twoParagraphs, + threeParagraphs, trailingP1, trailingP2 }; + + Random random = new Random(RAND_SEED); + + int stopAt = 465; + int i = 0; + try { + for (i=0; i < NUM_TESTS; i++) { + + int srcIndex = randInt(random, tests.length); + int targetIndex = randInt(random, tests.length); + MText target = new StyledText(tests[targetIndex]); + MConstText src = tests[srcIndex]; + + int srcStart = randInt(random, src.length()); + int srcLimit = randInt(random, srcStart, src.length()); + int start = randInt(random, target.length()); + int limit = randInt(random, start, target.length()); + + if (i == stopAt) { + stopAt = i; + } + + insertAndCheck(src, srcStart, srcLimit, target, start, limit); + } + } + finally { + if (i < NUM_TESTS) { + logln("iteration=" + i); + } + } + } + + private void insertAndCheck(MConstText src, int srcStart, int srcLimit, + MText target, int start, int limit) { + + // p-style after insertion + AttributeMap after; + if (limit == target.length() && srcLimit > srcStart) { + after = src.paragraphStyleAt(srcLimit); + } + else { + after = target.paragraphStyleAt(limit); + } + + AttributeMap before; + boolean srcHasPBreak = false; + for (int i=srcStart; i < srcLimit; i++) { + if (isParagraphBreak(src.at(i))) { + srcHasPBreak = true; + break; + } + } + + if (start > 0 && isParagraphBreak(target.at(start-1))) { + before = target.paragraphStyleAt(start-1); + } + else { + before = srcHasPBreak? src.paragraphStyleAt(srcStart) : after; + } + boolean stylePropogated = !before.equals(target.paragraphStyleAt(Math.max(0, start-1))); + + + target.resetDamagedRange(); + target.replace(start, limit, src, srcStart, srcLimit); + final int damageLimit = (start==limit && srcStart==srcLimit)? + Integer.MIN_VALUE : start + (srcLimit-srcStart); + + if (target.damagedRangeLimit() != damageLimit) { + logln("limit: " + damageLimit + "; target.limit: " + + target.damagedRangeLimit()); + errln("Damaged range limit is incorrect"); + } + + final int damageStart = (damageLimit==Integer.MIN_VALUE)? Integer.MAX_VALUE : + (stylePropogated? target.paragraphStart(Math.max(0, start-1)) : start); + if (target.damagedRangeStart() > damageStart) { + logln("start: " + damageStart + "; target.start: " + + target.damagedRangeStart()); + errln("Damaged range start is incorrect"); + } + + verifyParagraphCount(target); + + // check endpoints + if (!before.equals(target.paragraphStyleAt(Math.max(start-1, 0)))) { + errln("Incorrect paragraph style before modified range"); + } + + int lengthDelta = (srcLimit-srcStart) - (limit-start); + int indexAfterInsert = Math.min(target.length(), limit + lengthDelta); + if (!after.equals(target.paragraphStyleAt(indexAfterInsert))) { + errln("Incorrect paragraph style after modified range"); + } + + if (srcHasPBreak) { + int startP = target.paragraphLimit(start); + int limitOfTest = target.paragraphStart(indexAfterInsert); + + int offset = start - srcStart; + + while (startP < limitOfTest) { + int limitP = target.paragraphLimit(startP); + if (src.paragraphLimit(startP-offset) + offset != limitP) { + errln("paragraph limits are not consistent"); + } + if (!src.paragraphStyleAt(startP-offset) + .equals(target.paragraphStyleAt(startP))) { + errln("paragraph styles are not consistent"); + } + startP = limitP; + } + } + else { + for (int i=start; i < start+(srcLimit-srcStart); i++) { + if (!after.equals(target.paragraphStyleAt(i))) { + errln("paragraph style changed unexpectedly"); + } + } + } + } + + private void verifyParagraphCount(MConstText text) { + + int pCount = 0; + int textLength = text.length(); + + if (textLength == 0) { + pCount = 1; + } + else { + for (int s=0; s < textLength; s = text.paragraphLimit(s)) { + pCount++; + } + if (isParagraphBreak(text.at(textLength-1))) { + pCount++; + } + } + + int sepCount = 0; + for (int i=0; i < textLength; i++) { + if (isParagraphBreak(text.at(i))) { + sepCount++; + } + } + + if (sepCount + 1 != pCount) { + logln("sepCount=" + sepCount + "; pCount=" + pCount); + errln("Paragraph count is not consistent with characters"); + } + } + + private void checkEndpoint(MConstText text) { + + boolean emptyFinalParagraph; + int length = text.length(); + + if (length != 0) { + char ch = text.at(length-1); + emptyFinalParagraph = isParagraphBreak(ch); + } + else { + emptyFinalParagraph = true; + } + + if ((text.paragraphStart(length) == length) != emptyFinalParagraph) { + errln("Final paragraph length is incorrect"); + } + } +} \ No newline at end of file diff --git a/icu4j/src/com/ibm/test/richtext/TestAll.java b/icu4j/src/com/ibm/test/richtext/TestAll.java new file mode 100755 index 00000000000..0c815806c70 --- /dev/null +++ b/icu4j/src/com/ibm/test/richtext/TestAll.java @@ -0,0 +1,55 @@ +/* + * @(#)$RCSfile: TestAll.java,v $ $Revision: 1.1 $ $Date: 2000/04/24 20:38:00 $ + * + * (C) Copyright IBM Corp. 1998-1999. All Rights Reserved. + * + * The program is provided "as is" without any warranty express or + * implied, including the warranty of non-infringement and the implied + * warranties of merchantibility and fitness for a particular purpose. + * IBM will not be liable for any damages suffered by you as a result + * of using the Program. In no event will IBM be liable for any + * special, indirect or consequential damages or lost profits even if + * IBM has been advised of the possibility of their occurrence. IBM + * will not be liable for any third party claims against you. + */ +package com.ibm.richtext.tests; + +import com.ibm.test.TestFmwk; + +public class TestAll extends TestFmwk { + + static final String COPYRIGHT = + "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved"; + + public static void main(String[] args) throws Exception { + new TestAll().run(args); + } + + public void TestAttributeSet() throws Exception { + run(new TestAttributeSet()); + } + + public void TestAttributeMap() throws Exception { + run(new TestAttributeMap()); + } + + public void TestFormatter() throws Exception { + run(new TestFormatter()); + } + + public void TestMText() throws Exception { + run(new TestMText()); + } + + public void TestParagraphStyles() throws Exception { + run(new TestParagraphStyles()); + } + + public void TestMTextStreaming() throws Exception { + run(new TestMTextStreaming()); + } + + public void TestTextPanel() throws Exception { + run(new TestTextPanel()); + } +} \ No newline at end of file diff --git a/icu4j/src/com/ibm/test/richtext/TestAttributeMap.java b/icu4j/src/com/ibm/test/richtext/TestAttributeMap.java new file mode 100755 index 00000000000..cc8f7f44f6f --- /dev/null +++ b/icu4j/src/com/ibm/test/richtext/TestAttributeMap.java @@ -0,0 +1,409 @@ +/* + * @(#)$RCSfile: TestAttributeMap.java,v $ $Revision: 1.1 $ $Date: 2000/04/24 20:38:00 $ + * + * (C) Copyright IBM Corp. 1998-1999. All Rights Reserved. + * + * The program is provided "as is" without any warranty express or + * implied, including the warranty of non-infringement and the implied + * warranties of merchantibility and fitness for a particular purpose. + * IBM will not be liable for any damages suffered by you as a result + * of using the Program. In no event will IBM be liable for any + * special, indirect or consequential damages or lost profits even if + * IBM has been advised of the possibility of their occurrence. IBM + * will not be liable for any third party claims against you. + */ +package com.ibm.richtext.tests; + +import com.ibm.test.TestFmwk; + +import com.ibm.textlayout.attributes.AttributeSet; +import com.ibm.textlayout.attributes.TextAttribute; +import com.ibm.textlayout.attributes.Map; +import com.ibm.textlayout.attributes.AttributeMap; +import java.util.Enumeration; + +// Java2 imports +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; +import java.util.Map.Entry; + + +public class TestAttributeMap extends TestFmwk { + + static final String COPYRIGHT = + "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved"; + + + // There are JDK 1.1 versions of AttributeMap and AttributeSet. + // Some of the tests in this class require Java 2 API's. I have + // tried to isolate these tests by conditionalizing them on + // this static variable. If you are back-porting to 1.1, remove + // the Java 2 tests ONLY. + private static final boolean gJDK11 = false; + + public static void main(String[] args) throws Exception { + + new TestAttributeMap().run(args); + } + + private AttributeSet maps; // A Set of AttributeMaps + private AttributeSet sets; // A Set of Sets + + private static final class TestAttribute extends TextAttribute { + + TestAttribute(String name) { + super(name); + } + } + + private static final TestAttribute[] attributes = { + new TestAttribute("0"), new TestAttribute("1"), new TestAttribute("2") + }; + + private static final Object[] values = { + "Hello world", new Float(-42), new Object(), new AttributeMap(new TestAttribute("3"), "HH") + }; + + /** + * Returns lhs.equals(rhs) - but also checks for symmetry, and + * consistency with hashCode(). + */ + private boolean equalMaps(AttributeMap lhs, Object rhs) { + + boolean equal = lhs.equals(rhs); + if (equal != (rhs.equals(lhs))) { + errln("AttributeMap.equals is not symetric"); + } + if (equal) { + if (lhs.hashCode() != rhs.hashCode()) { + errln("AttributeMaps are equal but hashCodes differ"); + } + } + return equal; + } + + public TestAttributeMap() { + + maps = AttributeSet.EMPTY_SET; + maps = maps.addElement(AttributeMap.EMPTY_ATTRIBUTE_MAP); + maps.addElement(new AttributeMap(TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUB)); + maps.addElement(new AttributeMap(TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUPER)); + + for (int i=0; i < attributes.length; i++) { + for (int j=0; j < values.length; j++) { + maps = maps.addElement(new AttributeMap(attributes[i], values[j])); + } + } + + AttributeMap bigMap = new AttributeMap(new TestAttribute("4"), "value"); + for (int i=0; i < Math.min(attributes.length, values.length); i++) { + bigMap = bigMap.addAttribute(attributes[i], values[values.length-i-1]); + } + maps = maps.addElement(bigMap); + + sets = AttributeSet.EMPTY_SET; + + sets = new AttributeSet(AttributeSet.EMPTY_SET); + + for (int i=0; i < attributes.length; i++) { + AttributeSet newSet = new AttributeSet(attributes[i]); + sets = sets.addElement(newSet); + } + + AttributeSet allAttrs = AttributeSet.EMPTY_SET; + for (int i=0; i < attributes.length; i++) { + allAttrs = allAttrs.addElement(attributes[i]); + } + + sets = sets.addElement(allAttrs); + } + + /** + * Run tests on AttributeMap. If a test fails an exception will propogate out + * of this method. + */ + public void test() { + + easyTests(); + + Enumeration mapIter = maps.elements(); + while (mapIter.hasMoreElements()) { + + AttributeMap testMap = (AttributeMap) mapIter.nextElement(); + + _testModifiers(testMap); + _testViews(testMap); + + Enumeration unionIter = maps.elements(); + while (unionIter.hasMoreElements()) { + _testUnionWith(testMap, (AttributeMap) unionIter.nextElement()); + } + + Enumeration setIter = sets.elements(); + while (setIter.hasMoreElements()) { + AttributeSet testSet = (AttributeSet) setIter.nextElement(); + _testIntersectWith(testMap, testSet); + _testRemoveAttributes(testMap, testSet); + } + } + } + + /** + * Invoke modifiers on map. All should throw + * UnsupportedOperationException, and leave map unmodified. + */ + void _testModifiers(AttributeMap map) { + + if (gJDK11) { + return; + } + + AttributeMap originalMap = new AttributeMap(map); + + try { + map.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); + errln("Put should throw UnsupportedOperationException."); + } + catch(UnsupportedOperationException e) { + } + + try { + Object key = TextAttribute.WEIGHT; + Iterator iter = map.keySet().iterator(); + if (iter.hasNext()) { + key = iter.next(); + } + map.remove(key); + errln("Set should throw UnsupportedOperationException."); + } + catch(UnsupportedOperationException e) { + } + + try { + map.putAll(map); + errln("putAll should throw UnsupportedOperationException."); + } + catch(UnsupportedOperationException e) { + } + + try { + map.clear(); + errln("clear should throw UnsupportedOperationException."); + } + catch(UnsupportedOperationException e) { + } + + if (!originalMap.equals(map)) { + errln("Modifiers changed map."); + } + } + + /** + * Ensure that map.addAttributes(addMap) is equivalent to calling + * map.add on all of addMap's entries. + */ + void _testUnionWith(AttributeMap map, AttributeMap addMap) { + + AttributeMap lhs = map.addAttributes(addMap); + + AttributeMap rhs = map; + + Enumeration iter = addMap.getKeySet().elements(); + while (iter.hasMoreElements()) { + Object attr = iter.nextElement(); + Object value = addMap.get(attr); + rhs = rhs.addAttribute(attr, value); + } + + if (!equalMaps(lhs, rhs)) { + errln("Maps are not equal."); + } + } + + /** + * Ensure that map.removeAttributes(remove) is equivalent to calling + * map.removeAttribute on remove's elements. + */ + void _testRemoveAttributes(AttributeMap map, AttributeSet remove) { + + AttributeMap lhs = map.removeAttributes(remove); + + AttributeMap rhs = map; + + Enumeration iter = remove.elements(); + while (iter.hasMoreElements()) { + Object attr = iter.nextElement(); + rhs = rhs.removeAttribute(attr); + } + + if (!equalMaps(lhs, rhs)) { + errln("Maps are not equal."); + } + } + + /** + * Ensure that map.intersectWith(intersect) is equivalent to + * map.removeAttributes(map.keySet() - intersect); + */ + void _testIntersectWith(AttributeMap map, AttributeSet intersect) { + + AttributeMap lhs = map.intersectWith(intersect); + + AttributeSet keySet = map.getKeySet(); + AttributeSet removeSet = keySet.subtract(intersect); + AttributeMap rhs = map.removeAttributes(removeSet); + + if (!equalMaps(lhs, rhs)) { + map.intersectWith(intersect); + logln("intersect: " + intersect); + logln("keySet: " + keySet); + logln("removeSet: " + removeSet); + logln("map: " + map); + logln("lhs: " + lhs); + logln("rhs: " + rhs); + errln("Maps are not equal."); + } + } + + /** + * Ensure that: + * map, map.keySet(), and map.entrySet() are the same size; + * map.containsKey() is true for every key in keySet(); + * map.containsValue() is true for every value in values; + * every entry key is in keySet, every entry value is in map.values(); + * map.get() is consistent with entry's key, value; + * sum of hashcodes of entries equals map.hashCode(). + */ + void _testViews(AttributeMap map) { + + AttributeSet keySet = map.getKeySet(); + + Enumeration keyIter = keySet.elements(); + while (keyIter.hasMoreElements()) { + if (!map.containsKey(keyIter.nextElement())) { + errln("keySet contains key not in map"); + } + } + + if (gJDK11) { + return; + } + + Collection values = map.values(); + Set entrySet = map.entrySet(); + + if (keySet.size() != map.size() || entrySet.size() != map.size()) { + errln("Set sizes are inconsistent with map size."); + } + + int hashCode = 0; + + Iterator valueIter = values.iterator(); + while (valueIter.hasNext()) { + if (!map.containsValue(valueIter.next())) { + errln("value set contains value not in map"); + } + } + + Iterator entryIter = entrySet.iterator(); + while (entryIter.hasNext()) { + + Entry entry = (Entry) entryIter.next(); + + Object key = entry.getKey(); + if (!keySet.contains(key)) { + errln("Entry key is not in key set."); + } + + Object value = map.get(entry.getKey()); + if (!values.contains(value)) { + errln("Entry value is not in value set."); + } + + if (map.get(key) != value) { + errln("map.get did not return entry value."); + } + + hashCode += entry.hashCode(); + } + + if (hashCode != map.hashCode()) { + errln("map hashcode is not sum of entry hashcodes."); + } + } + + /** + * Look for correct behavior in obvious cases. + */ + void easyTests() { + + AttributeMap map = new AttributeMap(); + if (!map.equals(AttributeMap.EMPTY_ATTRIBUTE_MAP)) { + errln("Default-constructed map is not equal to empty map."); + } + + map = map.addAttribute(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); + Object otherMap = new AttributeMap(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); + if (!map.equals(otherMap)) { + errln("Maps are inconsistent after map.add"); + } + + otherMap = map.addAttributes(map); + if (!equalMaps(map,otherMap)) { + errln("Maps are inconsistent after addAttributes"); + } + + map = map.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); + + if (map.size() != 2) { + errln("Map size is wrong. map="+map); + } + + if (equalMaps(map,otherMap)) { + errln("Maps should not be equal"); + } + + Object posture = new Float(0); + map = map.addAttribute(TextAttribute.POSTURE, posture); + + if (map.size() != 2) { + errln("Map size is wrong"); + } + + if (!map.get(TextAttribute.POSTURE).equals(posture)) { + errln("Map element is wrong"); + } + + map = map.removeAttribute(TextAttribute.UNDERLINE); + + if (map.size() != 1) { + errln("Map size is wrong"); + } + + if (map.get(TextAttribute.UNDERLINE) != null) { + errln("Map should not have element"); + } + + // map has POSTURE_REGULAR. If we addAttributes a map with + // POSTURE_ITALIC the new map should have POSTURE_ITALIC + + map = map.addAttributes(new AttributeMap(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE)); + if (map.get(TextAttribute.POSTURE) != TextAttribute.POSTURE_OBLIQUE) { + errln("Map element is wrong"); + } + + _testModifiers(map); + _testViews(map); + + Enumeration mapIter = maps.elements(); + while (mapIter.hasMoreElements()) { + AttributeMap testMap = (AttributeMap) mapIter.nextElement(); + Object newValue = new Object(); + AttributeMap newMap = testMap.addAttribute(attributes[0], newValue); + if (newMap.get(attributes[0]) != newValue) { + errln("Did not get expected value back. map=" + map); + } + } + } +} \ No newline at end of file diff --git a/icu4j/src/com/ibm/test/richtext/TestAttributeSet.java b/icu4j/src/com/ibm/test/richtext/TestAttributeSet.java new file mode 100755 index 00000000000..497e62024fe --- /dev/null +++ b/icu4j/src/com/ibm/test/richtext/TestAttributeSet.java @@ -0,0 +1,91 @@ +/* + * @(#)$RCSfile: TestAttributeSet.java,v $ $Revision: 1.1 $ $Date: 2000/04/24 20:38:00 $ + * + * (C) Copyright IBM Corp. 1998-1999. All Rights Reserved. + * + * The program is provided "as is" without any warranty express or + * implied, including the warranty of non-infringement and the implied + * warranties of merchantibility and fitness for a particular purpose. + * IBM will not be liable for any damages suffered by you as a result + * of using the Program. In no event will IBM be liable for any + * special, indirect or consequential damages or lost profits even if + * IBM has been advised of the possibility of their occurrence. IBM + * will not be liable for any third party claims against you. + */ +package com.ibm.richtext.tests; + +import com.ibm.test.TestFmwk; +import com.ibm.textlayout.attributes.AttributeSet; +import java.util.Enumeration; + +public class TestAttributeSet extends TestFmwk { + + static final String COPYRIGHT = + "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved"; + + public static void main(String[] args) throws Exception { + + new TestAttributeSet().run(args); + } + + public void test() { + + final Object elem1 = new Object(); + final Object elem2 = new Float(4); + final Object elem3 = "String"; + final Object elem4 = Boolean.FALSE; + + AttributeSet set1 = new AttributeSet(new Object[] {elem1, elem2, elem3}); + if (set1.size() != 3) { + errln("Size is wrong."); + } + + if (set1.contains(elem4)){ + errln("Set contents are wrong."); + } + + if (!set1.contains(elem1)) { + errln("Set contents are wrong."); + } + + AttributeSet set2 = new AttributeSet(elem4); + + if (set2.size() != 1) { + errln("Size is wrong."); + } + + if (!set2.contains(elem4)){ + errln("Set contents are wrong."); + } + + if (set2.contains(elem1)) { + errln("Set contents are wrong."); + } + + Enumeration iter = set2.elements(); + if (!iter.nextElement().equals(elem4)) { + errln("Invalid object in iterator."); + } + + AttributeSet union = set2.unionWith(set1); + if (!set1.unionWith(set2).equals(union)) { + errln("unionWith is not commutative."); + } + + if (!union.contains(elem1) || !union.contains(elem4)) { + errln("Set contents are wrong."); + } + + if (!set1.addElement(elem4).equals(union)) { + errln("addElement is wrong."); + } + + if (!union.intersectWith(set1).equals(set1)) { + errln("intersectWith is wrong."); + } + + if (!union.subtract(set1).equals(set2)) { + errln("subtract is wrong."); + } + } +} \ No newline at end of file diff --git a/icu4j/src/com/ibm/test/richtext/TestFormatter.java b/icu4j/src/com/ibm/test/richtext/TestFormatter.java new file mode 100755 index 00000000000..8f264fc1974 --- /dev/null +++ b/icu4j/src/com/ibm/test/richtext/TestFormatter.java @@ -0,0 +1,250 @@ +/* + * @(#)$RCSfile: TestFormatter.java,v $ $Revision: 1.1 $ $Date: 2000/04/24 20:38:00 $ + * + * (C) Copyright IBM Corp. 1998-1999. All Rights Reserved. + * + * The program is provided "as is" without any warranty express or + * implied, including the warranty of non-infringement and the implied + * warranties of merchantibility and fitness for a particular purpose. + * IBM will not be liable for any damages suffered by you as a result + * of using the Program. In no event will IBM be liable for any + * special, indirect or consequential damages or lost profits even if + * IBM has been advised of the possibility of their occurrence. IBM + * will not be liable for any third party claims against you. + */ +package com.ibm.richtext.tests; + +import com.ibm.test.TestFmwk; + +import com.ibm.textlayout.attributes.AttributeMap; +import com.ibm.textlayout.attributes.TextAttribute; +import com.ibm.richtext.styledtext.MText; +import com.ibm.richtext.styledtext.MConstText; +import com.ibm.richtext.styledtext.StandardTabRuler; +import com.ibm.richtext.styledtext.StyledText; + +import com.ibm.richtext.textformat.TextOffset; +import com.ibm.richtext.textformat.MFormatter; + +import java.awt.Color; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.image.BufferedImage; + +import java.util.Hashtable; + +public final class TestFormatter extends TestFmwk { + + static final String COPYRIGHT = + "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved"; + public static void main(String[] args) throws Exception { + + new TestFormatter().run(args); + } + + private static final Point ORIGIN = new Point(0, 0); + + private static final AttributeMap DEFAULTS; + static { + final Float floatZero = new Float(0.0f); + + Hashtable defaults = new Hashtable(); + defaults.put(TextAttribute.FAMILY, "Serif"); + defaults.put(TextAttribute.WEIGHT, new Float(1.0f)); + defaults.put(TextAttribute.POSTURE, floatZero); + defaults.put(TextAttribute.SIZE, new Float(18.0f)); + defaults.put(TextAttribute.SUPERSCRIPT, new Integer(0)); + defaults.put(TextAttribute.FOREGROUND, Color.black); + defaults.put(TextAttribute.UNDERLINE, new Integer(-1)); + defaults.put(TextAttribute.STRIKETHROUGH, Boolean.FALSE); + + defaults.put(TextAttribute.EXTRA_LINE_SPACING, floatZero); + defaults.put(TextAttribute.FIRST_LINE_INDENT, floatZero); + defaults.put(TextAttribute.MIN_LINE_SPACING, floatZero); + defaults.put(TextAttribute.LINE_FLUSH, TextAttribute.FLUSH_LEADING); + defaults.put(TextAttribute.LEADING_MARGIN, floatZero); + defaults.put(TextAttribute.TRAILING_MARGIN, floatZero); + defaults.put(TextAttribute.TAB_RULER, new StandardTabRuler()); + + DEFAULTS = new AttributeMap(defaults); + } + + // arg to testLineExceptions + private static final int UNKNOWN = -1; + + private Graphics fGraphics; + + public TestFormatter() { + + fGraphics = new BufferedImage(100, 100, BufferedImage.TYPE_3BYTE_BGR).getGraphics(); + + //JDK 1.1: + //Frame f = new Frame(); + //f.show(); + //fGraphics = f.getGraphics(); + } + + private String fiveLines = "a\nb\nc\nd\ne"; + private String twelveLines = fiveLines + "\n" + fiveLines + "\nf\n"; + AttributeMap PLAIN = AttributeMap.EMPTY_ATTRIBUTE_MAP; + + public void test() { + + MConstText text = new StyledText(fiveLines, PLAIN); + _testLineExceptions(makeFormatter(text, 100, true), 5); + _testLineAccess(makeFormatter(text, 100, true), 5); + + text = new StyledText(twelveLines, PLAIN); + _testLineExceptions(makeFormatter(text, 3, false), 12); + _testLineAccess(makeFormatter(text, 100, true), 12); + + _testWithModification(); + } + + private void _testWithModification() { + + MText text = new StyledText(fiveLines, PLAIN); + MFormatter formatter = makeFormatter(text, 100, true); + Rectangle viewRect = new Rectangle(0, 0, 100, Integer.MAX_VALUE); + + formatter.stopBackgroundFormatting(); + text.append(new StyledText("\n", PLAIN)); + formatter.updateFormat(text.length()-1, 1, viewRect, ORIGIN); + + _testLineAccess(formatter, 6); + + formatter.stopBackgroundFormatting(); + text.append(new StyledText("ad", PLAIN)); + formatter.updateFormat(text.length()-2, 2, viewRect, ORIGIN); + _testLineAccess(formatter, 6); + _testLineExceptions(formatter, 6); + + formatter.stopBackgroundFormatting(); + text.remove(0, 1); + formatter.updateFormat(0, 0, viewRect, ORIGIN); + _testLineAccess(formatter, 6); + _testLineExceptions(formatter, 6); + } + + + private MFormatter makeFormatter(MConstText text, + int lineBound, + boolean wrap) { + + return MFormatter.createFormatter(text, + DEFAULTS, + lineBound, + wrap, + fGraphics); + } + + private void _testLineExceptions(MFormatter formatter, + int numLines) { + + if (numLines == UNKNOWN) { + numLines = formatter.getLineCount(); + } + + boolean caught = false; + + try { + formatter.lineRangeLow(numLines); + } + catch(IllegalArgumentException e) { + caught = true; + } + + if (!caught) { + errln("Didn't get exception"); + } + caught = false; + + try { + formatter.lineRangeLimit(numLines); + } + catch(IllegalArgumentException e) { + caught = true; + } + + if (!caught) { + errln("Didn't get exception"); + } + caught = false; + + try { + formatter.lineGraphicStart(numLines+1); + } + catch(IllegalArgumentException e) { + caught = true; + } + + if (!caught) { + errln("Didn't get exception"); + } + caught = false; + } + + private void _testLineAccess(MFormatter formatter, + int numLines) { + + if (numLines == UNKNOWN) { + numLines = formatter.getLineCount(); + } + + if (formatter.lineGraphicStart(0) != 0) { + errln("Line 0 doesn't start at height 0"); + } + if (formatter.lineRangeLow(0) != 0) { + errln("Line 0 doesn't start at character 0"); + } + + int lastLimit = formatter.lineRangeLimit(0); + final int lineBound = formatter.lineBound(); + int[] hitX = new int[] { -1, 1, lineBound + 2 }; + + TextOffset offset = new TextOffset(); + + for (int i=1; i < numLines; i++) { + + int height = formatter.lineGraphicStart(i); + if (lastLimit != formatter.lineRangeLow(i)) { + errln("lastLine limit is not current line start"); + } + int limit = formatter.lineRangeLimit(i); + + if (limit < lastLimit || (limit == lastLimit && i != numLines-1)) { + errln("line has negative or 0 length"); + } + + int nextHeight = formatter.lineGraphicStart(i+1); + if (nextHeight <= height) { + errln("0-height line"); + } + int incAmount = Math.max((nextHeight-height)/4, 1); + for (int hitY = height; hitY < nextHeight; hitY += incAmount) { + + if (formatter.lineAtHeight(hitY) != i) { + errln("lineAtHeight is wrong"); + } + + for (int j=0; j < hitX.length; j++) { + offset = formatter.pointToTextOffset(offset, + hitX[j], hitY, ORIGIN, null, false); + if (offset.fOffset < lastLimit || offset.fOffset > limit) { + errln("Inconsistent offset from pointToTextOffset"); + } + //if (formatter.lineContaining(offset) != i) { + // int debug = formatter.lineContaining(offset); + // errln("lineContaining is incorrect"); + //} + } + } + + lastLimit = limit; + } + } +} \ No newline at end of file diff --git a/icu4j/src/com/ibm/test/richtext/TestMText.java b/icu4j/src/com/ibm/test/richtext/TestMText.java new file mode 100755 index 00000000000..413f97aaf2d --- /dev/null +++ b/icu4j/src/com/ibm/test/richtext/TestMText.java @@ -0,0 +1,721 @@ +/* + * @(#)$RCSfile: TestMText.java,v $ $Revision: 1.1 $ $Date: 2000/04/24 20:38:00 $ + * + * (C) Copyright IBM Corp. 1998-1999. All Rights Reserved. + * + * The program is provided "as is" without any warranty express or + * implied, including the warranty of non-infringement and the implied + * warranties of merchantibility and fitness for a particular purpose. + * IBM will not be liable for any damages suffered by you as a result + * of using the Program. In no event will IBM be liable for any + * special, indirect or consequential damages or lost profits even if + * IBM has been advised of the possibility of their occurrence. IBM + * will not be liable for any third party claims against you. + */ +package com.ibm.richtext.tests; + +import com.ibm.test.TestFmwk; + +import com.ibm.textlayout.attributes.AttributeMap; +import com.ibm.textlayout.attributes.TextAttribute; + +import com.ibm.richtext.styledtext.MConstText; +import com.ibm.richtext.styledtext.MText; +import com.ibm.richtext.styledtext.StyledText; +import com.ibm.richtext.styledtext.StyleModifier; + +import java.text.CharacterIterator; +import java.util.Random; + +import java.io.*; + +public class TestMText extends TestFmwk { + + static final String COPYRIGHT = + "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved"; + public static void main(String[] args) throws Exception { + + new TestMText().run(args); + } + + private static final int TEST_ITERATIONS = 5000; + private static final int STYLE_TEST_ITERATIONS = 5000; + private static final long RAND_SEED = 598436; + + private static final int NOT_IN_MONKEY_TEST = -5000; + private int testIteration = NOT_IN_MONKEY_TEST; + private int theCase = NOT_IN_MONKEY_TEST; + + private static StyleModifier createMinusModifier(final Object attr) { + return new StyleModifier() { + public AttributeMap modifyStyle(AttributeMap style) { + return style.removeAttribute(attr); + } + }; + } + + public void test() { + + simpleTest(); + styleTest(); + monkeyTest(true); + } + + public void simpleTest() { + + AttributeMap boldStyle = new AttributeMap(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); + AttributeMap italicStyle = new AttributeMap(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); + + MConstText allBold = new StyledText("bbbbb", boldStyle); + MConstText allItalic = new StyledText("iii", italicStyle); + MConstText plain = new StyledText("pppppp", AttributeMap.EMPTY_ATTRIBUTE_MAP); + + { + MText buf = new StyledText(); + int ts = buf.getTimeStamp(); + buf.append(allBold); + buf.append(allItalic); + + if (ts == buf.getTimeStamp()) { + errln("Time stamp not incremented"); + } + + // should be bbbbbiii now + + if (buf.length() != allBold.length() + allItalic.length()) { + errln("Length is wrong."); + } + + for (int i=0; i < buf.length(); i++) { + + char rightChar; + AttributeMap rightStyle; + + if (i < allBold.length()) { + rightChar = allBold.at(0); + rightStyle = boldStyle; + } + else { + rightChar = allItalic.at(0); + rightStyle = italicStyle; + } + + if (buf.at(i) != rightChar) { + errln("Character is wrong."); + } + if (!buf.characterStyleAt(i).equals(rightStyle)) { + errln("Style is wrong."); + } + } + + int pos = 0; + + if (!buf.characterStyleAt(pos).equals(boldStyle)) { + errln("First style is wrong."); + } + if (buf.characterStyleLimit(pos) != allBold.length()) { + errln("Run length is wrong."); + } + + pos = allBold.length(); + + if (!buf.characterStyleAt(pos).equals(italicStyle)) { + errln("Second style is wrong."); + } + if (buf.characterStyleLimit(pos) != buf.length()) { + errln("Run length is wrong."); + } + + { + buf.resetDamagedRange(); + int oldLength = buf.length(); + buf.replace(buf.length(), buf.length(), allBold, 0, allBold.length()); + // bbbbbiiibbbbb + + if (buf.damagedRangeStart() != oldLength) { + errln("Damaged range start is incorrect"); + } + if (buf.damagedRangeLimit() != buf.length()) { + errln("Damaged range limit is incorrect"); + } + } + + int start = allBold.length(); + int limit = start + allItalic.length(); + buf.remove(start, limit); + // bbbbbbbbbb + + if (buf.length() != 2 * allBold.length()) { + errln("Text should be twice the length of bold text."); + } + + pos = buf.length() / 2; + if (buf.characterStyleStart(pos) != 0 || + buf.characterStyleLimit(pos) != buf.length()) { + errln("Run range is wrong."); + } + if (!buf.characterStyleAt(pos).equals(boldStyle)) { + errln("Run style is wrong."); + } + + ts = buf.getTimeStamp(); + CharacterIterator cIter = buf.createCharacterIterator(); + for (char ch = cIter.first(); ch != cIter.DONE; ch = cIter.next()) { + if (ch != allBold.at(0)) { + errln("Character is wrong."); + } + } + + if (ts != buf.getTimeStamp()) { + errln("Time stamp should not have changed"); + } + + buf.replace(0, 1, plain, 0, plain.length()); + + if (ts == buf.getTimeStamp()) { + errln("Time stamp not incremented"); + } + + // ppppppbbbbbbbbb + buf.replace(plain.length(), buf.length(), allItalic, 0, allItalic.length()); + // ppppppiii + + if (buf.length() != allItalic.length()+plain.length()) { + errln("Length is wrong."); + } + + pos = 0; + if (buf.characterStyleLimit(pos) != plain.length()) { + errln("Run limit is wrong."); + } + + pos = plain.length(); + if (buf.characterStyleLimit(pos) != buf.length()) { + errln("Run limit is wrong."); + } + + buf.replace(plain.length(), plain.length(), allBold, 0, allBold.length()); + // ppppppbbbbbiii + + AttributeMap st = buf.characterStyleAt(1); + if (!st.equals(AttributeMap.EMPTY_ATTRIBUTE_MAP)) { + errln("Style is wrong."); + } + if (buf.characterStyleStart(1) != 0 || buf.characterStyleLimit(1) != plain.length()) { + errln("Style start is wrong."); + } + + st = buf.characterStyleAt(buf.length() - 1); + if (!st.equals(italicStyle)) { + errln("Style is wrong."); + } + if (buf.characterStyleStart(buf.length() - 1) != plain.length()+allBold.length()) { + errln("Style start is wrong."); + } + + if (buf.characterStyleLimit(buf.length() - 1) != buf.length()) { + errln("Style limit is wrong."); + } + } + } + + private static int randInt(Random rand, int limit) { + + return randInt(rand, 0, limit); + } + + private static int randInt(Random rand, int start, int limit) { + + if (start > limit) { + throw new IllegalArgumentException("Range length is negative."); + } + else if (start == limit) { + return start; + } + + return start + (Math.abs(rand.nextInt())%(limit-start)) ; + } + + public void styleTest() { + + MText text = new StyledText("0123456789", AttributeMap.EMPTY_ATTRIBUTE_MAP); + + AttributeMap[] styles = new AttributeMap[text.length()]; + for (int i=0; i < styles.length; i++) { + styles[i] = AttributeMap.EMPTY_ATTRIBUTE_MAP; + } + AttributeMap[] oldStyles = new AttributeMap[styles.length]; + System.arraycopy(styles, 0, oldStyles, 0, styles.length); + + AttributeMap bigStyle = new AttributeMap(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON). + addAttribute(TextAttribute.SIZE, new Float(23.0f)); + + StyleModifier[] modifiers = { + StyleModifier.createReplaceModifier(new AttributeMap(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD)), + StyleModifier.createAddModifier(new AttributeMap(TextAttribute.WEIGHT, new Float(1.0f))), + createMinusModifier(TextAttribute.WEIGHT), + + StyleModifier.createAddModifier(new AttributeMap(TextAttribute.POSTURE, new Float(0.0f))), + StyleModifier.createReplaceModifier(new AttributeMap(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE)), + createMinusModifier(TextAttribute.POSTURE), + + StyleModifier.createAddModifier(bigStyle), + StyleModifier.createReplaceModifier(bigStyle), + createMinusModifier(bigStyle.getKeySet()) + }; + + Random rand = new Random(RAND_SEED); + final int stopAt = 4; + + for (int testIteration=0; testIteration < STYLE_TEST_ITERATIONS + 1; testIteration++) { + + System.arraycopy(styles, 0, oldStyles, 0, styles.length); + + int startingAt = Integer.MAX_VALUE; + int endingAt = Integer.MIN_VALUE; + int oldTs = text.getTimeStamp(); + + // hack way to do an invariant check before starting... + if (testIteration != 0) { + // modify styles + text.resetDamagedRange(); + startingAt = randInt(rand, styles.length+1); + endingAt = randInt(rand, startingAt, styles.length+1); + StyleModifier modifier = modifiers[randInt(rand, modifiers.length)]; + + if (testIteration == stopAt) { + testIteration = stopAt; + } + text.modifyCharacterStyles(startingAt, endingAt, modifier); + + for (int j=startingAt; j < endingAt; j++) { + styles[j] = modifier.modifyStyle(styles[j]); + } + } + + // check invariants + AttributeMap oldStyle = null; + int textLength = text.length(); + for (int runStart = 0; runStart < textLength;) { + + AttributeMap currentStyle = text.characterStyleAt(runStart); + int runLimit = text.characterStyleLimit(runStart); + if (runStart >= runLimit) { + errln("Run length is not positive"); + } + if (currentStyle.equals(oldStyle)) { + errln("Styles didn't merge"); + } + + for (int pos=runStart; pos < runLimit; pos++) { + AttributeMap charStyleAtPos = text.characterStyleAt(pos); + if (currentStyle != charStyleAtPos) { + errln("Iterator style is not equal to text style at " + pos + "."); + } + AttributeMap expected = styles[pos]; + if (!currentStyle.equals(expected)) { + errln("Iterator style doesn't match expected style at " + pos + "."); + } + if (!(text.characterStyleStart(pos) == runStart) || + !(text.characterStyleLimit(pos) == runLimit)) { + errln("style run start / limit is not consistent"); + } + } + runStart = runLimit; + } + if (textLength > 0) { + if (text.characterStyleAt(textLength) != + text.characterStyleAt(textLength-1)) { + errln("Character styles at end aren't the same"); + } + } + + // check damaged range: + int damageStart = Integer.MAX_VALUE; + int damageLimit = Integer.MIN_VALUE; + for (int i=0; i < textLength; i++) { + if (!styles[i].equals(oldStyles[i])) { + damageStart = Math.min(i, damageStart); + damageLimit = Math.max(i+1, damageLimit); + } + } + if (damageStart != text.damagedRangeStart() || + damageLimit != text.damagedRangeLimit()) { + logln("Test iteration: " + testIteration); + logln("startingAt: " + startingAt + "; endingAt: " + endingAt); + logln("damageStart: " + damageStart + "; damageLimit: " + damageLimit); + logln("text.rangeStart: " + text.damagedRangeStart() + + "text.rangeLimit: " + text.damagedRangeLimit()); + errln("Damage range start or limit is not expected value"); + } + + if ((damageLimit == Integer.MIN_VALUE) != (oldTs == text.getTimeStamp())) { + + errln("timeStamp is incorrect"); + } + } + } + + protected void err(String message) { + + if (testIteration != NOT_IN_MONKEY_TEST) { + message = "testIteration="+testIteration+"; testCase="+theCase+message; + } + super.err(message); + } + + /** + * Perform a random series of operations on an MText and + * check the result of each operation against a set of invariants. + */ + public void monkeyTest(boolean streaming) { + + /* + You can add any operation to the switch statement provided it + preserves the following invariants: + - The String plainText contains the same text as the StyledStringBuffer. + Obviously, for the test to be meaningful plainText must be computed + independently of the buffer (ie don't write: plainText = buf.getStyledString().toString()). + - Every 'b' is bold, every 'i' is italic, every 'p' is plain, and + no other characters appear in the text. + */ + + AttributeMap boldAttrs = new AttributeMap(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); + AttributeMap italicAttrs = new AttributeMap(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); + AttributeMap emptyAttrs = AttributeMap.EMPTY_ATTRIBUTE_MAP; + + final String bold1Str_getString = "b"; + MConstText bold1Str = new StyledText(bold1Str_getString, boldAttrs); + + final String italic1Str_getString = "i"; + MConstText italic1Str = new StyledText(italic1Str_getString, italicAttrs); + + final String plain1Str_getString = "p"; + MConstText plain1Str = new StyledText(plain1Str_getString, emptyAttrs); + + StyledText temp = new StyledText(); + temp.append(bold1Str); + temp.append(italic1Str); + final String boldItalicStr_getString = bold1Str_getString.concat(italic1Str_getString); + MConstText boldItalicStr = temp; + + temp = new StyledText(); + temp.append(bold1Str); + temp.append(bold1Str); + temp.append(bold1Str); + final String bold3Str_getString = "bbb"; + MConstText bold3Str = temp; + + MText buf = new StyledText(); + String plainText = new String(); + //int testIteration=0; - now instance variables so errln can report it + //int theCase=0; + + final int NUM_CASES = 14; + boolean[] casesExecuted = new boolean[NUM_CASES]; + final int stopAt = -1; + Random rand = new Random(RAND_SEED); + + final String ALWAYS_DIFFERENT = "\uFEFF"; + + for (testIteration=0; testIteration < TEST_ITERATIONS; testIteration++) { + + theCase = randInt(rand, NUM_CASES); + + casesExecuted[theCase] = true; + + if (testIteration == stopAt) { + testIteration = stopAt; // Convenient place to put breakpoint + } + + int timeStamp = buf.getTimeStamp(); + String oldPlainText = plainText; + if (oldPlainText == null) { + errln("oldPlainText is null!"); + } + + switch (theCase) { + + case 0: + // create new string; replace chars at start with different style + buf = new StyledText(); + buf.append(bold3Str); + buf.replace(0, 1, italic1Str, 0, italic1Str.length()); + buf.replace(0, 0, italic1Str, 0, italic1Str.length()); + + plainText = bold3Str_getString.substring(1, bold3Str.length()); + plainText = italic1Str_getString.concat(plainText); + plainText = italic1Str_getString.concat(plainText); + oldPlainText = null; + break; + + case 1: + // delete the last character from the string + if (buf.length() == 0) { + buf.replace(0, 0, italic1Str, 0, italic1Str.length()); + plainText = italic1Str_getString; + oldPlainText = ALWAYS_DIFFERENT; + } + buf.remove(buf.length()-1, buf.length()); + plainText = plainText.substring(0, plainText.length()-1); + break; + + case 2: + // replace some of the buffer with boldItalicStr + int rStart = randInt(rand, buf.length()+1); + int rStop = randInt(rand, rStart, buf.length()+1); + buf.replace(rStart, rStop, boldItalicStr); + { + String newString = (rStart>0)? plainText.substring(0, rStart) : new String(); + newString = newString.concat(boldItalicStr_getString); + if (rStop < plainText.length()) + newString = newString.concat(plainText.substring(rStop, plainText.length())); + oldPlainText = ALWAYS_DIFFERENT; + plainText = newString; + } + break; + + case 3: + // repeatedly insert strings into the center of the buffer + { + int insPos = buf.length() / 2; + String prefix = plainText.substring(0, insPos); + String suffix = plainText.substring(insPos, plainText.length()); + String middle = new String(); + for (int ii=0; ii<4; ii++) { + MConstText which = (ii%2==0)? boldItalicStr : bold3Str; + String whichString = (ii%2==0)? boldItalicStr_getString : bold3Str_getString; + int tempPos = insPos+middle.length(); + buf.insert(tempPos, which); + middle = middle.concat(whichString); + } + plainText = prefix.concat(middle).concat(suffix); + oldPlainText = ALWAYS_DIFFERENT; + } + break; + + case 4: + // insert bold1Str at end + buf.append(bold1Str); + plainText = plainText.concat(bold1Str_getString); + break; + + case 5: + // delete a character from the string + if (buf.length() > 0) { + int delPos = randInt(rand, buf.length()-1); + buf.remove(delPos, delPos+1); + plainText = plainText.substring(0, delPos).concat(plainText.substring(delPos+1)); + } + else { + buf.replace(0, 0, plain1Str, 0, plain1Str.length()); + plainText = plain1Str_getString; + } + break; + + case 6: + // replace the contents of the buffer (except the first character) with itself + { + int start = buf.length() > 1? 1 : 0; + buf.replace(start, buf.length(), buf); + plainText = plainText.substring(0, start).concat(plainText); + if (buf.length() > 0) { + oldPlainText = ALWAYS_DIFFERENT; + } + } + break; + + case 7: + // append the contents of the buffer to itself + { + MConstText content = buf; + buf.insert(buf.length(), content); + plainText = plainText.concat(plainText); + } + break; + + case 8: + // replace the buffer with boldItalicStr+bold3Str + { + MText replacement = new StyledText(); + replacement.append(boldItalicStr); + replacement.append(bold3Str); + buf.replace(0, buf.length(), replacement, 0, replacement.length()); + plainText = boldItalicStr_getString.concat(bold3Str_getString); + oldPlainText = ALWAYS_DIFFERENT; + } + break; + + case 9: + // insert bold1Str at end - same as 4 but uses different API + buf.replace(buf.length(), + buf.length(), + bold1Str_getString.toCharArray(), + 0, + bold1Str_getString.length(), + boldAttrs); + plainText = plainText.concat(bold1Str_getString); + break; + + case 10: + // remove all + buf.remove(); + plainText = ""; + oldPlainText = ALWAYS_DIFFERENT; + break; + + case 11: + // remove all - different way + buf.remove(0, buf.length()); + plainText = ""; + break; + + case 12: + // insert 'i' at 3rd character (or last, if fewer than 3 chars) + { + int insPos = Math.min(buf.length(), 3); + buf.replace(insPos, insPos, 'i', italicAttrs); + plainText = (plainText.substring(0, insPos)). + concat(italic1Str_getString). + concat(plainText.substring(insPos)); + } + break; + + case 13: + if (streaming) { + Throwable error = null; + try { + ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); + ObjectOutputStream objOut = new ObjectOutputStream(bytesOut); + objOut.writeObject(buf); + + ByteArrayInputStream bytesIn = + new ByteArrayInputStream(bytesOut.toByteArray()); + ObjectInputStream objIn = new ObjectInputStream(bytesIn); + buf = (MText) objIn.readObject(); + oldPlainText = null; + } + catch(IOException e) { + error = e; + } + catch(ClassNotFoundException e) { + error = e; + } + if (error != null) { + error.printStackTrace(); + errln("Streaming problem: " + error); + } + } + break; + + default: + errln("Invalid case."); + } + + // Check time stamp if oldPlainText != null. + // Time stamp should be different iff + // oldPlainText == plainText + if (oldPlainText != null) { + if ((timeStamp==buf.getTimeStamp()) != + oldPlainText.equals(plainText)) { + logln("plainText hashCode: " + plainText.hashCode()); + logln("oldPlainText hashCode: " + oldPlainText.hashCode()); + errln("Time stamp is incorrect"); + } + } + + // now check invariants: + if (plainText.length() != buf.length()) { + errln("Lengths don't match"); + } + + for (int j=0; j < buf.length(); j++) { + if (buf.at(j) != plainText.charAt(j)) { + errln("Characters don't match."); + } + } + + int start; + for (start = 0; start < buf.length();) { + + if (start != buf.characterStyleStart(start)) { + errln("style start is wrong"); + } + int limit = buf.characterStyleLimit(start); + if (start >= limit) { + errln("start >= limit"); + } + char current = plainText.charAt(start); + + AttributeMap comp = null; + if (current == 'p') { + comp = emptyAttrs; + } + else if (current == 'b') { + comp = boldAttrs; + } + else if (current == 'i') { + comp = italicAttrs; + } + else { + errln("An invalid character snuck in!"); + } + + AttributeMap startStyle = buf.characterStyleAt(start); + if (!comp.equals(startStyle)) { + errln("Style is not expected style."); + } + + for (int j = start; j < limit; j++) { + if (plainText.charAt(j) != current) { + errln("Character doesn't match style."); + } + if (buf.characterStyleAt(j) != startStyle) { + errln("Incorrect style in run"); + } + } + + if (limit < buf.length()) { + if (plainText.charAt(limit) == current) { + errln("Style run ends too soon."); + } + } + start = limit; + } + if (start != buf.length()) { + errln("Last limit is not buffer length."); + } + + // won't try to compute and check damaged range; however, + // if nonempty it should always be within text + int damageStart = buf.damagedRangeStart(); + int damageLimit = buf.damagedRangeLimit(); + if (damageStart == Integer.MAX_VALUE) { + if (damageLimit != Integer.MIN_VALUE) { + errln("Invalid empty interval"); + } + } + else { + if (damageStart > damageLimit) { + errln("Damage range inverted"); + } + if (damageStart < 0 || damageLimit > buf.length()) { + errln("Damage range endpoint out of bounds"); + } + } + } + + testIteration = NOT_IN_MONKEY_TEST; + + boolean allCasesExecuted = true; + for (int index=0; index < NUM_CASES; index++) { + allCasesExecuted &= casesExecuted[index]; + if (casesExecuted[index] == false) { + logln("Case " + index + " not executed."); + } + } + //if (allCasesExecuted) { + // logln("All cases executed."); + //} + } +} \ No newline at end of file diff --git a/icu4j/src/com/ibm/test/richtext/TestMTextStreaming.java b/icu4j/src/com/ibm/test/richtext/TestMTextStreaming.java new file mode 100755 index 00000000000..c45cff51fc0 --- /dev/null +++ b/icu4j/src/com/ibm/test/richtext/TestMTextStreaming.java @@ -0,0 +1,162 @@ +/* + * @(#)$RCSfile: TestMTextStreaming.java,v $ $Revision: 1.1 $ $Date: 2000/04/24 20:38:00 $ + * + * (C) Copyright IBM Corp. 1998-1999. All Rights Reserved. + * + * The program is provided "as is" without any warranty express or + * implied, including the warranty of non-infringement and the implied + * warranties of merchantibility and fitness for a particular purpose. + * IBM will not be liable for any damages suffered by you as a result + * of using the Program. In no event will IBM be liable for any + * special, indirect or consequential damages or lost profits even if + * IBM has been advised of the possibility of their occurrence. IBM + * will not be liable for any third party claims against you. + */ +package com.ibm.richtext.tests; + +import com.ibm.test.TestFmwk; + +import java.io.*; +import java.awt.Color; + +import com.ibm.richtext.styledtext.MText; +import com.ibm.richtext.styledtext.StandardTabRuler; +import com.ibm.richtext.styledtext.StyledText; +import com.ibm.richtext.styledtext.StyleModifier; + +import com.ibm.textlayout.attributes.AttributeMap; +import com.ibm.textlayout.attributes.TextAttribute; + +public class TestMTextStreaming extends TestFmwk { + + static final String COPYRIGHT = + "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved"; + + public static void main(String[] args) throws Exception { + + new TestMTextStreaming().run(args); + } + + public TestMTextStreaming() { + } + + public void test() { + + simpleTest(); + allAttributesTest(); + } + + private void simpleTest() { + + AttributeMap style = AttributeMap.EMPTY_ATTRIBUTE_MAP; + MText text = new StyledText("Hello world!", style); + + streamAndCompare(text); + } + + private static class TestModifier extends StyleModifier { + + private Object fKey; + private Object fValue; + + public AttributeMap modifyStyle(AttributeMap style) { + + return style.addAttribute(fKey, fValue); + } + + TestModifier(Object key, Object value) { + + fKey = key; + fValue = value; + } + } + + private void allAttributesTest() { + + AttributeMap style = AttributeMap.EMPTY_ATTRIBUTE_MAP; + MText text = new StyledText("Hello world!", style); + + int length = text.length(); + + final boolean CHARACTER = true; + final boolean PARAGRAPH = false; + + addStyle(text, 0, length/2, TextAttribute.FAMILY, "Times", CHARACTER); + addStyle(text, length/2, length, TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD, CHARACTER); + addStyle(text, 0, length/2, TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE, CHARACTER); + addStyle(text, 0, length/2, TextAttribute.SIZE, new Float(13.7f), CHARACTER); + addStyle(text, length/2, length, TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUB, CHARACTER); + addStyle(text, 0, length/2, TextAttribute.FOREGROUND, Color.blue, CHARACTER); + addStyle(text, 0, length/2, TextAttribute.BACKGROUND, Color.red, CHARACTER); + addStyle(text, 0, length-1, TextAttribute.STRIKETHROUGH, Boolean.TRUE, CHARACTER); + + addStyle(text, 0, length, TextAttribute.EXTRA_LINE_SPACING, new Float(4), PARAGRAPH); + addStyle(text, 0, length, TextAttribute.FIRST_LINE_INDENT, new Float(6), PARAGRAPH); + addStyle(text, 0, length, TextAttribute.MIN_LINE_SPACING, new Float(7), PARAGRAPH); + addStyle(text, 0, length, TextAttribute.LINE_FLUSH, TextAttribute.FLUSH_TRAILING, PARAGRAPH); + addStyle(text, 0, length, TextAttribute.LEADING_MARGIN, new Float(9), PARAGRAPH); + addStyle(text, 0, length, TextAttribute.TRAILING_MARGIN, new Float(9), PARAGRAPH); + addStyle(text, 0, length, TextAttribute.TAB_RULER, new StandardTabRuler(), PARAGRAPH); + + streamAndCompare(text); + } + + private static void addStyle(MText text, + int start, + int limit, + Object key, + Object value, + boolean character) { + + StyleModifier modifier = new TestModifier(key, value); + + if (character) { + text.modifyCharacterStyles(start, limit, modifier); + } + else { + text.modifyParagraphStyles(start, limit, modifier); + } + } + + public void streamAndCompare(MText text) { + + Throwable error = null; + + try { + ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); + ObjectOutputStream objOut = new ObjectOutputStream(bytesOut); + objOut.writeObject(text); + + ByteArrayInputStream bytesIn = + new ByteArrayInputStream(bytesOut.toByteArray()); + ObjectInputStream objIn = new ObjectInputStream(bytesIn); + MText streamedText = (MText) objIn.readObject(); + if (!isEqual(text, streamedText)) { + isEqual(text, streamedText); + errln("Streamed text is not equal"); + } + } +/* catch(OptionalDataException e) { + error = e; + } + catch(StreamCorruptedException e) { + error = e; + }*/ + catch(IOException e) { + error = e; + } + catch(ClassNotFoundException e) { + error = e; + } + + if (error != null) { + error.printStackTrace(); + errln("Serialization failed."); + } + } + + public static boolean isEqual(MText lhs, MText rhs) { + + return lhs.equals(rhs); + } +} \ No newline at end of file diff --git a/icu4j/src/com/ibm/test/richtext/TestParagraphStyles.java b/icu4j/src/com/ibm/test/richtext/TestParagraphStyles.java new file mode 100755 index 00000000000..cc8bdc2396b --- /dev/null +++ b/icu4j/src/com/ibm/test/richtext/TestParagraphStyles.java @@ -0,0 +1,339 @@ +/* + * @(#)$RCSfile: TestParagraphStyles.java,v $ $Revision: 1.1 $ $Date: 2000/04/24 20:38:00 $ + * + * (C) Copyright IBM Corp. 1998-1999. All Rights Reserved. + * + * The program is provided "as is" without any warranty express or + * implied, including the warranty of non-infringement and the implied + * warranties of merchantibility and fitness for a particular purpose. + * IBM will not be liable for any damages suffered by you as a result + * of using the Program. In no event will IBM be liable for any + * special, indirect or consequential damages or lost profits even if + * IBM has been advised of the possibility of their occurrence. IBM + * will not be liable for any third party claims against you. + */ +package com.ibm.richtext.tests; + +import com.ibm.test.TestFmwk; + +import com.ibm.richtext.styledtext.StyledText; +import com.ibm.richtext.styledtext.MConstText; +import com.ibm.richtext.styledtext.MText; +import com.ibm.textlayout.attributes.AttributeMap; +import com.ibm.richtext.styledtext.StyleModifier; +import java.util.Random; + +public final class TestParagraphStyles extends TestFmwk { + + static final String COPYRIGHT = + "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved"; + + public static void main(String[] args) throws Exception { + + new TestParagraphStyles().run(args); + } + + private static final int RAND_SEED = 1234; + private static final int NUM_TESTS = 2500; + + private static final boolean isParagraphBreak(char c) { + + return c =='\u2029' || c == '\n'; + } + + private static final Object KEY = "KEY"; + private static final AttributeMap PLAIN = AttributeMap.EMPTY_ATTRIBUTE_MAP; + private static final AttributeMap A_STYLE = new AttributeMap(KEY, new Character('a')); + private static final StyleModifier A_MOD = + StyleModifier.createReplaceModifier(A_STYLE); + private static final AttributeMap B_STYLE = new AttributeMap(KEY, new Character('b')); + private static final StyleModifier B_MOD = + StyleModifier.createReplaceModifier(B_STYLE); + private static final AttributeMap C_STYLE = new AttributeMap(KEY, new Character('c')); + private static final StyleModifier C_MOD = + StyleModifier.createReplaceModifier(C_STYLE); + private static final AttributeMap D_STYLE = new AttributeMap(KEY, new Character('d')); + private static final StyleModifier D_MOD = + StyleModifier.createReplaceModifier(D_STYLE); + private static final AttributeMap E_STYLE = new AttributeMap(KEY, new Character('e')); + private static final StyleModifier E_MOD = + StyleModifier.createReplaceModifier(E_STYLE); + + public void test() { + + easyTests(); + randomTest(); + } + + private void easyTests() { + + MText text = new StyledText("a\nb\nc\nd\n", PLAIN); + text.modifyParagraphStyles(0, text.length(), A_MOD); + verifyParagraphCount(text); + + MText src = new StyledText("XXX\nYYY", PLAIN); + src.modifyParagraphStyles(0, src.length(), B_MOD); + verifyParagraphCount(src); + + MText temp = text.extractWritable(0, text.length()); + temp.append(src); + verifyParagraphCount(temp); + for (int i=0; i < text.length(); i++) { + if (!temp.paragraphStyleAt(i).equals(text.paragraphStyleAt(i))) { + errln("Paragraph styles are wrong"); + } + } + for (int i=0; i < src.length(); i++) { + if (!temp.paragraphStyleAt(i+text.length()).equals(src.paragraphStyleAt(i))) { + errln("Paragraph styles are wrong"); + } + } + + temp = text.extractWritable(0, text.length()); + temp.replace(0, 1, src, 0, src.length()); + verifyParagraphCount(temp); + if (temp.paragraphLimit(0) != 4) { + errln("Paragraph limit is wrong"); + } + if (!temp.paragraphStyleAt(0).equals(B_STYLE)) { + errln("First style is wrong"); + } + if (!temp.paragraphStyleAt(4).equals(A_STYLE)) { + errln("Style after insert is wrong"); + } + + // test append + MConstText newSrc = src.extract(4, 7); + MText initC = new StyledText("cccccc", PLAIN); + initC.modifyParagraphStyles(0, initC.length(), C_MOD); + initC.append(newSrc); + // now initC should be one paragraph with style B + if (initC.paragraphLimit(0) != initC.length()) { + errln("Should only be one paragraph"); + } + if (initC.paragraphStyleAt(0) != initC.paragraphStyleAt(initC.length())) { + errln("Two different paragraph styles"); + } + if (!initC.paragraphStyleAt(initC.length()/2).equals(B_STYLE)) { + errln("Incorrect paragraph style"); + } + + text = new StyledText("aaa\n", PLAIN); + text.modifyParagraphStyles(0, text.length(), A_MOD); + text.modifyParagraphStyles(text.length(), text.length(), B_MOD); + if (text.paragraphStyleAt(text.length()) != B_STYLE) { + errln("0-length paragraph at end has incorrect style"); + } + } + + private static int randInt(Random rand, int limit) { + + return randInt(rand, 0, limit); + } + + private static int randInt(Random rand, int start, int limit) { + + if (start > limit) { + throw new IllegalArgumentException("Range is 0-length."); + } + else if (start == limit) { + return start; + } + + return start + (Math.abs(rand.nextInt())%(limit-start)) ; + } + + private void randomTest() { + + MText noParagraph = new StyledText("zzzz", PLAIN); + noParagraph.modifyParagraphStyles(0, noParagraph.length(), A_MOD); + MText twoParagraphs = new StyledText("aaa\nbbb", PLAIN); + twoParagraphs.modifyParagraphStyles(0, twoParagraphs.paragraphLimit(0), B_MOD); + MText threeParagraphs = new StyledText("cc\ndd\nee", PLAIN); + threeParagraphs.modifyParagraphStyles(0, 3, C_MOD); + threeParagraphs.modifyParagraphStyles(3, 6, D_MOD); + threeParagraphs.modifyParagraphStyles(6, 8, E_MOD); + MText trailingP1 = new StyledText("hhhh\n", PLAIN); + trailingP1.modifyParagraphStyles(0, trailingP1.paragraphLimit(0), C_MOD); + MText trailingP2 = new StyledText("iii\n", PLAIN); + trailingP2.modifyParagraphStyles(0, 0, D_MOD); + trailingP2.modifyParagraphStyles(trailingP2.length(), trailingP2.length(), B_MOD); + + if (!trailingP2.paragraphStyleAt(trailingP2.length()-1).equals(D_STYLE)) { + errln("Style incorrect in trailingP2"); + } + if (!trailingP2.paragraphStyleAt(trailingP2.length()).equals(B_STYLE)) { + errln("Ending style incorrect in trailingP2"); + } + + MConstText[] tests = { noParagraph, twoParagraphs, + threeParagraphs, trailingP1, trailingP2 }; + + Random random = new Random(RAND_SEED); + + int stopAt = 465; + int i = 0; + try { + for (i=0; i < NUM_TESTS; i++) { + + int srcIndex = randInt(random, tests.length); + int targetIndex = randInt(random, tests.length); + MText target = new StyledText(tests[targetIndex]); + MConstText src = tests[srcIndex]; + + int srcStart = randInt(random, src.length()); + int srcLimit = randInt(random, srcStart, src.length()); + int start = randInt(random, target.length()); + int limit = randInt(random, start, target.length()); + + if (i == stopAt) { + stopAt = i; + } + + insertAndCheck(src, srcStart, srcLimit, target, start, limit); + } + } + finally { + if (i < NUM_TESTS) { + logln("iteration=" + i); + } + } + } + + private void insertAndCheck(MConstText src, int srcStart, int srcLimit, + MText target, int start, int limit) { + + // p-style after insertion + AttributeMap after; + if (limit == target.length() && srcLimit > srcStart) { + after = src.paragraphStyleAt(srcLimit); + } + else { + after = target.paragraphStyleAt(limit); + } + + AttributeMap before; + boolean srcHasPBreak = false; + for (int i=srcStart; i < srcLimit; i++) { + if (isParagraphBreak(src.at(i))) { + srcHasPBreak = true; + break; + } + } + + if (start > 0 && isParagraphBreak(target.at(start-1))) { + before = target.paragraphStyleAt(start-1); + } + else { + before = srcHasPBreak? src.paragraphStyleAt(srcStart) : after; + } + boolean stylePropogated = !before.equals(target.paragraphStyleAt(Math.max(0, start-1))); + + + target.resetDamagedRange(); + target.replace(start, limit, src, srcStart, srcLimit); + final int damageLimit = (start==limit && srcStart==srcLimit)? + Integer.MIN_VALUE : start + (srcLimit-srcStart); + + if (target.damagedRangeLimit() != damageLimit) { + logln("limit: " + damageLimit + "; target.limit: " + + target.damagedRangeLimit()); + errln("Damaged range limit is incorrect"); + } + + final int damageStart = (damageLimit==Integer.MIN_VALUE)? Integer.MAX_VALUE : + (stylePropogated? target.paragraphStart(Math.max(0, start-1)) : start); + if (target.damagedRangeStart() > damageStart) { + logln("start: " + damageStart + "; target.start: " + + target.damagedRangeStart()); + errln("Damaged range start is incorrect"); + } + + verifyParagraphCount(target); + + // check endpoints + if (!before.equals(target.paragraphStyleAt(Math.max(start-1, 0)))) { + errln("Incorrect paragraph style before modified range"); + } + + int lengthDelta = (srcLimit-srcStart) - (limit-start); + int indexAfterInsert = Math.min(target.length(), limit + lengthDelta); + if (!after.equals(target.paragraphStyleAt(indexAfterInsert))) { + errln("Incorrect paragraph style after modified range"); + } + + if (srcHasPBreak) { + int startP = target.paragraphLimit(start); + int limitOfTest = target.paragraphStart(indexAfterInsert); + + int offset = start - srcStart; + + while (startP < limitOfTest) { + int limitP = target.paragraphLimit(startP); + if (src.paragraphLimit(startP-offset) + offset != limitP) { + errln("paragraph limits are not consistent"); + } + if (!src.paragraphStyleAt(startP-offset) + .equals(target.paragraphStyleAt(startP))) { + errln("paragraph styles are not consistent"); + } + startP = limitP; + } + } + else { + for (int i=start; i < start+(srcLimit-srcStart); i++) { + if (!after.equals(target.paragraphStyleAt(i))) { + errln("paragraph style changed unexpectedly"); + } + } + } + } + + private void verifyParagraphCount(MConstText text) { + + int pCount = 0; + int textLength = text.length(); + + if (textLength == 0) { + pCount = 1; + } + else { + for (int s=0; s < textLength; s = text.paragraphLimit(s)) { + pCount++; + } + if (isParagraphBreak(text.at(textLength-1))) { + pCount++; + } + } + + int sepCount = 0; + for (int i=0; i < textLength; i++) { + if (isParagraphBreak(text.at(i))) { + sepCount++; + } + } + + if (sepCount + 1 != pCount) { + logln("sepCount=" + sepCount + "; pCount=" + pCount); + errln("Paragraph count is not consistent with characters"); + } + } + + private void checkEndpoint(MConstText text) { + + boolean emptyFinalParagraph; + int length = text.length(); + + if (length != 0) { + char ch = text.at(length-1); + emptyFinalParagraph = isParagraphBreak(ch); + } + else { + emptyFinalParagraph = true; + } + + if ((text.paragraphStart(length) == length) != emptyFinalParagraph) { + errln("Final paragraph length is incorrect"); + } + } +} \ No newline at end of file