]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_2_1-src/src/com/ibm/richtext/test/unit/TestMText.java
icu4jsrc
[Dictionary.git] / jars / icu4j-4_2_1-src / src / com / ibm / richtext / test / unit / TestMText.java
1 /*\r
2  * (C) Copyright IBM Corp. 1998-2008.  All Rights Reserved.\r
3  *\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
12  */\r
13 package com.ibm.richtext.test.unit;\r
14 \r
15 import com.ibm.icu.dev.test.TestFmwk;\r
16 \r
17 import com.ibm.richtext.textlayout.attributes.AttributeMap;\r
18 import com.ibm.richtext.textlayout.attributes.TextAttribute;\r
19 \r
20 import com.ibm.richtext.styledtext.MConstText;\r
21 import com.ibm.richtext.styledtext.MText;\r
22 import com.ibm.richtext.styledtext.StyledText;\r
23 import com.ibm.richtext.styledtext.StyleModifier;\r
24 \r
25 import java.text.CharacterIterator;\r
26 import java.util.Random;\r
27 \r
28 import java.io.*;\r
29 \r
30 public class TestMText extends TestFmwk {\r
31 \r
32     static final String COPYRIGHT =\r
33                 "(C) Copyright IBM Corp. 1998-1999 - All Rights Reserved";\r
34     public static void main(String[] args) throws Exception {\r
35 \r
36         new TestMText().run(args);\r
37     }\r
38     \r
39     private static final int TEST_ITERATIONS = 5000;\r
40     private static final int STYLE_TEST_ITERATIONS = 5000;\r
41     private static final long RAND_SEED = 598436;\r
42 \r
43     private static final int NOT_IN_MONKEY_TEST = -5000;\r
44     private int testIteration = NOT_IN_MONKEY_TEST;\r
45     private int theCase = NOT_IN_MONKEY_TEST;\r
46     \r
47     private static StyleModifier createMinusModifier(final Object attr) {\r
48         return new StyleModifier() {\r
49             public AttributeMap modifyStyle(AttributeMap style) {\r
50                 return style.removeAttribute(attr);\r
51             }\r
52         };\r
53     }\r
54 \r
55     public void test() {\r
56     \r
57         simpleTest();\r
58         styleTest();\r
59         monkeyTest(true);\r
60     }\r
61     \r
62     public void simpleTest() {\r
63 \r
64         AttributeMap boldStyle = new AttributeMap(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);\r
65         AttributeMap italicStyle = new AttributeMap(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE);\r
66 \r
67         MConstText allBold = new StyledText("bbbbb", boldStyle);\r
68         MConstText allItalic = new StyledText("iii", italicStyle);\r
69         MConstText plain = new StyledText("pppppp", AttributeMap.EMPTY_ATTRIBUTE_MAP);\r
70 \r
71         {\r
72             MText buf = new StyledText();\r
73             int ts = buf.getTimeStamp();\r
74             buf.append(allBold);\r
75             buf.append(allItalic);\r
76 \r
77             if (ts == buf.getTimeStamp()) {\r
78                 errln("Time stamp not incremented");\r
79             }\r
80 \r
81             // should be bbbbbiii now\r
82 \r
83             if (buf.length() != allBold.length() + allItalic.length()) {\r
84                 errln("Length is wrong.");\r
85             }\r
86 \r
87             for (int i=0; i < buf.length(); i++) {\r
88 \r
89                 char rightChar;\r
90                 AttributeMap rightStyle;\r
91 \r
92                 if (i < allBold.length()) {\r
93                     rightChar = allBold.at(0);\r
94                     rightStyle = boldStyle;\r
95                 }\r
96                 else {\r
97                     rightChar = allItalic.at(0);\r
98                     rightStyle = italicStyle;\r
99                 }\r
100 \r
101                 if (buf.at(i) != rightChar) {\r
102                     errln("Character is wrong.");\r
103                 }\r
104                 if (!buf.characterStyleAt(i).equals(rightStyle)) {\r
105                     errln("Style is wrong.");\r
106                 }\r
107             }\r
108 \r
109             int pos = 0;\r
110 \r
111             if (!buf.characterStyleAt(pos).equals(boldStyle)) {\r
112                 errln("First style is wrong.");\r
113             }\r
114             if (buf.characterStyleLimit(pos) != allBold.length()) {\r
115                 errln("Run length is wrong.");\r
116             }\r
117 \r
118             pos = allBold.length();\r
119 \r
120             if (!buf.characterStyleAt(pos).equals(italicStyle)) {\r
121                 errln("Second style is wrong.");\r
122             }\r
123             if (buf.characterStyleLimit(pos) != buf.length()) {\r
124                 errln("Run length is wrong.");\r
125             }\r
126 \r
127             {\r
128                 buf.resetDamagedRange();\r
129                 int oldLength = buf.length();\r
130                 buf.replace(buf.length(), buf.length(), allBold, 0, allBold.length());\r
131                 // bbbbbiiibbbbb\r
132 \r
133                 if (buf.damagedRangeStart() != oldLength) {\r
134                     errln("Damaged range start is incorrect");\r
135                 }\r
136                 if (buf.damagedRangeLimit() != buf.length()) {\r
137                     errln("Damaged range limit is incorrect");\r
138                 }\r
139             }\r
140 \r
141             int start = allBold.length();\r
142             int limit = start + allItalic.length();\r
143             buf.remove(start, limit);\r
144             // bbbbbbbbbb\r
145 \r
146             if (buf.length() != 2 * allBold.length()) {\r
147                 errln("Text should be twice the length of bold text.");\r
148             }\r
149 \r
150             pos = buf.length() / 2;\r
151             if (buf.characterStyleStart(pos) != 0 ||\r
152                             buf.characterStyleLimit(pos) != buf.length()) {\r
153                 errln("Run range is wrong.");\r
154             }\r
155             if (!buf.characterStyleAt(pos).equals(boldStyle)) {\r
156                 errln("Run style is wrong.");\r
157             }\r
158 \r
159             ts = buf.getTimeStamp();\r
160             CharacterIterator cIter = buf.createCharacterIterator();\r
161             for (char ch = cIter.first(); ch != CharacterIterator.DONE; ch = cIter.next()) {\r
162                 if (ch != allBold.at(0)) {\r
163                     errln("Character is wrong.");\r
164                 }\r
165             }\r
166 \r
167             if (ts != buf.getTimeStamp()) {\r
168                 errln("Time stamp should not have changed");\r
169             }\r
170 \r
171             buf.replace(0, 1, plain, 0, plain.length());\r
172 \r
173             if (ts == buf.getTimeStamp()) {\r
174                 errln("Time stamp not incremented");\r
175             }\r
176 \r
177             // ppppppbbbbbbbbb\r
178             buf.replace(plain.length(), buf.length(), allItalic, 0, allItalic.length());\r
179             // ppppppiii\r
180 \r
181             if (buf.length() != allItalic.length()+plain.length()) {\r
182                 errln("Length is wrong.");\r
183             }\r
184 \r
185             pos = 0;\r
186             if (buf.characterStyleLimit(pos) != plain.length()) {\r
187                 errln("Run limit is wrong.");\r
188             }\r
189 \r
190             pos = plain.length();\r
191             if (buf.characterStyleLimit(pos) != buf.length()) {\r
192                 errln("Run limit is wrong.");\r
193             }\r
194 \r
195             buf.replace(plain.length(), plain.length(), allBold, 0, allBold.length());\r
196             // ppppppbbbbbiii\r
197 \r
198             AttributeMap st = buf.characterStyleAt(1);\r
199             if (!st.equals(AttributeMap.EMPTY_ATTRIBUTE_MAP)) {\r
200                 errln("Style is wrong.");\r
201             }\r
202             if (buf.characterStyleStart(1) != 0 || buf.characterStyleLimit(1) != plain.length()) {\r
203                 errln("Style start is wrong.");\r
204             }\r
205 \r
206             st = buf.characterStyleAt(buf.length() - 1);\r
207             if (!st.equals(italicStyle)) {\r
208                 errln("Style is wrong.");\r
209             }\r
210             if (buf.characterStyleStart(buf.length() - 1) != plain.length()+allBold.length()) {\r
211                 errln("Style start is wrong.");\r
212             }\r
213 \r
214             if (buf.characterStyleLimit(buf.length() - 1) != buf.length()) {\r
215                 errln("Style limit is wrong.");\r
216             }\r
217         }\r
218     }\r
219 \r
220     private static int randInt(Random rand, int limit) {\r
221 \r
222         return randInt(rand, 0, limit);\r
223     }\r
224 \r
225     private static int randInt(Random rand, int start, int limit) {\r
226 \r
227         if (start > limit) {\r
228             throw new IllegalArgumentException("Range length is negative.");\r
229         }\r
230         else if (start == limit) {\r
231             return start;\r
232         }\r
233 \r
234         return start + (Math.abs(rand.nextInt())%(limit-start)) ;\r
235     }\r
236 \r
237     public void styleTest() {\r
238 \r
239         MText text = new StyledText("0123456789", AttributeMap.EMPTY_ATTRIBUTE_MAP);\r
240 \r
241         AttributeMap[] styles = new AttributeMap[text.length()];\r
242         for (int i=0; i < styles.length; i++) {\r
243             styles[i] = AttributeMap.EMPTY_ATTRIBUTE_MAP;\r
244         }\r
245         AttributeMap[] oldStyles = new AttributeMap[styles.length];\r
246         System.arraycopy(styles, 0, oldStyles, 0, styles.length);\r
247 \r
248         AttributeMap bigStyle = new AttributeMap(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON).\r
249                                                     addAttribute(TextAttribute.SIZE, new Float(23.0f));\r
250 \r
251         StyleModifier[] modifiers = {\r
252             StyleModifier.createReplaceModifier(new AttributeMap(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD)),\r
253             StyleModifier.createAddModifier(new AttributeMap(TextAttribute.WEIGHT, new Float(1.0f))),\r
254             createMinusModifier(TextAttribute.WEIGHT),\r
255 \r
256             StyleModifier.createAddModifier(new AttributeMap(TextAttribute.POSTURE, new Float(0.0f))),\r
257             StyleModifier.createReplaceModifier(new AttributeMap(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE)),\r
258             createMinusModifier(TextAttribute.POSTURE),\r
259 \r
260             StyleModifier.createAddModifier(bigStyle),\r
261             StyleModifier.createReplaceModifier(bigStyle),\r
262             createMinusModifier(bigStyle.getKeySet())\r
263         };\r
264 \r
265         Random rand = new Random(RAND_SEED);\r
266         final int stopAt = 4;\r
267 \r
268         for (int testItr=0; testItr < STYLE_TEST_ITERATIONS + 1; testItr++) {\r
269 \r
270             System.arraycopy(styles, 0, oldStyles, 0, styles.length);\r
271 \r
272             int startingAt = Integer.MAX_VALUE;\r
273             int endingAt = Integer.MIN_VALUE;\r
274             int oldTs = text.getTimeStamp();\r
275 \r
276             // hack way to do an invariant check before starting...\r
277             if (testItr != 0) {\r
278                 // modify styles\r
279                 text.resetDamagedRange();\r
280                 startingAt = randInt(rand, styles.length+1);\r
281                 endingAt = randInt(rand, startingAt, styles.length+1);\r
282                 StyleModifier modifier = modifiers[randInt(rand, modifiers.length)];\r
283 \r
284                 if (testItr == stopAt) {\r
285                     testItr = stopAt;\r
286                 }\r
287                 text.modifyCharacterStyles(startingAt, endingAt, modifier);\r
288 \r
289                 for (int j=startingAt; j < endingAt; j++) {\r
290                     styles[j] = modifier.modifyStyle(styles[j]);\r
291                 }\r
292             }\r
293 \r
294             // check invariants\r
295             AttributeMap oldStyle = null;\r
296             int textLength = text.length();\r
297             for (int runStart = 0; runStart < textLength;) {\r
298 \r
299                 AttributeMap currentStyle = text.characterStyleAt(runStart);\r
300                 int runLimit = text.characterStyleLimit(runStart);\r
301                 if (runStart >= runLimit) {\r
302                     errln("Run length is not positive");\r
303                 }\r
304                 if (currentStyle.equals(oldStyle)) {\r
305                     errln("Styles didn't merge");\r
306                 }\r
307 \r
308                 for (int pos=runStart; pos < runLimit; pos++) {\r
309                     AttributeMap charStyleAtPos = text.characterStyleAt(pos);\r
310                     if (currentStyle != charStyleAtPos) {\r
311                         errln("Iterator style is not equal to text style at " + pos + ".");\r
312                     }\r
313                     AttributeMap expected = styles[pos];\r
314                     if (!currentStyle.equals(expected)) {\r
315                         errln("Iterator style doesn't match expected style at " + pos + ".");\r
316                     }\r
317                     if (!(text.characterStyleStart(pos) == runStart) ||\r
318                             !(text.characterStyleLimit(pos) == runLimit)) {\r
319                         errln("style run start / limit is not consistent");\r
320                     }\r
321                 }\r
322                 runStart = runLimit;\r
323             }\r
324             if (textLength > 0) {\r
325                 if (text.characterStyleAt(textLength) !=\r
326                             text.characterStyleAt(textLength-1)) {\r
327                     errln("Character styles at end aren't the same");\r
328                 }\r
329             }\r
330 \r
331             // check damaged range:\r
332             int damageStart = Integer.MAX_VALUE;\r
333             int damageLimit = Integer.MIN_VALUE;\r
334             for (int i=0; i < textLength; i++) {\r
335                 if (!styles[i].equals(oldStyles[i])) {\r
336                     damageStart = Math.min(i, damageStart);\r
337                     damageLimit = Math.max(i+1, damageLimit);\r
338                 }\r
339             }\r
340             if (damageStart != text.damagedRangeStart() ||\r
341                             damageLimit != text.damagedRangeLimit()) {\r
342                 logln("Test iteration: " + testItr);\r
343                 logln("startingAt: " + startingAt + ";  endingAt: " + endingAt);\r
344                 logln("damageStart: " + damageStart + ";  damageLimit: " + damageLimit);\r
345                 logln("text.rangeStart: " + text.damagedRangeStart() +\r
346                                    "text.rangeLimit: " + text.damagedRangeLimit());\r
347                 errln("Damage range start or limit is not expected value");\r
348             }\r
349 \r
350             if ((damageLimit == Integer.MIN_VALUE) != (oldTs == text.getTimeStamp())) {\r
351 \r
352                 errln("timeStamp is incorrect");\r
353             }\r
354         }\r
355     }\r
356 \r
357     public void msg(String message, int level, boolean incCount, boolean newln) {\r
358         if (level == ERR && testIteration != NOT_IN_MONKEY_TEST) {\r
359             message = "testIteration="+testIteration+"; testCase="+theCase+message;\r
360         }\r
361         super.msg(message, level, incCount, newln);\r
362     }\r
363     \r
364     /**\r
365     * Perform a random series of operations on an MText and\r
366     * check the result of each operation against a set of invariants.\r
367     */\r
368     public void monkeyTest(boolean streaming) {\r
369 \r
370         /*\r
371             You can add any operation to the switch statement provided it\r
372             preserves the following invariants:\r
373             - The String plainText contains the same text as the StyledStringBuffer.\r
374               Obviously, for the test to be meaningful plainText must be computed\r
375               independently of the buffer (ie don't write:  plainText = buf.getStyledString().toString()).\r
376             - Every 'b' is bold, every 'i' is italic, every 'p' is plain, and\r
377               no other characters appear in the text.\r
378         */\r
379 \r
380         AttributeMap boldAttrs = new AttributeMap(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);\r
381         AttributeMap italicAttrs = new AttributeMap(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE);\r
382         AttributeMap emptyAttrs = AttributeMap.EMPTY_ATTRIBUTE_MAP;\r
383 \r
384         final String bold1Str_getString = "b";\r
385         MConstText bold1Str = new StyledText(bold1Str_getString, boldAttrs);\r
386 \r
387         final String italic1Str_getString = "i";\r
388         MConstText italic1Str = new StyledText(italic1Str_getString, italicAttrs);\r
389 \r
390         final String plain1Str_getString = "p";\r
391         MConstText plain1Str = new StyledText(plain1Str_getString, emptyAttrs);\r
392 \r
393         StyledText temp = new StyledText();\r
394         temp.append(bold1Str);\r
395         temp.append(italic1Str);\r
396         final String boldItalicStr_getString = bold1Str_getString.concat(italic1Str_getString);\r
397         MConstText boldItalicStr = temp;\r
398 \r
399         temp = new StyledText();\r
400         temp.append(bold1Str);\r
401         temp.append(bold1Str);\r
402         temp.append(bold1Str);\r
403         final String bold3Str_getString = "bbb";\r
404         MConstText bold3Str = temp;\r
405 \r
406         MText buf = new StyledText();\r
407         String plainText = new String();\r
408         //int testIteration=0; - now instance variables so errln can report it\r
409         //int theCase=0;\r
410 \r
411         final int NUM_CASES = 14;\r
412         boolean[] casesExecuted = new boolean[NUM_CASES];\r
413         final int stopAt = -1;\r
414         Random rand = new Random(RAND_SEED);\r
415 \r
416         final String ALWAYS_DIFFERENT = "\uFEFF";\r
417 \r
418             for (testIteration=0; testIteration < TEST_ITERATIONS; testIteration++) {\r
419 \r
420                 theCase = randInt(rand, NUM_CASES);\r
421 \r
422                 casesExecuted[theCase] = true;\r
423 \r
424                 if (testIteration == stopAt) {\r
425                     testIteration = stopAt;  // Convenient place to put breakpoint\r
426                 }\r
427 \r
428                 int timeStamp = buf.getTimeStamp();\r
429                 String oldPlainText = plainText;\r
430                 if (oldPlainText == null) {\r
431                     errln("oldPlainText is null!");\r
432                 }\r
433 \r
434                 switch (theCase) {\r
435 \r
436                     case 0:\r
437                         // create new string; replace chars at start with different style\r
438                         buf = new StyledText();\r
439                         buf.append(bold3Str);\r
440                         buf.replace(0, 1, italic1Str, 0, italic1Str.length());\r
441                         buf.replace(0, 0, italic1Str, 0, italic1Str.length());\r
442 \r
443                         plainText = bold3Str_getString.substring(1, bold3Str.length());\r
444                         plainText = italic1Str_getString.concat(plainText);\r
445                         plainText = italic1Str_getString.concat(plainText);\r
446                         oldPlainText = null;\r
447                         break;\r
448 \r
449                     case 1:\r
450                         // delete the last character from the string\r
451                         if (buf.length() == 0) {\r
452                             buf.replace(0, 0, italic1Str, 0, italic1Str.length());\r
453                             plainText = italic1Str_getString;\r
454                             oldPlainText = ALWAYS_DIFFERENT;\r
455                         }\r
456                         buf.remove(buf.length()-1, buf.length());\r
457                         plainText = plainText.substring(0, plainText.length()-1);\r
458                         break;\r
459 \r
460                     case 2:\r
461                         // replace some of the buffer with boldItalicStr\r
462                         int rStart = randInt(rand, buf.length()+1);\r
463                         int rStop = randInt(rand, rStart, buf.length()+1);\r
464                         buf.replace(rStart, rStop, boldItalicStr);\r
465                         {\r
466                             String newString = (rStart>0)? plainText.substring(0, rStart) : new String();\r
467                             newString = newString.concat(boldItalicStr_getString);\r
468                             if (rStop < plainText.length())\r
469                                 newString = newString.concat(plainText.substring(rStop, plainText.length()));\r
470                             oldPlainText = ALWAYS_DIFFERENT;\r
471                             plainText = newString;\r
472                         }\r
473                         break;\r
474 \r
475                     case 3:\r
476                         // repeatedly insert strings into the center of the buffer\r
477                         {\r
478                             int insPos = buf.length() / 2;\r
479                             String prefix = plainText.substring(0, insPos);\r
480                             String suffix = plainText.substring(insPos, plainText.length());\r
481                             String middle = new String();\r
482                             for (int ii=0; ii<4; ii++) {\r
483                                 MConstText which = (ii%2==0)? boldItalicStr : bold3Str;\r
484                                 String whichString = (ii%2==0)? boldItalicStr_getString : bold3Str_getString;\r
485                                 int tempPos = insPos+middle.length();\r
486                                 buf.insert(tempPos, which);\r
487                                 middle = middle.concat(whichString);\r
488                             }\r
489                             plainText = prefix.concat(middle).concat(suffix);\r
490                             oldPlainText = ALWAYS_DIFFERENT;\r
491                         }\r
492                         break;\r
493 \r
494                     case 4:\r
495                     // insert bold1Str at end\r
496                         buf.append(bold1Str);\r
497                         plainText = plainText.concat(bold1Str_getString);\r
498                         break;\r
499 \r
500                     case 5:\r
501                     // delete a character from the string\r
502                         if (buf.length() > 0) {\r
503                             int delPos = randInt(rand, buf.length()-1);\r
504                             buf.remove(delPos, delPos+1);\r
505                             plainText = plainText.substring(0, delPos).concat(plainText.substring(delPos+1));\r
506                         }\r
507                         else {\r
508                             buf.replace(0, 0, plain1Str, 0, plain1Str.length());\r
509                             plainText = plain1Str_getString;\r
510                         }\r
511                         break;\r
512 \r
513                     case 6:\r
514                     // replace the contents of the buffer (except the first character) with itself\r
515                         {\r
516                             int start = buf.length() > 1? 1 : 0;\r
517                             buf.replace(start, buf.length(), buf);\r
518                             plainText = plainText.substring(0, start).concat(plainText);\r
519                             if (buf.length() > 0) {\r
520                                 oldPlainText = ALWAYS_DIFFERENT;\r
521                             }\r
522                         }\r
523                         break;\r
524 \r
525                     case 7:\r
526                     // append the contents of the buffer to itself\r
527                         {\r
528                             MConstText content = buf;\r
529                             buf.insert(buf.length(), content);\r
530                             plainText = plainText.concat(plainText);\r
531                         }\r
532                         break;\r
533 \r
534                     case 8:\r
535                     // replace the buffer with boldItalicStr+bold3Str\r
536                         {\r
537                             MText replacement = new StyledText();\r
538                             replacement.append(boldItalicStr);\r
539                             replacement.append(bold3Str);\r
540                             buf.replace(0, buf.length(), replacement, 0, replacement.length());\r
541                             plainText = boldItalicStr_getString.concat(bold3Str_getString);\r
542                             oldPlainText = ALWAYS_DIFFERENT;\r
543                         }\r
544                         break;\r
545 \r
546                     case 9:\r
547                     // insert bold1Str at end - same as 4 but uses different API\r
548                         buf.replace(buf.length(),\r
549                                     buf.length(),\r
550                                     bold1Str_getString.toCharArray(),\r
551                                     0,\r
552                                     bold1Str_getString.length(),\r
553                                     boldAttrs);\r
554                         plainText = plainText.concat(bold1Str_getString);\r
555                         break;\r
556 \r
557                     case 10:\r
558                     // remove all\r
559                         buf.remove();\r
560                         plainText = "";\r
561                         oldPlainText = ALWAYS_DIFFERENT;\r
562                         break;\r
563 \r
564                     case 11:\r
565                     // remove all - different way\r
566                         buf.remove(0, buf.length());\r
567                         plainText = "";\r
568                         break;\r
569 \r
570                     case 12:\r
571                         // insert 'i' at 3rd character (or last, if fewer than 3 chars)\r
572                         {\r
573                             int insPos = Math.min(buf.length(), 3);\r
574                             buf.replace(insPos, insPos, 'i', italicAttrs);\r
575                             plainText = (plainText.substring(0, insPos)).\r
576                                         concat(italic1Str_getString).\r
577                                         concat(plainText.substring(insPos));\r
578                         }\r
579                         break;\r
580 \r
581                     case 13:\r
582                         if (streaming) {\r
583                             Throwable error = null;\r
584                             try {\r
585                                 ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();\r
586                                 ObjectOutputStream objOut = new ObjectOutputStream(bytesOut);\r
587                                 objOut.writeObject(buf);\r
588 \r
589                                 ByteArrayInputStream bytesIn =\r
590                                                 new ByteArrayInputStream(bytesOut.toByteArray());\r
591                                 ObjectInputStream objIn = new ObjectInputStream(bytesIn);\r
592                                 buf = (MText) objIn.readObject();\r
593                                 oldPlainText = null;\r
594                             }\r
595                             catch(IOException e) {\r
596                                 error = e;\r
597                             }\r
598                             catch(ClassNotFoundException e) {\r
599                                 error = e;\r
600                             }\r
601                             if (error != null) {\r
602                                 error.printStackTrace();\r
603                                 errln("Streaming problem: " + error);\r
604                             }\r
605                         }\r
606                         break;\r
607 \r
608                     default:\r
609                         errln("Invalid case.");\r
610                 }\r
611 \r
612                 // Check time stamp if oldPlainText != null.\r
613                 // Time stamp should be different iff\r
614                 // oldPlainText == plainText\r
615                 if (oldPlainText != null) {\r
616                     if ((timeStamp==buf.getTimeStamp()) !=\r
617                                     oldPlainText.equals(plainText)) {\r
618                         logln("plainText hashCode: " + plainText.hashCode());\r
619                         logln("oldPlainText hashCode: " + oldPlainText.hashCode());\r
620                         errln("Time stamp is incorrect");\r
621                     }\r
622                 }\r
623 \r
624                 // now check invariants:\r
625                 if (plainText.length() != buf.length()) {\r
626                     errln("Lengths don't match");\r
627                 }\r
628 \r
629                 for (int j=0; j < buf.length(); j++) {\r
630                     if (buf.at(j) != plainText.charAt(j)) {\r
631                         errln("Characters don't match.");\r
632                     }\r
633                 }\r
634 \r
635                 int start;\r
636                 for (start = 0; start < buf.length();) {\r
637 \r
638                     if (start != buf.characterStyleStart(start)) {\r
639                         errln("style start is wrong");\r
640                     }\r
641                     int limit = buf.characterStyleLimit(start);\r
642                     if (start >= limit) {\r
643                         errln("start >= limit");\r
644                     }\r
645                     char current = plainText.charAt(start);\r
646 \r
647                     AttributeMap comp = null;\r
648                     if (current == 'p') {\r
649                         comp = emptyAttrs;\r
650                     }\r
651                     else if (current == 'b') {\r
652                         comp = boldAttrs;\r
653                     }\r
654                     else if (current == 'i') {\r
655                         comp = italicAttrs;\r
656                     }\r
657                     else {\r
658                         errln("An invalid character snuck in!");\r
659                     }\r
660 \r
661                     AttributeMap startStyle = buf.characterStyleAt(start);\r
662                     if (!comp.equals(startStyle)) {\r
663                         errln("Style is not expected style.");\r
664                     }\r
665 \r
666                     for (int j = start; j < limit; j++) {\r
667                         if (plainText.charAt(j) != current) {\r
668                             errln("Character doesn't match style.");\r
669                         }\r
670                         if (buf.characterStyleAt(j) != startStyle) {\r
671                             errln("Incorrect style in run");\r
672                         }\r
673                     }\r
674 \r
675                     if (limit < buf.length()) {\r
676                         if (plainText.charAt(limit) == current) {\r
677                             errln("Style run ends too soon.");\r
678                         }\r
679                     }\r
680                     start = limit;\r
681                 }\r
682                 if (start != buf.length()) {\r
683                     errln("Last limit is not buffer length.");\r
684                 }\r
685 \r
686                 // won't try to compute and check damaged range;  however,\r
687                 // if nonempty it should always be within text\r
688                 int damageStart = buf.damagedRangeStart();\r
689                 int damageLimit = buf.damagedRangeLimit();\r
690                 if (damageStart == Integer.MAX_VALUE) {\r
691                     if (damageLimit != Integer.MIN_VALUE) {\r
692                         errln("Invalid empty interval");\r
693                     }\r
694                 }\r
695                 else {\r
696                     if (damageStart > damageLimit) {\r
697                         errln("Damage range inverted");\r
698                     }\r
699                     if (damageStart < 0 || damageLimit > buf.length()) {\r
700                         errln("Damage range endpoint out of bounds");\r
701                     }\r
702                 }\r
703             }\r
704 \r
705         testIteration = NOT_IN_MONKEY_TEST;\r
706         \r
707         boolean allCasesExecuted = true;\r
708         for (int index=0; index < NUM_CASES; index++) {\r
709             allCasesExecuted &= casesExecuted[index];\r
710             if (casesExecuted[index] == false) {\r
711                 logln("Case " + index + " not executed.");\r
712             }\r
713         }\r
714         //if (allCasesExecuted) {\r
715         //    logln("All cases executed.");\r
716         //}\r
717     }\r
718 }\r