2 * (C) Copyright IBM Corp. 1998-2007. All Rights Reserved.
\r
4 * The program is provided "as is" without any warranty express or
\r
5 * implied, including the warranty of non-infringement and the implied
\r
6 * warranties of merchantibility and fitness for a particular purpose.
\r
7 * IBM will not be liable for any damages suffered by you as a result
\r
8 * of using the Program. In no event will IBM be liable for any
\r
9 * special, indirect or consequential damages or lost profits even if
\r
10 * IBM has been advised of the possibility of their occurrence. IBM
\r
11 * will not be liable for any third party claims against you.
\r
13 package com.ibm.richtext.test.unit;
\r
15 import com.ibm.icu.dev.test.TestFmwk;
\r
17 import com.ibm.richtext.styledtext.StyledText;
\r
18 import com.ibm.richtext.styledtext.MConstText;
\r
19 import com.ibm.richtext.styledtext.MText;
\r
20 import com.ibm.richtext.textlayout.attributes.AttributeMap;
\r
21 import com.ibm.richtext.styledtext.StyleModifier;
\r
22 import java.util.Random;
\r
24 public final class TestParagraphStyles extends TestFmwk {
\r
26 static final String COPYRIGHT =
\r
27 "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";
\r
29 public static void main(String[] args) throws Exception {
\r
31 new TestParagraphStyles().run(args);
\r
34 private static final int RAND_SEED = 1234;
\r
35 private static final int NUM_TESTS = 2500;
\r
37 private static final boolean isParagraphBreak(char c) {
\r
39 return c =='\u2029' || c == '\n';
\r
42 private static final Object KEY = "KEY";
\r
43 private static final AttributeMap PLAIN = AttributeMap.EMPTY_ATTRIBUTE_MAP;
\r
44 private static final AttributeMap A_STYLE = new AttributeMap(KEY, new Character('a'));
\r
45 private static final StyleModifier A_MOD =
\r
46 StyleModifier.createReplaceModifier(A_STYLE);
\r
47 private static final AttributeMap B_STYLE = new AttributeMap(KEY, new Character('b'));
\r
48 private static final StyleModifier B_MOD =
\r
49 StyleModifier.createReplaceModifier(B_STYLE);
\r
50 private static final AttributeMap C_STYLE = new AttributeMap(KEY, new Character('c'));
\r
51 private static final StyleModifier C_MOD =
\r
52 StyleModifier.createReplaceModifier(C_STYLE);
\r
53 private static final AttributeMap D_STYLE = new AttributeMap(KEY, new Character('d'));
\r
54 private static final StyleModifier D_MOD =
\r
55 StyleModifier.createReplaceModifier(D_STYLE);
\r
56 private static final AttributeMap E_STYLE = new AttributeMap(KEY, new Character('e'));
\r
57 private static final StyleModifier E_MOD =
\r
58 StyleModifier.createReplaceModifier(E_STYLE);
\r
60 public void test() {
\r
66 private void easyTests() {
\r
68 MText text = new StyledText("a\nb\nc\nd\n", PLAIN);
\r
69 text.modifyParagraphStyles(0, text.length(), A_MOD);
\r
70 verifyParagraphCount(text);
\r
72 MText src = new StyledText("XXX\nYYY", PLAIN);
\r
73 src.modifyParagraphStyles(0, src.length(), B_MOD);
\r
74 verifyParagraphCount(src);
\r
76 MText temp = text.extractWritable(0, text.length());
\r
78 verifyParagraphCount(temp);
\r
79 for (int i=0; i < text.length(); i++) {
\r
80 if (!temp.paragraphStyleAt(i).equals(text.paragraphStyleAt(i))) {
\r
81 errln("Paragraph styles are wrong");
\r
84 for (int i=0; i < src.length(); i++) {
\r
85 if (!temp.paragraphStyleAt(i+text.length()).equals(src.paragraphStyleAt(i))) {
\r
86 errln("Paragraph styles are wrong");
\r
90 temp = text.extractWritable(0, text.length());
\r
91 temp.replace(0, 1, src, 0, src.length());
\r
92 verifyParagraphCount(temp);
\r
93 if (temp.paragraphLimit(0) != 4) {
\r
94 errln("Paragraph limit is wrong");
\r
96 if (!temp.paragraphStyleAt(0).equals(B_STYLE)) {
\r
97 errln("First style is wrong");
\r
99 if (!temp.paragraphStyleAt(4).equals(A_STYLE)) {
\r
100 errln("Style after insert is wrong");
\r
104 MConstText newSrc = src.extract(4, 7);
\r
105 MText initC = new StyledText("cccccc", PLAIN);
\r
106 initC.modifyParagraphStyles(0, initC.length(), C_MOD);
\r
107 initC.append(newSrc);
\r
108 // now initC should be one paragraph with style B
\r
109 if (initC.paragraphLimit(0) != initC.length()) {
\r
110 errln("Should only be one paragraph");
\r
112 if (initC.paragraphStyleAt(0) != initC.paragraphStyleAt(initC.length())) {
\r
113 errln("Two different paragraph styles");
\r
115 if (!initC.paragraphStyleAt(initC.length()/2).equals(B_STYLE)) {
\r
116 errln("Incorrect paragraph style");
\r
119 text = new StyledText("aaa\n", PLAIN);
\r
120 text.modifyParagraphStyles(0, text.length(), A_MOD);
\r
121 text.modifyParagraphStyles(text.length(), text.length(), B_MOD);
\r
122 if (text.paragraphStyleAt(text.length()) != B_STYLE) {
\r
123 errln("0-length paragraph at end has incorrect style");
\r
127 private static int randInt(Random rand, int limit) {
\r
129 return randInt(rand, 0, limit);
\r
132 private static int randInt(Random rand, int start, int limit) {
\r
134 if (start > limit) {
\r
135 throw new IllegalArgumentException("Range is 0-length.");
\r
137 else if (start == limit) {
\r
141 return start + (Math.abs(rand.nextInt())%(limit-start)) ;
\r
144 private void randomTest() {
\r
146 MText noParagraph = new StyledText("zzzz", PLAIN);
\r
147 noParagraph.modifyParagraphStyles(0, noParagraph.length(), A_MOD);
\r
148 MText twoParagraphs = new StyledText("aaa\nbbb", PLAIN);
\r
149 twoParagraphs.modifyParagraphStyles(0, twoParagraphs.paragraphLimit(0), B_MOD);
\r
150 MText threeParagraphs = new StyledText("cc\ndd\nee", PLAIN);
\r
151 threeParagraphs.modifyParagraphStyles(0, 3, C_MOD);
\r
152 threeParagraphs.modifyParagraphStyles(3, 6, D_MOD);
\r
153 threeParagraphs.modifyParagraphStyles(6, 8, E_MOD);
\r
154 MText trailingP1 = new StyledText("hhhh\n", PLAIN);
\r
155 trailingP1.modifyParagraphStyles(0, trailingP1.paragraphLimit(0), C_MOD);
\r
156 MText trailingP2 = new StyledText("iii\n", PLAIN);
\r
157 trailingP2.modifyParagraphStyles(0, 0, D_MOD);
\r
158 trailingP2.modifyParagraphStyles(trailingP2.length(), trailingP2.length(), B_MOD);
\r
160 if (!trailingP2.paragraphStyleAt(trailingP2.length()-1).equals(D_STYLE)) {
\r
161 errln("Style incorrect in trailingP2");
\r
163 if (!trailingP2.paragraphStyleAt(trailingP2.length()).equals(B_STYLE)) {
\r
164 errln("Ending style incorrect in trailingP2");
\r
167 MConstText[] tests = { noParagraph, twoParagraphs,
\r
168 threeParagraphs, trailingP1, trailingP2 };
\r
170 Random random = new Random(RAND_SEED);
\r
175 for (i=0; i < NUM_TESTS; i++) {
\r
177 int srcIndex = randInt(random, tests.length);
\r
178 int targetIndex = randInt(random, tests.length);
\r
179 MText target = new StyledText(tests[targetIndex]);
\r
180 MConstText src = tests[srcIndex];
\r
182 int srcStart = randInt(random, src.length());
\r
183 int srcLimit = randInt(random, srcStart, src.length());
\r
184 int start = randInt(random, target.length());
\r
185 int limit = randInt(random, start, target.length());
\r
191 insertAndCheck(src, srcStart, srcLimit, target, start, limit);
\r
195 if (i < NUM_TESTS) {
\r
196 logln("iteration=" + i);
\r
201 private void insertAndCheck(MConstText src, int srcStart, int srcLimit,
\r
202 MText target, int start, int limit) {
\r
204 // p-style after insertion
\r
205 AttributeMap after;
\r
206 if (limit == target.length() && srcLimit > srcStart) {
\r
207 after = src.paragraphStyleAt(srcLimit);
\r
210 after = target.paragraphStyleAt(limit);
\r
213 AttributeMap before;
\r
214 boolean srcHasPBreak = false;
\r
215 for (int i=srcStart; i < srcLimit; i++) {
\r
216 if (isParagraphBreak(src.at(i))) {
\r
217 srcHasPBreak = true;
\r
222 if (start > 0 && isParagraphBreak(target.at(start-1))) {
\r
223 before = target.paragraphStyleAt(start-1);
\r
226 before = srcHasPBreak? src.paragraphStyleAt(srcStart) : after;
\r
228 boolean stylePropogated = !before.equals(target.paragraphStyleAt(Math.max(0, start-1)));
\r
231 target.resetDamagedRange();
\r
232 target.replace(start, limit, src, srcStart, srcLimit);
\r
233 final int damageLimit = (start==limit && srcStart==srcLimit)?
\r
234 Integer.MIN_VALUE : start + (srcLimit-srcStart);
\r
236 if (target.damagedRangeLimit() != damageLimit) {
\r
237 logln("limit: " + damageLimit + "; target.limit: " +
\r
238 target.damagedRangeLimit());
\r
239 errln("Damaged range limit is incorrect");
\r
242 final int damageStart = (damageLimit==Integer.MIN_VALUE)? Integer.MAX_VALUE :
\r
243 (stylePropogated? target.paragraphStart(Math.max(0, start-1)) : start);
\r
244 if (target.damagedRangeStart() > damageStart) {
\r
245 logln("start: " + damageStart + "; target.start: " +
\r
246 target.damagedRangeStart());
\r
247 errln("Damaged range start is incorrect");
\r
250 verifyParagraphCount(target);
\r
253 if (!before.equals(target.paragraphStyleAt(Math.max(start-1, 0)))) {
\r
254 errln("Incorrect paragraph style before modified range");
\r
257 int lengthDelta = (srcLimit-srcStart) - (limit-start);
\r
258 int indexAfterInsert = Math.min(target.length(), limit + lengthDelta);
\r
259 if (!after.equals(target.paragraphStyleAt(indexAfterInsert))) {
\r
260 errln("Incorrect paragraph style after modified range");
\r
263 if (srcHasPBreak) {
\r
264 int startP = target.paragraphLimit(start);
\r
265 int limitOfTest = target.paragraphStart(indexAfterInsert);
\r
267 int offset = start - srcStart;
\r
269 while (startP < limitOfTest) {
\r
270 int limitP = target.paragraphLimit(startP);
\r
271 if (src.paragraphLimit(startP-offset) + offset != limitP) {
\r
272 errln("paragraph limits are not consistent");
\r
274 if (!src.paragraphStyleAt(startP-offset)
\r
275 .equals(target.paragraphStyleAt(startP))) {
\r
276 errln("paragraph styles are not consistent");
\r
282 for (int i=start; i < start+(srcLimit-srcStart); i++) {
\r
283 if (!after.equals(target.paragraphStyleAt(i))) {
\r
284 errln("paragraph style changed unexpectedly");
\r
290 private void verifyParagraphCount(MConstText text) {
\r
293 int textLength = text.length();
\r
295 if (textLength == 0) {
\r
299 for (int s=0; s < textLength; s = text.paragraphLimit(s)) {
\r
302 if (isParagraphBreak(text.at(textLength-1))) {
\r
308 for (int i=0; i < textLength; i++) {
\r
309 if (isParagraphBreak(text.at(i))) {
\r
314 if (sepCount + 1 != pCount) {
\r
315 logln("sepCount=" + sepCount + "; pCount=" + pCount);
\r
316 errln("Paragraph count is not consistent with characters");
\r
320 // private void checkEndpoint(MConstText text) {
\r
322 // boolean emptyFinalParagraph;
\r
323 // int length = text.length();
\r
325 // if (length != 0) {
\r
326 // char ch = text.at(length-1);
\r
327 // emptyFinalParagraph = isParagraphBreak(ch);
\r
330 // emptyFinalParagraph = true;
\r
333 // if ((text.paragraphStart(length) == length) != emptyFinalParagraph) {
\r
334 // errln("Final paragraph length is incorrect");
\r