1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 package ifc.i18n;
29 
30 import java.util.Vector;
31 
32 import lib.MultiMethodTest;
33 import lib.Status;
34 import lib.StatusException;
35 
36 import com.sun.star.i18n.Boundary;
37 import com.sun.star.i18n.LineBreakHyphenationOptions;
38 import com.sun.star.i18n.LineBreakResults;
39 import com.sun.star.i18n.LineBreakUserOptions;
40 import com.sun.star.i18n.ScriptType;
41 import com.sun.star.i18n.WordType;
42 import com.sun.star.i18n.XBreakIterator;
43 import com.sun.star.lang.Locale;
44 
45 /**
46 * Testing <code>com.sun.star.i18n.XBreakIterator</code>
47 * interface methods :
48 * <ul>
49 *  <li><code> nextCharacters()</code></li>
50 *  <li><code> previousCharacters()</code></li>
51 *  <li><code> nextWord()</code></li>
52 *  <li><code> previousWord()</code></li>
53 *  <li><code> getWordBoundary()</code></li>
54 *  <li><code> getWordType()</code></li>
55 *  <li><code> isBeginWord()</code></li>
56 *  <li><code> isEndWord()</code></li>
57 *  <li><code> beginOfSentence()</code></li>
58 *  <li><code> endOfSentence()</code></li>
59 *  <li><code> getLineBreak()</code></li>
60 *  <li><code> beginOfScript()</code></li>
61 *  <li><code> endOfScript()</code></li>
62 *  <li><code> nextScript()</code></li>
63 *  <li><code> previousScript()</code></li>
64 *  <li><code> getScriptType()</code></li>
65 *  <li><code> beginOfCharBlock()</code></li>
66 *  <li><code> endOfCharBlock()</code></li>
67 *  <li><code> nextCharBlock()</code></li>
68 *  <li><code> previousCharBlock()</code></li>
69 * </ul> <p>
70 * This test needs the following object relations :
71 * <ul>
72 *  <li> <code>'Locale'</code>
73 *   (of type <code>com.sun.star.lang.Locale</code>):
74 *   this locale is used as locale argument for tested methods.
75 *  </li>
76 *  <li> <code>'UnicodeString'</code>
77 *   (of type <code>String</code>): Unicode string which is passed
78 *   to methods except 'CharacterBlock' methods.
79 *  </li>
80 * <ul> <p>
81 * @see com.sun.star.i18n.XBreakIterator
82 */
83 public class _XBreakIterator extends MultiMethodTest {
84 
85     public XBreakIterator oObj = null;
86 
87     Locale locale = null;
88     String UnicodeString = null;
89 
90     short wordType = WordType.ANYWORD_IGNOREWHITESPACES;
91 
92     /**
93      * Retrieves object relations.
94      * @throws StatusException If one of relations not found.
95      */
96     protected void before() {
97         locale = (Locale)tEnv.getObjRelation("Locale");
98         if (locale == null) {
99             throw new StatusException
100                 (Status.failed("Relation 'Locale' not found")) ;
101         }
102 
103         UnicodeString = (String)tEnv.getObjRelation("UnicodeString");
104         if (UnicodeString == null) {
105             throw new StatusException(Status.failed
106                 ("Relation 'UnicodeString' not found")) ;
107         }
108     }
109 
110     /**
111      * Compares returned next character positions with expected values. <p>
112      *
113      * Has <b>OK</b> status if position after travel and traveled length
114      * has expected values.
115      */
116     public void _nextCharacters() {
117         short nCharacterIteratorMode =
118             com.sun.star.i18n.CharacterIteratorMode.SKIPCHARACTER;
119 
120         int strLength = UnicodeString.length();
121 
122         //Start from position : Travel ... chars :
123         // Actual position after : How many chars traveled
124         int[][] nextCharacters = {
125             { 1, 5000, strLength , strLength - 1 },
126             { 10, 6, 16, 6}};
127 
128         boolean bRes = true;
129 
130         for(int i = 0; i < nextCharacters.length; i++) {
131             int[] lDone = new int[1];
132             long lRes = oObj.nextCharacters(UnicodeString, nextCharacters[i][0],
133                 locale, nCharacterIteratorMode, nextCharacters[i][1], lDone);
134             log.println("Expected result is: lRes = " + nextCharacters[i][2] +
135                         "; lDone = " + nextCharacters[i][3] );
136             log.println("Actual result is: lRes = " + lRes +
137                         "; lDone = " + lDone[0] );
138 
139             bRes = bRes && lRes == nextCharacters[i][2];
140             bRes = bRes && lDone[0] == nextCharacters[i][3];
141         }
142 
143         tRes.tested("nextCharacters()", bRes);
144     }
145 
146     /**
147      * Compares returned previous character positions with expected values. <p>
148      *
149      * Has <b>OK</b> status if position after travel and traveled length
150      * has expected values.
151      */
152     public void _previousCharacters() {
153         short nCharacterIteratorMode =
154             com.sun.star.i18n.CharacterIteratorMode.SKIPCHARACTER;
155 
156 
157         //Start from position : Travel ... chars : Actual position after :
158         //How many chars traveled
159         int[][] previousCharacters = {
160             {5, 5000, 0, 5},
161             {10, 6, 4, 6}};
162 
163         boolean bRes = true;
164         for(int i = 0; i < previousCharacters.length; i++) {
165             int[] lDone = new int[1];
166             int lRes = oObj.previousCharacters(UnicodeString,
167                 previousCharacters[i][0],
168                 locale, nCharacterIteratorMode,
169                 previousCharacters[i][1], lDone);
170             log.println("Expected result is: lRes = " + previousCharacters[i][2]
171                 + "; lDone = " + previousCharacters[i][3] );
172             log.println("Actual result is: lRes = " + lRes
173                 + "; lDone = " + lDone[0]);
174 
175             bRes = bRes && lRes == previousCharacters[i][2];
176             bRes = bRes && lDone[0] == previousCharacters[i][3];
177         }
178 
179         tRes.tested("previousCharacters()", bRes);
180     }
181 
182     Vector vBounds = new Vector();
183 
184     /**
185     * Saves bounds of all returned words for the future tests. <p>
186     * Has <b>OK</b> status.
187     */
188     public void _nextWord() {
189         int i = 0;
190 
191         while( i < UnicodeString.length() - 1 ) {
192             Boundary bounds = oObj.nextWord
193                 (UnicodeString, i, locale, wordType);
194             if (bounds.endPos - bounds.startPos > 3) {
195                 vBounds.add( bounds );
196                 log.println("Word " + vBounds.size() + "("
197                     + bounds.startPos + "," + bounds.endPos + "): '" +
198                     UnicodeString.substring(bounds.startPos,
199                                             bounds.endPos) + "'");
200             }
201             i = bounds.endPos - 1;
202         }
203         log.println("In text there are " + vBounds.size()
204             + " words, if count from left to right");
205         tRes.tested("nextWord()", true);
206     }
207 
208     /**
209     * Compares number of word bounds with number of word bounds saved
210     * by the method _nextWord().<p>
211     * Has <b>OK</b> status if number of word bounds are equal.
212     */
213     public void _previousWord() {
214         requiredMethod("nextWord()");
215 
216         int i = UnicodeString.length() - 1;
217         Vector vPrevBounds = new Vector();
218         while( i > 0  ) {
219             Boundary bounds =
220                 oObj.previousWord(UnicodeString, i, locale, wordType);
221             if (bounds.endPos - bounds.startPos > 3) {
222                 vPrevBounds.add( bounds );
223                 log.println("Word " + vPrevBounds.size() + "("
224                     + bounds.startPos + "," + bounds.endPos + "): '"
225                     + UnicodeString.substring(bounds.startPos, bounds.endPos)
226                     + "'");
227             }
228             i = bounds.startPos;
229         }
230         log.println("In text there are " + vPrevBounds.size()
231             + " words, if count from right to left");
232         tRes.tested("previousWord()", vPrevBounds.size() == vBounds.size() );
233     }
234 
235     /**
236      * For every word in array obtained by <code>nextWord</code> method test
237      * computes bounds of the word, passing its internal character position.<p>
238      *
239      * Has <b>OK</b> status if bounds calculated by <code>getWordBoundary()</code>
240      * method are the same as bounds obtained by <code>nextWord</code> method.
241      */
242     public void _getWordBoundary() {
243         requiredMethod("nextWord()");
244 
245         boolean bRes = true;
246 
247         for(int i = 0; i < vBounds.size(); i++) {
248             // calculate middle of the word
249             Boundary iBounds = (Boundary)vBounds.get(i);
250             int iPos = (iBounds.endPos - iBounds.startPos) / 2
251                         + iBounds.startPos;
252             Boundary bounds = oObj.getWordBoundary(UnicodeString, iPos,
253                 locale, wordType, true);
254             log.println("Expected result is: startPos = " + iBounds.startPos +
255                                  "; endPos = " + iBounds.endPos);
256             log.println("Actual result is: startPos = " + bounds.startPos
257                 + "; endPos = " + bounds.endPos + " Word is: '"
258                 + UnicodeString.substring(bounds.startPos, bounds.endPos) + "'");
259 
260             bRes = bRes && iBounds.startPos == bounds.startPos;
261             bRes = bRes && iBounds.endPos == bounds.endPos;
262         }
263 
264         tRes.tested("getWordBoundary()", bRes);
265     }
266 
267     /**
268      * For every word in array obtained by <code>nextWord</code> method test
269      * get its type, passing its internal character position.<p>
270      *
271      * Has <b>OK</b> status if every word has type <code>WordType.ANY_WORD</code>
272      */
273     public void _getWordType() {
274         requiredMethod("nextWord()");
275 
276         boolean bRes = true;
277 
278         for(int i = 0; i < vBounds.size(); i++) {
279             // calculate middle of the word
280             Boundary iBounds = (Boundary)vBounds.get(i);
281             int iPos = (iBounds.endPos - iBounds.startPos) / 2
282                         + iBounds.startPos;
283 
284             short type = oObj.getWordType(UnicodeString, iPos, locale);
285 
286             bRes = bRes && type == WordType.ANY_WORD;
287         }
288 
289         tRes.tested("getWordType()", bRes);
290     }
291 
292     /**
293      * For every word in array obtained by <code>nextWord</code> method test
294      * tries to determine if the character at a position starts a word.
295      * First word starting position is passed, then internal character
296      * position is passed. <p>
297      * Has <b>OK</b> status if in the first case <code>true</code>
298      * returned and in the second - <code>false</code> for every word.
299      */
300     public void _isBeginWord() {
301         requiredMethod("nextWord()");
302 
303         boolean bRes = true;
304 
305         for(int i = 0; i < vBounds.size(); i++) {
306             Boundary iBounds = (Boundary)vBounds.get(i);
307             boolean isBegin = oObj.isBeginWord(UnicodeString, iBounds.startPos,
308                                                locale, WordType.ANY_WORD);
309             bRes = bRes && isBegin;
310             boolean isNotBegin = !oObj.isBeginWord(UnicodeString,
311                     iBounds.startPos + 1, locale, WordType.ANY_WORD);
312             bRes = bRes && isNotBegin;
313 
314             log.println("At position + " + iBounds.startPos
315                 + " isBeginWord? " + isBegin);
316             log.println("At position + " + (iBounds.startPos + 1)
317                 + " isBeginWord? " + !isNotBegin);
318         }
319 
320         tRes.tested("isBeginWord()", bRes);
321     }
322 
323     /**
324      * For every word in array obtained by <code>nextWord</code> method test
325      * tries to determine if the character at a position ends a word.
326      * First word ending position is passed, then internal character
327      * position is passed. <p>
328      *
329      * Has <b>OK</b> status if in the first case <code>true</code>
330      * returned and in the second - <code>false</code> for every word.
331      */
332     public void _isEndWord() {
333         requiredMethod("nextWord()");
334 
335         boolean bRes = true;
336 
337         for(int i = 0; i < vBounds.size(); i++) {
338             Boundary iBounds = (Boundary)vBounds.get(i);
339             boolean isEnd = oObj.isEndWord(UnicodeString, iBounds.endPos,
340                 locale, WordType.ANY_WORD);
341             bRes = bRes && isEnd;
342             boolean isNotEnd = !oObj.isEndWord(UnicodeString,
343                 iBounds.endPos - 1, locale, WordType.ANY_WORD);
344             bRes = bRes && isNotEnd;
345 
346             log.println("At position + " + iBounds.endPos
347                 + " isEndWord? " + isEnd);
348             log.println("At position + " + (iBounds.endPos - 1)
349                 + " isEndWord? " + !isNotEnd);
350         }
351 
352         tRes.tested("isEndWord()", bRes);
353     }
354 
355     Vector vSentenceStart = new Vector();
356     /**
357      * Tries to find all sentences starting positions passing every character
358      * as position parameter and stores them. Then tries to pass invalid
359      * position parameters.
360      *
361      * Has <b>OK</b> status if -1 is returned for wrong position arguments.
362      */
363     public void _beginOfSentence() {
364         int iPos = 0;
365         while( iPos < UnicodeString.length() ) {
366             Integer start = new Integer( oObj.beginOfSentence(UnicodeString,
367                 iPos, locale) );
368             if (start.intValue() >= 0 && !vSentenceStart.contains(start) ) {
369                 vSentenceStart.add( start );
370                 log.println("Sentence " + vSentenceStart.size()
371                     + " : start from position " + start);
372             }
373             iPos++;
374         }
375 
376         //test for invalid nStartPosition
377         boolean bRes = oObj.beginOfSentence(UnicodeString, -10, locale) == -1;
378         bRes &= oObj.beginOfSentence(UnicodeString,
379             UnicodeString.length() + 1, locale) == -1;
380 
381         if (!bRes) {
382             log.println("When invalid position, returned value isn't equal to -1");
383         }
384 
385         tRes.tested("beginOfSentence()", bRes);
386     }
387 
388     /**
389      * For every sentence starting position found in
390      * <code>beginOfSentence()</code> test tries to compute end
391      * position of a sentence and checks that the end position is
392      * greater than starting.
393      * Then wrong position arguments are passed.
394      *
395      * Has <b>OK</b> status if the end position of every sentence
396      * greater than starting and -1 returned for invalid arguments.
397      */
398     public void _endOfSentence() {
399         boolean bRes = true;
400         for(int i = 0; i < vSentenceStart.size(); i++) {
401             int start = ((Integer)vSentenceStart.get(i)).intValue();
402             int end = oObj.endOfSentence(UnicodeString, start, locale);
403             bRes &= end > start;
404             log.println("Sentence " + i + " range is [" + start + ", "
405                 + end + "]");
406         }
407 
408         //test for invalid nStartPosition
409         boolean bInvRes = oObj.endOfSentence(UnicodeString, -10, locale) == -1;
410         bInvRes &= oObj.endOfSentence(UnicodeString,
411             UnicodeString.length() + 1, locale) == -1;
412 
413         if (!bInvRes) {
414             log.println("When invalid position, returned value isn't equal to -1");
415         }
416 
417         tRes.tested("endOfSentence()", bRes && bInvRes);
418     }
419 
420     /**
421     * Tries to break a string in position other than 0 iterating characters
422     * from the string beginning (Hyphenation is not used for a while). <p>
423     *
424     * Has <b>OK</b> status if non-zero break position was found and it is
425     * less or equal than position we trying to break.
426     */
427     public void _getLineBreak() {
428         boolean bRes = true;
429         LineBreakResults lineBreakResults;
430         LineBreakHyphenationOptions lineBreakHyphenationOptions =
431             new LineBreakHyphenationOptions();
432         LineBreakUserOptions lineBreakUserOptions = new LineBreakUserOptions();
433 
434         lineBreakUserOptions.applyForbiddenRules = false;
435         lineBreakUserOptions.allowHyphenateEnglish = false;
436 
437         int breakPos = 0;
438         int pos = 0;
439 
440         while(breakPos == 0 && pos < UnicodeString.length() ) {
441             lineBreakResults = oObj.getLineBreak(UnicodeString, pos,
442                 locale, 0, lineBreakHyphenationOptions, lineBreakUserOptions);
443             breakPos = lineBreakResults.breakIndex;
444             pos++;
445         }
446 
447         // finally the position of break must be found in the middle and
448         // it must be before the break position specified
449         bRes = breakPos <= pos && breakPos > 0;
450 
451         if (!bRes) {
452             log.println("The last position was: " + pos
453                 + ", and the break position was: " + breakPos);
454         }
455 
456         tRes.tested("getLineBreak()", bRes);
457     }
458 
459     // Asian type script
460     private static String katakana = new String(new char[] {0x30A1, 0x30A2}) ;
461     // Weak type script
462     private static String arrows = new String(new char[] {0x2190, 0x2191}) ;
463     // Complex type script
464     private static String arabic = new String(new char[] {0x0641, 0x0642}) ;
465 
466     /**
467     * Tries to find the begining of the nearest script specified
468     * relatively to position passed. <p>
469     * Has <b>OK</b> status if the starting position of script is returned.
470     */
471     public void _beginOfScript() {
472         String multiScript = "ab" + katakana  ;
473 
474         int pos = oObj.beginOfScript(multiScript, 3, ScriptType.ASIAN) ;
475 
476         log.println("Position = " + pos) ;
477 
478         tRes.tested("beginOfScript()", pos == 2) ;
479     }
480 
481     /**
482     * Tries to find the end of the nearest script specified
483     * relatively to position passed. <p>
484     * Has <b>OK</b> status if the end position of script is returned.
485     */
486     public void _endOfScript() {
487         String multiScript = "ab" + katakana + "cd" ;
488 
489         int pos = oObj.endOfScript(multiScript, 2, ScriptType.ASIAN) ;
490 
491         log.println("Position = " + pos) ;
492 
493         tRes.tested("endOfScript()", pos == 4) ;
494     }
495 
496     /**
497     * Tries to find the next script starting position specified
498     * relatively to position passed. <p>
499     * Has <b>OK</b> status if the appropriate position is returned.
500     */
501     public void _nextScript() {
502         String multiScript = "ab" + katakana + "cd"  ;
503 
504         int pos = oObj.nextScript(multiScript, 0, ScriptType.LATIN) ;
505 
506         log.println("Position = " + pos) ;
507 
508         tRes.tested("nextScript()", pos == 4) ;
509     }
510 
511     /**
512     * Tries to find the previous script starting position specified
513     * relatively to position passed. <p>
514     * Has <b>OK</b> status if the appropriate position is returned.
515     */
516     public void _previousScript() {
517         String multiScript = "ab" + katakana + "cd"  ;
518 
519         int pos = oObj.previousScript(multiScript, 5, ScriptType.ASIAN) ;
520 
521         log.println("Position = " + pos) ;
522 
523         tRes.tested("previousScript()", pos == 2) ;
524     }
525 
526     /**
527     * Tries to determine script type (of all four types). <p>
528     * Has <b>OK</b> status if <code>LATIN</code> type returned
529     * for ACSII character, <code>ASIAN</code> for Katakana Unicode
530     * codepoints, <code>COMPLEX</code> for Arabic Unicode
531     * codepoints and <code>WEAK</code> for codepoints from Arrows
532     * Unicode block.
533     */
534     public void _getScriptType() {
535         boolean res = true ;
536 
537         res &= oObj.getScriptType("abcd", 0) == ScriptType.LATIN ;
538         res &= oObj.getScriptType(katakana, 0) == ScriptType.ASIAN;
539         res &= oObj.getScriptType(arabic, 0) == ScriptType.COMPLEX ;
540         res &= oObj.getScriptType(arrows, 0) == ScriptType.WEAK ;
541 
542         tRes.tested("getScriptType()", res) ;
543     }
544 
545     boolean bCharBlockRes = true;
546 
547     protected short getCharBlockType(int pos) {
548         short i = 1;
549         short cType = 0;
550         while (i < 31) {
551             if (oObj.beginOfCharBlock(UnicodeString, pos, locale, i) != -1) {
552                 cType = i;
553                 i = 100;
554             }
555             i++;
556         }
557 
558         return cType;
559     }
560 
561     Vector vCharBlockBounds = new Vector();
562     Vector vCharBlockTypes = new Vector();
563 
564     /**
565      * Creates array of all char blocks with their boundaries and
566      * types using <code>beginOfCharBlock()</code> and
567      * <code>endOfCharBlock()</code> methods. <p>
568      *
569      * Has <b>OK</b> status if the end of each boundary is the same
570      * as start of the next one and if the start of the first block
571      * has position 0 and the end of the last block is at the end
572      * of the whole string.
573      */
574     public void _beginOfCharBlock() {
575         int iPos = 0;
576 
577         while( iPos < UnicodeString.length() && iPos > -1) {
578             short charType = getCharBlockType(iPos);
579             int startPos = oObj.beginOfCharBlock(UnicodeString, iPos,
580                 locale, charType);
581             int endPos = oObj.endOfCharBlock(UnicodeString, iPos,
582                 locale, charType);
583             iPos = endPos;
584             vCharBlockBounds.add(new Boundary(startPos, endPos));
585             log.println("" + vCharBlockBounds.size() + "). Bounds: ["
586                 + startPos + "," + endPos + "]; Type = " + charType);
587             vCharBlockTypes.add(new Short(charType));
588         }
589 
590         for(int i = 0; i < vCharBlockBounds.size() - 1; i++) {
591             int endPos = ((Boundary)vCharBlockBounds.get(i)).endPos;
592             int startPos = ((Boundary)vCharBlockBounds.get(i + 1)).startPos;
593             bCharBlockRes &= endPos == startPos;
594         }
595 
596         log.println("Testing for no intersections : " + bCharBlockRes);
597         int startPos = ((Boundary)vCharBlockBounds.get(0)).startPos;
598         bCharBlockRes &= startPos == 0;
599         int endPos = ((Boundary)vCharBlockBounds.get
600             (vCharBlockBounds.size() - 1)).endPos;
601         bCharBlockRes &= endPos == UnicodeString.length();
602         log.println("Regions should starts with 0 and ends with "
603             + UnicodeString.length());
604 
605         tRes.tested("beginOfCharBlock()", bCharBlockRes);
606     }
607 
608     /**
609      * Testing of this method is performed in <code>beginOfCharBlock()</code>
610      * method test. <p>
611      *
612      * Has the status same as <code>beginOfCharBlock()</code> method status.
613      */
614     public void _endOfCharBlock() {
615         requiredMethod("beginOfCharBlock()");
616         tRes.tested("endOfCharBlock()", bCharBlockRes);
617     }
618 
619     /**
620      * For every character block obtained in <code>beginOfCharBlock()</code>
621      * method test (except the first) tries to find its starting position
622      * by mean of <code>nextCharBlock()</code> method passing as position
623      * argument the position before the start of a block. <p>
624      *
625      * Has <b>OK</b> status if the start of every block was found and it's
626      * equal to this block boundary start.
627      */
628     public void _nextCharBlock() {
629         requiredMethod("beginOfCharBlock()");
630 
631         boolean bRes = true;
632         for(int i = 0; i < vCharBlockBounds.size(); i++) {
633             Boundary bounds = (Boundary)vCharBlockBounds.get(i);
634             Short type = (Short)vCharBlockTypes.get(i);
635             if (bounds.startPos - 1 < 0) continue;
636             int iPos = oObj.nextCharBlock(UnicodeString, bounds.startPos - 1,
637                 locale, type.shortValue());
638             if (iPos != bounds.startPos) {
639                 bRes = false;
640                 log.println("nextCharBlock(UnicodeString, "
641                     + (bounds.startPos - 1) + ", locale, " + type
642                     + ") should return " + bounds.startPos);
643                 log.println("... and actual value is " + iPos);
644             }
645         }
646 
647         tRes.tested("nextCharBlock()", bRes);
648     }
649 
650     /**
651      * For every character block obtained in <code>beginOfCharBlock()</code>
652      * method test (except the first) tries to find its starting position
653      * by mean of <code>previousCharBlock()</code> method passing as position
654      * argument the position after the end of a block. <p>
655      *
656      * Has <b>OK</b> status if the start of every block was found and it's
657      * equal to this block boundary start.
658      */
659     public void _previousCharBlock() {
660         requiredMethod("beginOfCharBlock()");
661 
662         boolean bRes = true;
663         for(int i = 0; i < vCharBlockBounds.size(); i++) {
664             Boundary bounds = (Boundary)vCharBlockBounds.get(i);
665             Short type = (Short)vCharBlockTypes.get(i);
666             int iPos = oObj.previousCharBlock(UnicodeString,
667                 bounds.endPos + 1, locale, type.shortValue());
668             if (iPos != bounds.startPos) {
669                 bRes = false;
670                 log.println("previousCharBlock(UnicodeString, "
671                     + (bounds.endPos + 1) + ", locale, " + type
672                     + ") should return " + bounds.startPos);
673                 log.println("... and actual value is " + iPos);
674             }
675         }
676 
677         tRes.tested("previousCharBlock()", bRes);
678     }
679 
680 }
681 
682