1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html#License
3/*
4 *******************************************************************************
5 * Copyright (C) 2009-2015, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 *******************************************************************************
8 */
9
10package com.ibm.icu.dev.test.util;
11
12import java.io.ByteArrayInputStream;
13import java.io.ByteArrayOutputStream;
14import java.io.IOException;
15import java.io.InputStream;
16import java.nio.ByteBuffer;
17import java.util.Iterator;
18
19import org.junit.Test;
20
21import com.ibm.icu.dev.test.TestFmwk;
22import com.ibm.icu.impl.ICUBinary;
23import com.ibm.icu.impl.Trie2;
24import com.ibm.icu.impl.Trie2Writable;
25import com.ibm.icu.impl.Trie2_16;
26import com.ibm.icu.impl.Trie2_32;
27
28public class Trie2Test extends TestFmwk {
29    /**
30     * Constructor
31     */
32     public Trie2Test()
33     {
34     }
35
36     // public methods -----------------------------------------------
37
38     //
39     //  TestAPI.  Check that all API methods can be called, and do at least some minimal
40     //            operation correctly.  This is not a full test of correct behavior.
41     //
42    @Test
43     public void TestTrie2API() {
44         // Trie2.createFromSerialized()
45         //   This function is well exercised by TestRanges().
46
47         // Trie2.getVersion(InputStream is, boolean anyEndianOk)
48         //
49
50         try {
51             Trie2Writable trie = new Trie2Writable(0,0);
52             ByteArrayOutputStream os = new ByteArrayOutputStream();
53             trie.toTrie2_16().serialize(os);
54             ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
55             assertEquals(null, 2, Trie2.getVersion(is, true));
56         } catch (IOException e) {
57             errln(where() + e.toString());
58         }
59
60         // Equals & hashCode
61         //
62         {
63             Trie2Writable trieWA = new Trie2Writable(0,0);
64             Trie2Writable trieWB = new Trie2Writable(0,0);
65             Trie2 trieA = trieWA;
66             Trie2 trieB = trieWB;
67             assertTrue("", trieA.equals(trieB));
68             assertEquals("", trieA, trieB);
69             assertEquals("", trieA.hashCode(), trieB.hashCode());
70             trieWA.set(500, 2);
71             assertNotEquals("", trieA, trieB);
72             // Note that the hash codes do not strictly need to be different,
73             //   but it's highly likely that something is wrong if they are the same.
74             assertNotEquals("", trieA.hashCode(), trieB.hashCode());
75             trieWB.set(500, 2);
76             trieA = trieWA.toTrie2_16();
77             assertEquals("", trieA, trieB);
78             assertEquals("", trieA.hashCode(), trieB.hashCode());
79         }
80
81         //
82         // Iterator creation
83         //
84         {
85             Trie2Writable trie = new Trie2Writable(17,0);
86             Iterator<Trie2.Range>   it;
87             it = trie.iterator();
88
89             Trie2.Range r = it.next();
90             assertEquals("", 0, r.startCodePoint);
91             assertEquals("", 0x10ffff, r.endCodePoint);
92             assertEquals("", 17, r.value);
93             assertEquals("", false, r.leadSurrogate);
94
95             r = it.next();
96             assertEquals("", 0xd800, r.startCodePoint);
97             assertEquals("", 0xdbff, r.endCodePoint);
98             assertEquals("", 17, r.value);
99             assertEquals("", true, r.leadSurrogate);
100
101
102             int i = 0;
103             for (Trie2.Range rr: trie) {
104                 switch (i) {
105                 case 0:
106                     assertEquals("", 0, rr.startCodePoint);
107                     assertEquals("", 0x10ffff, rr.endCodePoint);
108                     assertEquals("", 17, rr.value);
109                     assertEquals("", false, rr.leadSurrogate);
110                     break;
111                 case 1:
112                     assertEquals("", 0xd800, rr.startCodePoint);
113                     assertEquals("", 0xdbff, rr.endCodePoint);
114                     assertEquals("", 17, rr.value);
115                     assertEquals("", true, rr.leadSurrogate);
116                     break;
117                 default:
118                     errln(where() + " Unexpected iteration result");
119                 }
120                 i++;
121             }
122         }
123
124         // Iteration with a value mapping function
125         //
126         {
127             Trie2Writable trie = new Trie2Writable(0xbadfeed, 0);
128             trie.set(0x10123, 42);
129
130             Trie2.ValueMapper vm = new Trie2.ValueMapper() {
131                 public int map(int v) {
132                     if (v == 0xbadfeed) {
133                         v = 42;
134                     }
135                     return v;
136                 }
137             };
138             Iterator<Trie2.Range> it = trie.iterator(vm);
139             Trie2.Range r = it.next();
140             assertEquals("", 0, r.startCodePoint);
141             assertEquals("", 0x10ffff, r.endCodePoint);
142             assertEquals("", 42, r.value);
143             assertEquals("", false, r.leadSurrogate);
144         }
145
146
147         // Iteration over a leading surrogate range.
148         //
149         {
150             Trie2Writable trie = new Trie2Writable(0xdefa17, 0);
151             trie.set(0x2f810, 10);
152             Iterator<Trie2.Range> it = trie.iteratorForLeadSurrogate((char)0xd87e);
153             Trie2.Range r = it.next();
154             assertEquals("", 0x2f800,  r.startCodePoint);
155             assertEquals("", 0x2f80f,  r.endCodePoint);
156             assertEquals("", 0xdefa17, r.value);
157             assertEquals("", false,    r.leadSurrogate);
158
159             r = it.next();
160             assertEquals("", 0x2f810, r.startCodePoint);
161             assertEquals("", 0x2f810, r.endCodePoint);
162             assertEquals("", 10,      r.value);
163             assertEquals("", false,   r.leadSurrogate);
164
165             r = it.next();
166             assertEquals("", 0x2f811,  r.startCodePoint);
167             assertEquals("", 0x2fbff,  r.endCodePoint);
168             assertEquals("", 0xdefa17, r.value);
169             assertEquals("", false,    r.leadSurrogate);
170
171             assertFalse("", it.hasNext());
172         }
173
174         // Iteration over a leading surrogate range with a ValueMapper.
175         //
176         {
177             Trie2Writable trie = new Trie2Writable(0xdefa17, 0);
178             trie.set(0x2f810, 10);
179             Trie2.ValueMapper m = new Trie2.ValueMapper() {
180                 public int map(int in) {
181                     if (in==10) {
182                         in = 0xdefa17;
183                     }
184                     return in;
185                 }
186             };
187             Iterator<Trie2.Range> it = trie.iteratorForLeadSurrogate((char)0xd87e, m);
188             Trie2.Range r = it.next();
189             assertEquals("", 0x2f800,  r.startCodePoint);
190             assertEquals("", 0x2fbff,  r.endCodePoint);
191             assertEquals("", 0xdefa17, r.value);
192             assertEquals("", false,    r.leadSurrogate);
193
194             assertFalse("", it.hasNext());
195         }
196
197         // Trie2.serialize()
198         //     Test the implementation in Trie2, which is used with Read Only Tries.
199         //
200         {
201             Trie2Writable trie = new Trie2Writable(101, 0);
202             trie.setRange(0xf000, 0x3c000, 200, true);
203             trie.set(0xffee, 300);
204             Trie2_16 frozen16 = trie.toTrie2_16();
205             Trie2_32 frozen32 = trie.toTrie2_32();
206             assertEquals("", trie, frozen16);
207             assertEquals("", trie, frozen32);
208             assertEquals("", frozen16, frozen32);
209             ByteArrayOutputStream os = new ByteArrayOutputStream();
210             try {
211                 frozen16.serialize(os);
212                 Trie2 unserialized16 = Trie2.createFromSerialized(ByteBuffer.wrap(os.toByteArray()));
213                 assertEquals("", trie, unserialized16);
214                 assertEquals("", Trie2_16.class, unserialized16.getClass());
215
216                 os.reset();
217                 frozen32.serialize(os);
218                 Trie2 unserialized32 = Trie2.createFromSerialized(ByteBuffer.wrap(os.toByteArray()));
219                 assertEquals("", trie, unserialized32);
220                 assertEquals("", Trie2_32.class, unserialized32.getClass());
221             } catch (IOException e) {
222                 errln(where() + " Unexpected exception:  " + e);
223             }
224
225
226         }
227     }
228
229
230    @Test
231     public void TestTrie2WritableAPI() {
232         //
233         //   Trie2Writable methods.  Check that all functions are present and
234         //      nominally working.  Not an in-depth test.
235         //
236
237         // Trie2Writable constructor
238         Trie2 t1 = new Trie2Writable(6, 666);
239
240         // Constructor from another Trie2
241         Trie2 t2 = new Trie2Writable(t1);
242         assertTrue("", t1.equals(t2));
243
244         // Set / Get
245         Trie2Writable t1w = new Trie2Writable(10, 666);
246         t1w.set(0x4567, 99);
247         assertEquals("", 10, t1w.get(0x4566));
248         assertEquals("", 99, t1w.get(0x4567));
249         assertEquals("", 666, t1w.get(-1));
250         assertEquals("", 666, t1w.get(0x110000));
251
252
253         // SetRange
254         t1w = new Trie2Writable(10, 666);
255         t1w.setRange(13 /*start*/, 6666 /*end*/, 7788 /*value*/, false  /*overwrite */);
256         t1w.setRange(6000, 7000, 9900, true);
257         assertEquals("",   10, t1w.get(12));
258         assertEquals("", 7788, t1w.get(13));
259         assertEquals("", 7788, t1w.get(5999));
260         assertEquals("", 9900, t1w.get(6000));
261         assertEquals("", 9900, t1w.get(7000));
262         assertEquals("",   10, t1w.get(7001));
263         assertEquals("",  666, t1w.get(0x110000));
264
265         // setRange from a Trie2.Range
266         //    (Ranges are more commonly created by iterating over a Trie2,
267         //     but create one by hand here)
268         Trie2.Range r = new Trie2.Range();
269         r.startCodePoint = 50;
270         r.endCodePoint   = 52;
271         r.value          = 0x12345678;
272         r.leadSurrogate  = false;
273         t1w = new Trie2Writable(0, 0xbad);
274         t1w.setRange(r, true);
275         assertEquals(null, 0, t1w.get(49));
276         assertEquals("", 0x12345678, t1w.get(50));
277         assertEquals("", 0x12345678, t1w.get(52));
278         assertEquals("", 0, t1w.get(53));
279
280
281         // setForLeadSurrogateCodeUnit / getFromU16SingleLead
282         t1w = new Trie2Writable(10, 0xbad);
283         assertEquals("", 10, t1w.getFromU16SingleLead((char)0x0d801));
284         t1w.setForLeadSurrogateCodeUnit((char)0xd801, 5000);
285         t1w.set(0xd801, 6000);
286         assertEquals("", 5000, t1w.getFromU16SingleLead((char)0x0d801));
287         assertEquals("", 6000, t1w.get(0x0d801));
288
289         // get().  Is covered by nearly every other test.
290
291
292         // Trie2_16 getAsFrozen_16()
293         t1w = new Trie2Writable(10, 666);
294         t1w.set(42, 5555);
295         t1w.set(0x1ff00, 224);
296         Trie2_16 t1_16 = t1w.toTrie2_16();
297         assertTrue("", t1w.equals(t1_16));
298         // alter the writable Trie2 and then re-freeze.
299         t1w.set(152, 129);
300         t1_16 = t1w.toTrie2_16();
301         assertTrue("", t1w.equals(t1_16));
302         assertEquals("", 129, t1w.get(152));
303
304         // Trie2_32 getAsFrozen_32()
305         //
306         t1w = new Trie2Writable(10, 666);
307         t1w.set(42, 5555);
308         t1w.set(0x1ff00, 224);
309         Trie2_32 t1_32 = t1w.toTrie2_32();
310         assertTrue("", t1w.equals(t1_32));
311         // alter the writable Trie2 and then re-freeze.
312         t1w.set(152, 129);
313         assertNotEquals("", t1_32, t1w);
314         t1_32 = t1w.toTrie2_32();
315         assertTrue("", t1w.equals(t1_32));
316         assertEquals("", 129, t1w.get(152));
317
318
319         // serialize(OutputStream os, ValueWidth width)
320         //
321         ByteArrayOutputStream os = new ByteArrayOutputStream();
322         t1w = new Trie2Writable(0, 0xbad);
323         t1w.set(0x41, 0x100);
324         t1w.set(0xc2, 0x200);
325         t1w.set(0x404, 0x300);
326         t1w.set(0xd903, 0x500);
327         t1w.set(0xdd29, 0x600);
328         t1w.set(0x1055d3, 0x700);
329         t1w.setForLeadSurrogateCodeUnit((char)0xda1a, 0x800);
330         try {
331             // Serialize to 16 bits.
332             int serializedLen = t1w.toTrie2_16().serialize(os);
333             // Fragile test.  Serialized length could change with changes to compaction.
334             //                But it should not change unexpectedly.
335             assertEquals("", 3508, serializedLen);
336             Trie2 t1ws16 = Trie2.createFromSerialized(ByteBuffer.wrap(os.toByteArray()));
337             assertEquals("", t1ws16.getClass(), Trie2_16.class);
338             assertEquals("", t1w, t1ws16);
339
340             // Serialize to 32 bits
341             os.reset();
342             serializedLen = t1w.toTrie2_32().serialize(os);
343             // Fragile test.  Serialized length could change with changes to compaction.
344             //                But it should not change unexpectedly.
345             assertEquals("", 4332, serializedLen);
346             Trie2 t1ws32 = Trie2.createFromSerialized(ByteBuffer.wrap(os.toByteArray()));
347             assertEquals("", t1ws32.getClass(), Trie2_32.class);
348             assertEquals("", t1w, t1ws32);
349         } catch (IOException e) {
350             errln(where() + e.toString());
351         }
352
353
354     }
355
356    @Test
357     public void TestCharSequenceIterator() {
358         String text = "abc123\ud800\udc01 ";    // Includes a Unicode supplemental character
359         String vals = "LLLNNNX?S";
360
361         Trie2Writable  tw = new Trie2Writable(0, 666);
362         tw.setRange('a', 'z', 'L', false);
363         tw.setRange('1', '9', 'N', false);
364         tw.set(' ', 'S');
365         tw.set(0x10001, 'X');
366
367         Trie2.CharSequenceIterator it = tw.charSequenceIterator(text, 0);
368
369         // Check forwards iteration.
370         Trie2.CharSequenceValues ir;
371         int i;
372         for (i=0; it.hasNext(); i++) {
373             ir = it.next();
374             int expectedCP = Character.codePointAt(text, i);
375             assertEquals("" + " i="+i, expectedCP,     ir.codePoint);
376             assertEquals("" + " i="+i, i,              ir.index);
377             assertEquals("" + " i="+i, vals.charAt(i), ir.value);
378             if (expectedCP >= 0x10000) {
379                 i++;
380             }
381         }
382         assertEquals("", text.length(), i);
383
384         // Check reverse iteration, starting at an intermediate point.
385         it.set(5);
386         for (i=5; it.hasPrevious(); ) {
387             ir = it.previous();
388             int expectedCP = Character.codePointBefore(text, i);
389             i -= (expectedCP < 0x10000? 1 : 2);
390             assertEquals("" + " i="+i, expectedCP,     ir.codePoint);
391             assertEquals("" + " i="+i, i,              ir.index);
392             assertEquals("" + " i="+i, vals.charAt(i), ir.value);
393         }
394         assertEquals("", 0, i);
395
396     }
397
398
399     //
400     //  Port of Tests from ICU4C ...
401     //
402     //     setRanges array elements are
403     //        {start Code point, limit CP, value, overwrite}
404     //
405     //     There must be an entry with limit 0 and with the intialValue.
406     //     It may be preceded by an entry with negative limit and the errorValue.
407     //
408     //     checkRanges array elemets are
409     //        { limit code point, value}
410     //
411     //     The expected value range is from the previous boundary's limit to before
412     //        this boundary's limit
413
414     //
415     String[] trieNames = {"setRanges1", "setRanges2", "setRanges3", "setRangesEmpty", "setRangesSingleValue"};
416     /* set consecutive ranges, even with value 0 */
417
418
419
420     private static int[][] setRanges1 ={
421         { 0,        0,        0,      0 },
422         { 0,        0x40,     0,      0 },
423         { 0x40,     0xe7,     0x1234, 0 },
424         { 0xe7,     0x3400,   0,      0 },
425         { 0x3400,   0x9fa6,   0x6162, 0 },
426         { 0x9fa6,   0xda9e,   0x3132, 0 },
427         { 0xdada,   0xeeee,   0x87ff, 0 },
428         { 0xeeee,   0x11111,  1,      0 },
429         { 0x11111,  0x44444,  0x6162, 0 },
430         { 0x44444,  0x60003,  0,      0 },
431         { 0xf0003,  0xf0004,  0xf,    0 },
432         { 0xf0004,  0xf0006,  0x10,   0 },
433         { 0xf0006,  0xf0007,  0x11,   0 },
434         { 0xf0007,  0xf0040,  0x12,   0 },
435         { 0xf0040,  0x110000, 0,      0 }
436     };
437
438     private static int[][]  checkRanges1 = {
439         { 0,        0 },
440         { 0x40,     0 },
441         { 0xe7,     0x1234 },
442         { 0x3400,   0 },
443         { 0x9fa6,   0x6162 },
444         { 0xda9e,   0x3132 },
445         { 0xdada,   0 },
446         { 0xeeee,   0x87ff },
447         { 0x11111,  1 },
448         { 0x44444,  0x6162 },
449         { 0xf0003,  0 },
450         { 0xf0004,  0xf },
451         { 0xf0006,  0x10 },
452         { 0xf0007,  0x11 },
453         { 0xf0040,  0x12 },
454         { 0x110000, 0 }
455     };
456
457     /* set some interesting overlapping ranges */
458     private static  int [][] setRanges2={
459         { 0,        0,        0,      0 },
460         { 0x21,     0x7f,     0x5555, 1 },
461         { 0x2f800,  0x2fedc,  0x7a,   1 },
462         { 0x72,     0xdd,     3,      1 },
463         { 0xdd,     0xde,     4,      0 },
464         { 0x201,    0x240,    6,      1 },  /* 3 consecutive blocks with the same pattern but */
465         { 0x241,    0x280,    6,      1 },  /* discontiguous value ranges, testing utrie2_enum() */
466         { 0x281,    0x2c0,    6,      1 },
467         { 0x2f987,  0x2fa98,  5,      1 },
468         { 0x2f777,  0x2f883,  0,      1 },
469         { 0x2f900,  0x2ffaa,  1,      0 },
470         { 0x2ffaa,  0x2ffab,  2,      1 },
471         { 0x2ffbb,  0x2ffc0,  7,      1 }
472     };
473
474     private static int[] [] checkRanges2={
475         { 0,        0 },
476         { 0x21,     0 },
477         { 0x72,     0x5555 },
478         { 0xdd,     3 },
479         { 0xde,     4 },
480         { 0x201,    0 },
481         { 0x240,    6 },
482         { 0x241,    0 },
483         { 0x280,    6 },
484         { 0x281,    0 },
485         { 0x2c0,    6 },
486         { 0x2f883,  0 },
487         { 0x2f987,  0x7a },
488         { 0x2fa98,  5 },
489         { 0x2fedc,  0x7a },
490         { 0x2ffaa,  1 },
491         { 0x2ffab,  2 },
492         { 0x2ffbb,  0 },
493         { 0x2ffc0,  7 },
494         { 0x110000, 0 }
495     };
496
497/*
498     private static int[] [] checkRanges2_d800={
499         { 0x10000,  0 },
500         { 0x10400,  0 }
501     };
502
503     private static int[][] checkRanges2_d87e={
504         { 0x2f800,  6 },
505         { 0x2f883,  0 },
506         { 0x2f987,  0x7a },
507         { 0x2fa98,  5 },
508         { 0x2fc00,  0x7a }
509     };
510
511     private static int[][] checkRanges2_d87f={
512         { 0x2fc00,  0 },
513         { 0x2fedc,  0x7a },
514         { 0x2ffaa,  1 },
515         { 0x2ffab,  2 },
516         { 0x2ffbb,  0 },
517         { 0x2ffc0,  7 },
518         { 0x30000,  0 }
519     };
520
521     private static int[][]  checkRanges2_dbff={
522         { 0x10fc00, 0 },
523         { 0x110000, 0 }
524     };
525*/
526
527     /* use a non-zero initial value */
528     private static int[][] setRanges3={
529         { 0,        0,        9, 0 },     // non-zero initial value.
530         { 0x31,     0xa4,     1, 0 },
531         { 0x3400,   0x6789,   2, 0 },
532         { 0x8000,   0x89ab,   9, 1 },
533         { 0x9000,   0xa000,   4, 1 },
534         { 0xabcd,   0xbcde,   3, 1 },
535         { 0x55555,  0x110000, 6, 1 },  /* highStart<U+ffff with non-initialValue */
536         { 0xcccc,   0x55555,  6, 1 }
537     };
538
539     private static int[][] checkRanges3={
540         { 0,        9 },  /* non-zero initialValue */
541         { 0x31,     9 },
542         { 0xa4,     1 },
543         { 0x3400,   9 },
544         { 0x6789,   2 },
545         { 0x9000,   9 },
546         { 0xa000,   4 },
547         { 0xabcd,   9 },
548         { 0xbcde,   3 },
549         { 0xcccc,   9 },
550         { 0x110000, 6 }
551     };
552
553     /* empty or single-value tries, testing highStart==0 */
554     private static int[][] setRangesEmpty={
555         { 0,        0,        3, 0 }         // Only the element with the initial value.
556     };
557
558     private static int[][] checkRangesEmpty={
559         { 0,        3 },
560         { 0x110000, 3 }
561     };
562
563     private static int[][] setRangesSingleValue={
564         { 0,        0,        3,  0 },   // Initial value = 3
565         { 0,        0x110000, 5, 1 },
566     };
567
568     private static int[][] checkRangesSingleValue={
569         { 0,        3 },
570         { 0x110000, 5 }
571     };
572
573
574     //
575     // Create a test Trie2 from a setRanges test array.
576     //    Range data ported from C.
577     //
578     private Trie2Writable genTrieFromSetRanges(int [][] ranges) {
579         int i = 0;
580         int initialValue = 0;
581         int errorValue   = 0x0bad;
582
583         if (ranges[i][1] < 0) {
584             errorValue = ranges[i][2];
585             i++;
586         }
587         initialValue = ranges[i++][2];
588         Trie2Writable trie = new Trie2Writable(initialValue, errorValue);
589
590         for (; i<ranges.length; i++) {
591             int     rangeStart = ranges[i][0];
592             int     rangeEnd   = ranges[i][1]-1;
593             int     value      = ranges[i][2];
594             boolean overwrite = (ranges[i][3] != 0);
595             trie.setRange(rangeStart, rangeEnd, value, overwrite);
596         }
597
598         // Insert some non-default values for lead surrogates.
599         //   TODO:  this should be represented in the data.
600         trie.setForLeadSurrogateCodeUnit((char)0xd800, 90);
601         trie.setForLeadSurrogateCodeUnit((char)0xd999, 94);
602         trie.setForLeadSurrogateCodeUnit((char)0xdbff, 99);
603
604         return trie;
605     }
606
607
608     //
609     //  Check the expected values from a single Trie2.
610     //
611     private void trieGettersTest(String           testName,
612                                  Trie2            trie,         // The Trie2 to test.
613                                  int[][]          checkRanges)  // Expected data.
614                                                                 //   Tuples of (value, high limit code point)
615                                                                 //   High limit is first code point following the range
616                                                                 //   with the indicated value.
617                                                                 //      (Structures copied from ICU4C tests.)
618     {
619         int countCheckRanges = checkRanges.length;
620
621         int initialValue, errorValue;
622         int value, value2;
623         int start, limit;
624         int i, countSpecials;
625
626         countSpecials=0;  /*getSpecialValues(checkRanges, countCheckRanges, &initialValue, &errorValue);*/
627         errorValue = 0x0bad;
628         initialValue = 0;
629         if (checkRanges[countSpecials][0] == 0) {
630             initialValue = checkRanges[countSpecials][1];
631             countSpecials++;
632         }
633
634         start=0;
635         for(i=countSpecials; i<countCheckRanges; ++i) {
636             limit=checkRanges[i][0];
637             value=checkRanges[i][1];
638
639             while(start<limit) {
640                 value2=trie.get(start);
641                 if (value != value2) {
642                     // The redundant if, outside of the assert, is for speed.
643                     // It makes a significant difference for this test.
644                     assertEquals("wrong value for " + testName + " of " + Integer.toHexString(start), value, value2);
645                 }
646                 ++start;
647             }
648         }
649
650
651         if(!testName.startsWith("dummy") && !testName.startsWith("trie1")) {
652             /* Test values for lead surrogate code units.
653              * For non-lead-surrogate code units,  getFromU16SingleLead() and get()
654              *   should be the same.
655              */
656             for(start=0xd7ff; start<0xdc01; ++start) {
657                 switch(start) {
658                 case 0xd7ff:
659                 case 0xdc00:
660                     value=trie.get(start);
661                     break;
662                 case 0xd800:
663                     value=90;
664                     break;
665                 case 0xd999:
666                     value=94;
667                     break;
668                 case 0xdbff:
669                     value=99;
670                     break;
671                 default:
672                     value=initialValue;
673                     break;
674                 }
675                 value2 = trie.getFromU16SingleLead((char)start);
676                 if(value2!=value) {
677                     errln(where() + " testName: " + testName + " getFromU16SingleLead() failed." +
678                             "char, exected, actual = " + Integer.toHexString(start) + ", " +
679                             Integer.toHexString(value) + ", " + Integer.toHexString(value2));
680                 }
681             }
682         }
683
684         /* test errorValue */
685         value=trie.get(-1);
686         value2=trie.get(0x110000);
687         if(value!=errorValue || value2!=errorValue) {
688             errln("trie2.get() error value test.  Expected, actual1, actual2 = " +
689                     errorValue + ", " + value + ", " + value2);
690         }
691
692         // Check that Trie enumeration produces the same contents as simple get()
693         for (Trie2.Range range: trie) {
694             for (int cp=range.startCodePoint; cp<=range.endCodePoint; cp++) {
695                 if (range.leadSurrogate) {
696                     assertTrue(testName, cp>=(char)0xd800 && cp<(char)0xdc00);
697                     assertEquals(testName, range.value, trie.getFromU16SingleLead((char)cp));
698                 } else {
699                     assertEquals(testName, range.value, trie.get(cp));
700                 }
701             }
702         }
703     }
704
705     // Was testTrieRanges in ICU4C.  Renamed to not conflict with ICU4J test framework.
706     private void checkTrieRanges(String testName, String serializedName, boolean withClone,
707             int[][] setRanges, int [][] checkRanges) throws IOException {
708
709         // Run tests against Tries that were built by ICU4C and serialized.
710         String fileName16 = "Trie2Test." + serializedName + ".16.tri2";
711         String fileName32 = "Trie2Test." + serializedName + ".32.tri2";
712
713         InputStream is = Trie2Test.class.getResourceAsStream(fileName16);
714         Trie2 trie16;
715         try {
716             trie16 = Trie2.createFromSerialized(ICUBinary.getByteBufferFromInputStreamAndCloseStream(is));
717         } finally {
718             is.close();
719         }
720         trieGettersTest(testName, trie16, checkRanges);
721
722         is = Trie2Test.class.getResourceAsStream(fileName32);
723         Trie2 trie32;
724         try {
725             trie32 = Trie2.createFromSerialized(ICUBinary.getByteBufferFromInputStreamAndCloseStream(is));
726         } finally {
727             is.close();
728         }
729         trieGettersTest(testName, trie32, checkRanges);
730
731         // Run the same tests against locally contructed Tries.
732         Trie2Writable trieW = genTrieFromSetRanges(setRanges);
733         trieGettersTest(testName, trieW,  checkRanges);
734         assertEquals("", trieW, trie16);   // Locally built tries must be
735         assertEquals("", trieW, trie32);   //   the same as those imported from ICU4C
736
737
738         Trie2_32 trie32a = trieW.toTrie2_32();
739         trieGettersTest(testName, trie32a, checkRanges);
740
741         Trie2_16 trie16a = trieW.toTrie2_16();
742         trieGettersTest(testName, trie16a, checkRanges);
743
744     }
745
746     // Was "TrieTest" in trie2test.c
747    @Test
748     public void TestRanges() throws IOException {
749         checkTrieRanges("set1",           "setRanges1",     false, setRanges1,     checkRanges1);
750         checkTrieRanges("set2-overlap",   "setRanges2",     false, setRanges2,     checkRanges2);
751         checkTrieRanges("set3-initial-9", "setRanges3",     false, setRanges3,     checkRanges3);
752         checkTrieRanges("set-empty",      "setRangesEmpty", false, setRangesEmpty, checkRangesEmpty);
753         checkTrieRanges("set-single-value", "setRangesSingleValue", false, setRangesSingleValue,
754             checkRangesSingleValue);
755         checkTrieRanges("set2-overlap.withClone", "setRanges2", true, setRanges2,     checkRanges2);
756     }
757
758
759     private String where() {
760         StackTraceElement[] st = new Throwable().getStackTrace();
761         String w = "File: " + st[1].getFileName() + ", Line " + st[1].getLineNumber();
762         return w;
763     }
764}
765