1/* GENERATED SOURCE. DO NOT MODIFY. */
2// © 2016 and later: Unicode, Inc. and others.
3// License & terms of use: http://www.unicode.org/copyright.html#License
4/*
5*******************************************************************************
6*   Copyright (C) 2001-2012, International Business Machines
7*   Corporation and others.  All Rights Reserved.
8*******************************************************************************
9*/
10
11package android.icu.dev.test.shaping;
12
13import java.lang.reflect.Method;
14import java.util.MissingResourceException;
15
16import org.junit.Test;
17
18import android.icu.dev.test.TestFmwk;
19import android.icu.text.ArabicShaping;
20import android.icu.text.ArabicShapingException;
21
22/**
23 * Regression test for Arabic shaping.
24 */
25public class ArabicShapingRegTest extends TestFmwk {
26
27    /* constants copied from ArabicShaping for convenience */
28
29    public static final int LENGTH_GROW_SHRINK = 0;
30    public static final int LENGTH_FIXED_SPACES_NEAR = 1;
31    public static final int LENGTH_FIXED_SPACES_AT_END = 2;
32    public static final int LENGTH_FIXED_SPACES_AT_BEGINNING = 3;
33
34    public static final int TEXT_DIRECTION_LOGICAL = 0;
35    public static final int TEXT_DIRECTION_VISUAL_LTR = 4;
36
37    public static final int LETTERS_NOOP = 0;
38    public static final int LETTERS_SHAPE = 8;
39    public static final int LETTERS_SHAPE_TASHKEEL_ISOLATED = 0x18;
40    public static final int LETTERS_UNSHAPE = 0x10;
41
42    public static final int DIGITS_NOOP = 0;
43    public static final int DIGITS_EN2AN = 0x20;
44    public static final int DIGITS_AN2EN = 0x40;
45    public static final int DIGITS_EN2AN_INIT_LR = 0x60;
46    public static final int DIGITS_EN2AN_INIT_AL = 0x80;
47//    private static final int DIGITS_RESERVED = 0xa0;
48
49    public static final int DIGIT_TYPE_AN = 0;
50    public static final int DIGIT_TYPE_AN_EXTENDED = 0x100;
51
52    public static class TestData {
53        public int type;
54        public String source;
55        public int flags;
56        public String result;
57        public int length;
58        public Class error;
59
60        public static final int STANDARD = 0;
61        public static final int PREFLIGHT = 1;
62        public static final int ERROR = 2;
63
64        public static TestData standard(String source, int flags, String result) {
65            return new TestData(STANDARD, source, flags, result, 0, null);
66        }
67
68        public static TestData preflight(String source, int flags, int length) {
69            return new TestData(PREFLIGHT, source, flags, null, length, null);
70        }
71
72        public static TestData error(String source, int flags, Class error) {
73            return new TestData(ERROR, source, flags, null, 0, error);
74        }
75
76        private TestData(int type, String source, int flags, String result, int length, Class error) {
77            this.type = type;
78            this.source = source;
79            this.flags = flags;
80            this.result = result;
81            this.length = length;
82            this.error = error;
83        }
84
85        private static final String[] typenames = { "standard", "preflight", "error" };
86
87        public String toString() {
88            StringBuffer buf = new StringBuffer(super.toString());
89            buf.append("[\n");
90            buf.append(typenames[type]);
91            buf.append(",\n");
92            if (source == null) {
93                buf.append("null");
94            } else {
95                buf.append('"');
96                buf.append(escapedString(source));
97                buf.append('"');
98            }
99            buf.append(",\n");
100            buf.append(Integer.toHexString(flags));
101            buf.append(",\n");
102            if (result == null) {
103                buf.append("null");
104            } else {
105                buf.append('"');
106                buf.append(escapedString(result));
107                buf.append('"');
108            }
109            buf.append(",\n");
110            buf.append(length);
111            buf.append(",\n");
112            buf.append(error);
113            buf.append(']');
114            return buf.toString();
115        }
116    }
117
118    private static final String lamAlefSpecialVLTR =
119        "\u0020\u0646\u0622\u0644\u0627\u0020" +
120         "\u0646\u0623\u064E\u0644\u0627\u0020" +
121         "\u0646\u0627\u0670\u0644\u0627\u0020" +
122         "\u0646\u0622\u0653\u0644\u0627\u0020" +
123         "\u0646\u0625\u0655\u0644\u0627\u0020" +
124         "\u0646\u0622\u0654\u0644\u0627\u0020" +
125         "\uFEFC\u0639";
126
127    private static final String tashkeelSpecialVLTR =
128        "\u064A\u0628\u0631\u0639\u0020" +
129        "\u064A\u0628\u0651\u0631\u064E\u0639\u0020" +
130        "\u064C\u064A\u0628\u0631\u064F\u0639\u0020" +
131        "\u0628\u0670\u0631\u0670\u0639\u0020" +
132        "\u0628\u0653\u0631\u0653\u0639\u0020" +
133        "\u0628\u0654\u0631\u0654\u0639\u0020" +
134        "\u0628\u0655\u0631\u0655\u0639\u0020";
135
136    private static final String tashkeelShaddaRTL=
137            "\u0634\u0651\u0645\u0652\u0633";
138    private static final String tashkeelShaddaLTR=
139            "\u0633\u0652\u0645\u0651\u0634";
140
141    private static final String ArMathSym =
142        "\uD83B\uDE00\uD83B\uDE01\uD83B\uDE02\uD83B\uDE03\u0020" +
143        "\uD83B\uDE24\uD83B\uDE05\uD83B\uDE06\u0020" +
144        "\uD83B\uDE07\uD83B\uDE08\uD83B\uDE09\u0020" +
145        "\uD83B\uDE0A\uD83B\uDE0B\uD83B\uDE0C\uD83B\uDE0D\u0020" +
146        "\uD83B\uDE0E\uD83B\uDE0F\uD83B\uDE10\uD83B\uDE11\u0020" +
147        "\uD83B\uDE12\uD83B\uDE13\uD83B\uDE14\uD83B\uDE15\u0020" +
148        "\uD83B\uDE16\uD83B\uDE17\uD83B\uDE18\u0020" +
149        "\uD83B\uDE19\uD83B\uDE1A\uD83B\uDE1B";
150
151    private static final String ArMathSymLooped =
152        "\uD83B\uDE80\uD83B\uDE81\uD83B\uDE82\uD83B\uDE83\u0020" +
153        "\uD83B\uDE84\uD83B\uDE85\uD83B\uDE86\u0020" +
154        "\uD83B\uDE87\uD83B\uDE88\uD83B\uDE89\u0020" +
155        "\uD83B\uDE8B\uD83B\uDE8C\uD83B\uDE8D\u0020" +
156        "\uD83B\uDE8E\uD83B\uDE8F\uD83B\uDE90\uD83B\uDE91\u0020" +
157        "\uD83B\uDE92\uD83B\uDE93\uD83B\uDE94\uD83B\uDE95\u0020" +
158        "\uD83B\uDE96\uD83B\uDE97\uD83B\uDE98\u0020" +
159        "\uD83B\uDE99\uD83B\uDE9A\uD83B\uDE9B";
160
161    private static final String ArMathSymDoubleStruck =
162        "\uD83B\uDEA1\uD83B\uDEA2\uD83B\uDEA3\u0020" +
163        "\uD83B\uDEA5\uD83B\uDEA6\u0020" +
164        "\uD83B\uDEA7\uD83B\uDEA8\uD83B\uDEA9\u0020" +
165        "\uD83B\uDEAB\uD83B\uDEAC\uD83B\uDEAD\u0020" +
166        "\uD83B\uDEAE\uD83B\uDEAF\uD83B\uDEB0\uD83B\uDEB1\u0020" +
167        "\uD83B\uDEB2\uD83B\uDEB3\uD83B\uDEB4\uD83B\uDEB5\u0020" +
168        "\uD83B\uDEB6\uD83B\uDEB7\uD83B\uDEB8\u0020" +
169        "\uD83B\uDEB9\uD83B\uDEBA\uD83B\uDEBB";
170
171    private static final String ArMathSymInitial =
172        "\uD83B\uDE21\uD83B\uDE22\u0020" +
173        "\uD83B\uDE27\uD83B\uDE29\u0020" +
174        "\uD83B\uDE2A\uD83B\uDE2B\uD83B\uDE2C\uD83B\uDE2D\u0020" +
175        "\uD83B\uDE2E\uD83B\uDE2F\uD83B\uDE30\uD83B\uDE31\u0020" +
176        "\uD83B\uDE32\uD83B\uDE34\uD83B\uDE35\u0020" +
177        "\uD83B\uDE36\uD83B\uDE37\u0020" +
178        "\uD83B\uDE39\uD83B\uDE3B";
179
180    private static final String ArMathSymTailed =
181        "\uD83B\uDE42\uD83B\uDE47\uD83B\uDE49\uD83B\uDE4B\u0020" +
182        "\uD83B\uDE4D\uD83B\uDE4E\uD83B\uDE4F\u0020" +
183        "\uD83B\uDE51\uD83B\uDE52\uD83B\uDE54\uD83B\uDE57\u0020" +
184        "\uD83B\uDE59\uD83B\uDE5B\uD83B\uDE5D\uD83B\uDE5F";
185
186    private static final String ArMathSymStretched =
187        "\uD83B\uDE21\u0633\uD83B\uDE62\u0647";
188
189    private static final String logicalUnshape =
190        "\u0020\u0020\u0020\uFE8D\uFEF5\u0020\uFEE5\u0020\uFE8D\uFEF7\u0020" +
191        "\uFED7\uFEFC\u0020\uFEE1\u0020\uFE8D\uFEDF\uFECC\uFEAE\uFE91\uFEF4" +
192        "\uFE94\u0020\uFE8D\uFEDF\uFEA4\uFEAE\uFE93\u0020\u0020\u0020\u0020";
193
194    private static final String numSource =
195        "\u0031" +  /* en:1 */
196        "\u0627" +  /* arabic:alef */
197        "\u0032" +  /* en:2 */
198        "\u06f3" +  /* an:3 */
199        "\u0061" +  /* latin:a */
200        "\u0034";   /* en:4 */
201
202    private static final TestData[] standardTests = {
203        /* lam alef special visual ltr */
204        TestData.standard(lamAlefSpecialVLTR,
205                          LETTERS_SHAPE | TEXT_DIRECTION_VISUAL_LTR | LENGTH_FIXED_SPACES_NEAR,
206                          "\u0020\ufee5\u0020\ufef5\ufe8d\u0020" +
207                          "\ufee5\u0020\ufe76\ufef7\ufe8d\u0020" +
208                          "\ufee5\u0020\u0670\ufefb\ufe8d\u0020" +
209                          "\ufee5\u0020\u0653\ufef5\ufe8d\u0020" +
210                          "\ufee5\u0020\u0655\ufef9\ufe8d\u0020" +
211                          "\ufee5\u0020\u0654\ufef5\ufe8d\u0020" +
212                          "\ufefc\ufecb"),
213        TestData.standard(lamAlefSpecialVLTR,
214                          LETTERS_SHAPE | TEXT_DIRECTION_VISUAL_LTR | LENGTH_FIXED_SPACES_AT_END,
215                          "\u0020\ufee5\ufef5\ufe8d\u0020\ufee5" +
216                          "\ufe76\ufef7\ufe8d\u0020\ufee5\u0670" +
217                          "\ufefb\ufe8d\u0020\ufee5\u0653\ufef5" +
218                          "\ufe8d\u0020\ufee5\u0655\ufef9\ufe8d" +
219                          "\u0020\ufee5\u0654\ufef5\ufe8d\u0020" +
220                          "\ufefc\ufecb\u0020\u0020\u0020\u0020" +
221                          "\u0020\u0020"),
222        TestData.standard(lamAlefSpecialVLTR,
223                          LETTERS_SHAPE | TEXT_DIRECTION_VISUAL_LTR | LENGTH_FIXED_SPACES_AT_BEGINNING,
224                          "\u0020\u0020\u0020\u0020\u0020\u0020" +
225                          "\u0020\ufee5\ufef5\ufe8d\u0020\ufee5" +
226                          "\ufe76\ufef7\ufe8d\u0020\ufee5\u0670" +
227                          "\ufefb\ufe8d\u0020\ufee5\u0653\ufef5" +
228                          "\ufe8d\u0020\ufee5\u0655\ufef9\ufe8d" +
229                          "\u0020\ufee5\u0654\ufef5\ufe8d\u0020" +
230                          "\ufefc\ufecb"),
231        TestData.standard(lamAlefSpecialVLTR,
232                          LETTERS_SHAPE | TEXT_DIRECTION_VISUAL_LTR | LENGTH_GROW_SHRINK,
233                          "\u0020\ufee5\ufef5\ufe8d\u0020\ufee5" +
234                          "\ufe76\ufef7\ufe8d\u0020\ufee5\u0670" +
235                          "\ufefb\ufe8d\u0020\ufee5\u0653\ufef5" +
236                          "\ufe8d\u0020\ufee5\u0655\ufef9\ufe8d" +
237                          "\u0020\ufee5\u0654\ufef5\ufe8d\u0020" +
238                          "\ufefc\ufecb"),
239
240        /* TASHKEEL */
241        TestData.standard(lamAlefSpecialVLTR,
242                          LETTERS_SHAPE_TASHKEEL_ISOLATED | TEXT_DIRECTION_VISUAL_LTR | LENGTH_FIXED_SPACES_NEAR,
243                          "\u0020\ufee5\u0020\ufef5\ufe8d\u0020" +
244                          "\ufee5\u0020\ufe76\ufef7\ufe8d\u0020" +
245                          "\ufee5\u0020\u0670\ufefb\ufe8d\u0020" +
246                          "\ufee5\u0020\u0653\ufef5\ufe8d\u0020" +
247                          "\ufee5\u0020\u0655\ufef9\ufe8d\u0020" +
248                          "\ufee5\u0020\u0654\ufef5\ufe8d\u0020" +
249                          "\ufefc\ufecb"),
250        TestData.standard(lamAlefSpecialVLTR,
251                          LETTERS_SHAPE_TASHKEEL_ISOLATED | TEXT_DIRECTION_VISUAL_LTR | LENGTH_FIXED_SPACES_AT_END,
252                          "\u0020\ufee5\ufef5\ufe8d\u0020\ufee5" +
253                          "\ufe76\ufef7\ufe8d\u0020\ufee5\u0670" +
254                          "\ufefb\ufe8d\u0020\ufee5\u0653\ufef5" +
255                          "\ufe8d\u0020\ufee5\u0655\ufef9\ufe8d" +
256                          "\u0020\ufee5\u0654\ufef5\ufe8d\u0020" +
257                          "\ufefc\ufecb\u0020\u0020\u0020\u0020" +
258                          "\u0020\u0020"),
259        TestData.standard(lamAlefSpecialVLTR,
260                          LETTERS_SHAPE_TASHKEEL_ISOLATED | TEXT_DIRECTION_VISUAL_LTR | LENGTH_FIXED_SPACES_AT_BEGINNING,
261                          "\u0020\u0020\u0020\u0020\u0020\u0020" +
262                          "\u0020\ufee5\ufef5\ufe8d\u0020\ufee5" +
263                          "\ufe76\ufef7\ufe8d\u0020\ufee5\u0670" +
264                          "\ufefb\ufe8d\u0020\ufee5\u0653\ufef5" +
265                          "\ufe8d\u0020\ufee5\u0655\ufef9\ufe8d" +
266                          "\u0020\ufee5\u0654\ufef5\ufe8d\u0020" +
267                          "\ufefc\ufecb"),
268        TestData.standard(lamAlefSpecialVLTR,
269                          LETTERS_SHAPE_TASHKEEL_ISOLATED | TEXT_DIRECTION_VISUAL_LTR | LENGTH_GROW_SHRINK,
270                          "\u0020\ufee5\ufef5\ufe8d\u0020\ufee5" +
271                          "\ufe76\ufef7\ufe8d\u0020\ufee5\u0670" +
272                          "\ufefb\ufe8d\u0020\ufee5\u0653\ufef5" +
273                          "\ufe8d\u0020\ufee5\u0655\ufef9\ufe8d" +
274                          "\u0020\ufee5\u0654\ufef5\ufe8d\u0020" +
275                          "\ufefc\ufecb"),
276
277        /* tashkeel special visual ltr */
278        TestData.standard(tashkeelSpecialVLTR,
279                          LETTERS_SHAPE | TEXT_DIRECTION_VISUAL_LTR | LENGTH_FIXED_SPACES_NEAR,
280                          "\ufef2\ufe91\ufeae\ufecb\u0020" +
281                          "\ufef2\ufe91\ufe7c\ufeae\ufe77\ufecb\u0020" +
282                          "\ufe72\ufef2\ufe91\ufeae\ufe79\ufecb\u0020" +
283                          "\ufe8f\u0670\ufeae\u0670\ufecb\u0020" +
284                          "\ufe8f\u0653\ufeae\u0653\ufecb\u0020" +
285                          "\ufe8f\u0654\ufeae\u0654\ufecb\u0020" +
286                          "\ufe8f\u0655\ufeae\u0655\ufecb\u0020"),
287
288        TestData.standard(tashkeelSpecialVLTR,
289                          LETTERS_SHAPE_TASHKEEL_ISOLATED | TEXT_DIRECTION_VISUAL_LTR | LENGTH_FIXED_SPACES_NEAR,
290                          "\ufef2\ufe91\ufeae\ufecb\u0020" +
291                          "\ufef2\ufe91\ufe7c\ufeae\ufe76\ufecb\u0020" +
292                          "\ufe72\ufef2\ufe91\ufeae\ufe78\ufecb\u0020" +
293                          "\ufe8f\u0670\ufeae\u0670\ufecb\u0020" +
294                          "\ufe8f\u0653\ufeae\u0653\ufecb\u0020" +
295                          "\ufe8f\u0654\ufeae\u0654\ufecb\u0020" +
296                          "\ufe8f\u0655\ufeae\u0655\ufecb\u0020"),
297
298        TestData.standard(tashkeelShaddaRTL,
299                          ArabicShaping.LETTERS_SHAPE|ArabicShaping.TASHKEEL_BEGIN |ArabicShaping.TEXT_DIRECTION_VISUAL_RTL ,
300                          "\u0020\ufeb7\ufe7d\ufee4\ufeb2"),
301        TestData.standard(tashkeelShaddaRTL,
302                          ArabicShaping.LETTERS_SHAPE|ArabicShaping.TASHKEEL_END|ArabicShaping.TEXT_DIRECTION_VISUAL_RTL ,
303                          "\ufeb7\ufe7d\ufee4\ufeb2\u0020"),
304        TestData.standard(tashkeelShaddaRTL,
305                          ArabicShaping.LETTERS_SHAPE|ArabicShaping.TASHKEEL_RESIZE|ArabicShaping.TEXT_DIRECTION_VISUAL_RTL ,
306                          "\ufeb7\ufe7d\ufee4\ufeb2"),
307        TestData.standard(tashkeelShaddaRTL,
308                          ArabicShaping.LETTERS_SHAPE|ArabicShaping.TASHKEEL_REPLACE_BY_TATWEEL|ArabicShaping.TEXT_DIRECTION_VISUAL_RTL ,
309                          "\ufeb7\ufe7d\ufee4\u0640\ufeb2"),
310
311        TestData.standard(tashkeelShaddaLTR,
312                          ArabicShaping.LETTERS_SHAPE|ArabicShaping.TASHKEEL_BEGIN |ArabicShaping.TEXT_DIRECTION_VISUAL_LTR ,
313                          "\u0020\ufeb2\ufee4\ufe7d\ufeb7"),
314        TestData.standard(tashkeelShaddaLTR,
315                          ArabicShaping.LETTERS_SHAPE|ArabicShaping.TASHKEEL_END |ArabicShaping.TEXT_DIRECTION_VISUAL_LTR ,
316                          "\ufeb2\ufee4\ufe7d\ufeb7\u0020"),
317        TestData.standard(tashkeelShaddaLTR,
318                          ArabicShaping.LETTERS_SHAPE|ArabicShaping.TASHKEEL_RESIZE |ArabicShaping.TEXT_DIRECTION_VISUAL_LTR ,
319                          "\ufeb2\ufee4\ufe7d\ufeb7"),
320        TestData.standard(tashkeelShaddaLTR,
321                          ArabicShaping.LETTERS_SHAPE|ArabicShaping.TASHKEEL_REPLACE_BY_TATWEEL |ArabicShaping.TEXT_DIRECTION_VISUAL_LTR ,
322                          "\ufeb2\u0640\ufee4\ufe7d\ufeb7"),
323
324        TestData.standard(ArMathSym,
325                          ArabicShaping.LETTERS_SHAPE|ArabicShaping.TASHKEEL_BEGIN |ArabicShaping.TEXT_DIRECTION_VISUAL_RTL ,
326                          "\uD83B\uDE00\uD83B\uDE01\uD83B\uDE02\uD83B\uDE03\u0020" +
327                          "\uD83B\uDE24\uD83B\uDE05\uD83B\uDE06\u0020" +
328                          "\uD83B\uDE07\uD83B\uDE08\uD83B\uDE09\u0020" +
329                          "\uD83B\uDE0A\uD83B\uDE0B\uD83B\uDE0C\uD83B\uDE0D\u0020" +
330                          "\uD83B\uDE0E\uD83B\uDE0F\uD83B\uDE10\uD83B\uDE11\u0020" +
331                          "\uD83B\uDE12\uD83B\uDE13\uD83B\uDE14\uD83B\uDE15\u0020" +
332                          "\uD83B\uDE16\uD83B\uDE17\uD83B\uDE18\u0020" +
333                          "\uD83B\uDE19\uD83B\uDE1A\uD83B\uDE1B"),
334        TestData.standard(ArMathSymLooped,
335                          ArabicShaping.LETTERS_SHAPE|ArabicShaping.TASHKEEL_END|ArabicShaping.TEXT_DIRECTION_VISUAL_RTL ,
336                          "\uD83B\uDE80\uD83B\uDE81\uD83B\uDE82\uD83B\uDE83\u0020" +
337                          "\uD83B\uDE84\uD83B\uDE85\uD83B\uDE86\u0020" +
338                          "\uD83B\uDE87\uD83B\uDE88\uD83B\uDE89\u0020" +
339                          "\uD83B\uDE8B\uD83B\uDE8C\uD83B\uDE8D\u0020" +
340                          "\uD83B\uDE8E\uD83B\uDE8F\uD83B\uDE90\uD83B\uDE91\u0020" +
341                          "\uD83B\uDE92\uD83B\uDE93\uD83B\uDE94\uD83B\uDE95\u0020" +
342                          "\uD83B\uDE96\uD83B\uDE97\uD83B\uDE98\u0020" +
343                          "\uD83B\uDE99\uD83B\uDE9A\uD83B\uDE9B"),
344        TestData.standard(ArMathSymDoubleStruck,
345                          ArabicShaping.LETTERS_SHAPE|ArabicShaping.TASHKEEL_RESIZE|ArabicShaping.TEXT_DIRECTION_VISUAL_RTL ,
346                          "\uD83B\uDEA1\uD83B\uDEA2\uD83B\uDEA3\u0020" +
347                          "\uD83B\uDEA5\uD83B\uDEA6\u0020" +
348                          "\uD83B\uDEA7\uD83B\uDEA8\uD83B\uDEA9\u0020" +
349                          "\uD83B\uDEAB\uD83B\uDEAC\uD83B\uDEAD\u0020" +
350                          "\uD83B\uDEAE\uD83B\uDEAF\uD83B\uDEB0\uD83B\uDEB1\u0020" +
351                          "\uD83B\uDEB2\uD83B\uDEB3\uD83B\uDEB4\uD83B\uDEB5\u0020" +
352                          "\uD83B\uDEB6\uD83B\uDEB7\uD83B\uDEB8\u0020" +
353                          "\uD83B\uDEB9\uD83B\uDEBA\uD83B\uDEBB"),
354
355        TestData.standard(ArMathSymInitial,
356                          ArabicShaping.LETTERS_SHAPE|ArabicShaping.TASHKEEL_BEGIN |ArabicShaping.TEXT_DIRECTION_VISUAL_LTR ,
357                          "\uD83B\uDE21\uD83B\uDE22\u0020" +
358                          "\uD83B\uDE27\uD83B\uDE29\u0020" +
359                          "\uD83B\uDE2A\uD83B\uDE2B\uD83B\uDE2C\uD83B\uDE2D\u0020" +
360                          "\uD83B\uDE2E\uD83B\uDE2F\uD83B\uDE30\uD83B\uDE31\u0020" +
361                          "\uD83B\uDE32\uD83B\uDE34\uD83B\uDE35\u0020" +
362                          "\uD83B\uDE36\uD83B\uDE37\u0020" +
363                          "\uD83B\uDE39\uD83B\uDE3B"),
364        TestData.standard(ArMathSymTailed,
365                          ArabicShaping.LETTERS_SHAPE|ArabicShaping.TASHKEEL_END |ArabicShaping.TEXT_DIRECTION_VISUAL_LTR ,
366                          "\uD83B\uDE42\uD83B\uDE47\uD83B\uDE49\uD83B\uDE4B\u0020" +
367                          "\uD83B\uDE4D\uD83B\uDE4E\uD83B\uDE4F\u0020" +
368                          "\uD83B\uDE51\uD83B\uDE52\uD83B\uDE54\uD83B\uDE57\u0020" +
369                          "\uD83B\uDE59\uD83B\uDE5B\uD83B\uDE5D\uD83B\uDE5F"),
370        TestData.standard(ArMathSymStretched,
371                          ArabicShaping.LETTERS_SHAPE|ArabicShaping.TASHKEEL_RESIZE |ArabicShaping.TEXT_DIRECTION_VISUAL_LTR ,
372                          "\uD83B\uDE21\uFEB1\uD83B\uDE62\uFEE9"),
373
374        /* logical unshape */
375        TestData.standard(logicalUnshape,
376                          LETTERS_UNSHAPE | TEXT_DIRECTION_LOGICAL | LENGTH_FIXED_SPACES_NEAR,
377                          "\u0020\u0020\u0020\u0627\u0644\u0622\u0646\u0020\u0627\u0644\u0623\u0642\u0644\u0627" +
378                          "\u0645\u0020\u0627\u0644\u0639\u0631\u0628\u064a\u0629\u0020\u0627\u0644\u062d\u0631" +
379                          "\u0629\u0020\u0020\u0020\u0020"),
380        TestData.standard(logicalUnshape,
381                          LETTERS_UNSHAPE | TEXT_DIRECTION_LOGICAL | LENGTH_FIXED_SPACES_AT_END,
382                          "\u0020\u0020\u0020\u0627\u0644\u0622\u0020\u0646\u0020\u0627\u0644\u0623\u0020\u0642" +
383                          "\u0644\u0627\u0020\u0645\u0020\u0627\u0644\u0639\u0631\u0628\u064a\u0629\u0020\u0627" +
384                          "\u0644\u062d\u0631\u0629\u0020"),
385        TestData.standard(logicalUnshape,
386                          LETTERS_UNSHAPE | TEXT_DIRECTION_LOGICAL | LENGTH_FIXED_SPACES_AT_BEGINNING,
387                          "\u0627\u0644\u0622\u0020\u0646\u0020\u0627\u0644\u0623\u0020\u0642\u0644\u0627\u0020" +
388                          "\u0645\u0020\u0627\u0644\u0639\u0631\u0628\u064a\u0629\u0020\u0627\u0644\u062d\u0631" +
389                          "\u0629\u0020\u0020\u0020\u0020"),
390        TestData.standard(logicalUnshape,
391                          LETTERS_UNSHAPE | TEXT_DIRECTION_LOGICAL | LENGTH_GROW_SHRINK,
392                          "\u0020\u0020\u0020\u0627\u0644\u0622\u0020\u0646\u0020\u0627\u0644\u0623\u0020\u0642" +
393                          "\u0644\u0627\u0020\u0645\u0020\u0627\u0644\u0639\u0631\u0628\u064a\u0629\u0020\u0627" +
394                          "\u0644\u062d\u0631\u0629\u0020\u0020\u0020\u0020"),
395
396        /* numbers */
397        TestData.standard(numSource,
398                          DIGITS_EN2AN | DIGIT_TYPE_AN,
399                          "\u0661\u0627\u0662\u06f3\u0061\u0664"),
400        TestData.standard(numSource,
401                          DIGITS_AN2EN | DIGIT_TYPE_AN_EXTENDED,
402                          "\u0031\u0627\u0032\u0033\u0061\u0034"),
403        TestData.standard(numSource,
404                          DIGITS_EN2AN_INIT_LR | DIGIT_TYPE_AN,
405                          "\u0031\u0627\u0662\u06f3\u0061\u0034"),
406        TestData.standard(numSource,
407                          DIGITS_EN2AN_INIT_AL | DIGIT_TYPE_AN_EXTENDED,
408                          "\u06f1\u0627\u06f2\u06f3\u0061\u0034"),
409        TestData.standard(numSource,
410                          DIGITS_EN2AN_INIT_LR | DIGIT_TYPE_AN | TEXT_DIRECTION_VISUAL_LTR,
411                          "\u0661\u0627\u0032\u06f3\u0061\u0034"),
412        TestData.standard(numSource,
413                          DIGITS_EN2AN_INIT_AL | DIGIT_TYPE_AN_EXTENDED | TEXT_DIRECTION_VISUAL_LTR,
414                          "\u06f1\u0627\u0032\u06f3\u0061\u06f4"),
415
416        /* no-op */
417        TestData.standard(numSource,
418                          0,
419                          numSource),
420    };
421
422    private static final TestData[] preflightTests = {
423        /* preflight */
424        TestData.preflight("\u0644\u0627",
425                           LETTERS_SHAPE | LENGTH_GROW_SHRINK,
426                           1),
427
428        TestData.preflight("\u0644\u0627\u0031",
429                           DIGITS_EN2AN | DIGIT_TYPE_AN_EXTENDED | LENGTH_GROW_SHRINK,
430                           3),
431
432        TestData.preflight("\u0644\u0644",
433                           LETTERS_SHAPE | LENGTH_GROW_SHRINK,
434                           2),
435
436        TestData.preflight("\ufef7",
437                           LETTERS_UNSHAPE | LENGTH_GROW_SHRINK,
438                           2),
439    };
440
441    private static final TestData[] errorTests = {
442        /* bad data */
443        TestData.error("\u0020\ufef7\u0644\u0020",
444                       LETTERS_UNSHAPE | LENGTH_FIXED_SPACES_NEAR,
445                       ArabicShapingException.class),
446
447        TestData.error("\u0020\ufef7",
448                       LETTERS_UNSHAPE | LENGTH_FIXED_SPACES_AT_END,
449                       ArabicShapingException.class),
450
451        TestData.error("\ufef7\u0020",
452                       LETTERS_UNSHAPE | LENGTH_FIXED_SPACES_AT_BEGINNING,
453                       ArabicShapingException.class),
454
455        /* bad options */
456        TestData.error("\ufef7",
457                       0xffffffff,
458                       IllegalArgumentException.class),
459
460        TestData.error("\ufef7",
461                       LETTERS_UNSHAPE | LENGTH_GROW_SHRINK,
462                       ArabicShapingException.class),
463
464        TestData.error(null,
465                       LETTERS_UNSHAPE | LENGTH_FIXED_SPACES_AT_END,
466                       IllegalArgumentException.class),
467    };
468
469    @Test
470    public void TestStandard() {
471        for (int i = 0; i < standardTests.length; ++i) {
472            TestData test = standardTests[i];
473
474            Exception ex = null;
475            String result = null;
476            ArabicShaping shaper = null;
477
478            try {
479                shaper = new ArabicShaping(test.flags);
480                result = shaper.shape(test.source);
481            }
482            catch(MissingResourceException e){
483                throw e;
484            }
485            catch (IllegalStateException ie){
486                warnln("IllegalStateException: "+ie.toString());
487                return;
488            }
489            catch (Exception e) {
490                ex = e;
491            }
492
493            if (!test.result.equals(result)) {
494                reportTestFailure(i, test, shaper, result, ex);
495            }
496        }
497    }
498
499    @Test
500    public void TestPreflight() {
501        for (int i = 0; i < preflightTests.length; ++i) {
502            TestData test = preflightTests[i];
503
504            Exception ex = null;
505            char src[] = null;
506            int len = 0;
507            ArabicShaping shaper = null;
508
509            if (test.source != null) {
510                src = test.source.toCharArray();
511            }
512
513            try {
514                shaper = new ArabicShaping(test.flags);
515                len = shaper.shape(src, 0, src.length, null, 0, 0);
516            }
517            catch (Exception e) {
518                ex = e;
519            }
520
521            if (test.length != len) {
522                reportTestFailure(i, test, shaper, test.source, ex);
523            }
524        }
525    }
526
527    @Test
528    public void TestError() {
529        for (int i = 0; i < errorTests.length; ++i) {
530            TestData test = errorTests[i];
531
532            Exception ex = null;
533            char src[] = null;
534            int len = 0;
535            ArabicShaping shaper = null;
536
537            if (test.source != null) {
538                src = test.source.toCharArray();
539                len = src.length;
540            }
541
542            try {
543                shaper = new ArabicShaping(test.flags);
544                shaper.shape(src, 0, len);
545            }
546            catch (Exception e) {
547                ex = e;
548            }
549
550            if (!test.error.isInstance(ex)) {
551                reportTestFailure(i, test, shaper, test.source, ex);
552            }
553        }
554    }
555
556    @Test
557    public void TestEquals()
558    {
559        ArabicShaping as1 = new ArabicShaping(LETTERS_SHAPE | TEXT_DIRECTION_VISUAL_LTR | LENGTH_FIXED_SPACES_NEAR);
560        ArabicShaping as2 = new ArabicShaping(LETTERS_SHAPE | TEXT_DIRECTION_VISUAL_LTR | LENGTH_FIXED_SPACES_NEAR);
561        ArabicShaping as3 = new ArabicShaping(LETTERS_UNSHAPE | TEXT_DIRECTION_LOGICAL | LENGTH_FIXED_SPACES_AT_BEGINNING);
562
563        if (! as1.equals(as1)) {
564            err("as1: " + as1 + " does not equal itself!\n");
565        }
566
567        if (! as1.equals(as2)) {
568            err("as1: " + as1 + ", as2: " + as2 + " are not equal, but should be.\n");
569        }
570
571        if (as1.equals(as3)) {
572            err("as1: " + as1 + ", as3: " + as3 + " are equal but should not be.\n");
573        }
574    }
575
576    // TODO(junit): remove this and convert callers to parameterized tests
577    private void reportTestFailure(int index, TestData test, ArabicShaping shaper, String result, Exception error) {
578        if (error != null && error instanceof MissingResourceException ) {
579            warnln(error.getMessage());
580        }
581
582        StringBuffer buf = new StringBuffer();
583        buf.append("*** test failure ***\n");
584        buf.append("index: " + index + "\n");
585        buf.append("test: " + test + "\n");
586        buf.append("shaper: " + shaper + "\n");
587        buf.append("result: " + escapedString(result) + "\n");
588        buf.append("error: " + error + "\n");
589
590        if (result != null && test.result != null && !test.result.equals(result)) {
591            for (int i = 0; i < Math.max(test.result.length(), result.length()); ++i) {
592                String temp = Integer.toString(i);
593                if (temp.length() < 2) {
594                    temp = " ".concat(temp);
595                }
596                char trg = i < test.result.length() ? test.result.charAt(i) : '\uffff';
597                char res = i < result.length() ? result.charAt(i) : '\uffff';
598
599                buf.append("[" + temp + "] ");
600                buf.append(escapedString("" + trg) + " ");
601                buf.append(escapedString("" + res) + " ");
602                if (trg != res) {
603                    buf.append("***");
604                }
605                buf.append("\n");
606            }
607        }
608        err(buf.toString());
609    }
610
611    private static String escapedString(String str) {
612        if (str == null) {
613            return null;
614        }
615
616        StringBuffer buf = new StringBuffer(str.length() * 6);
617        for (int i = 0; i < str.length(); ++i) {
618            char ch = str.charAt(i);
619            buf.append("\\u");
620            if (ch < 0x1000) {
621                buf.append('0');
622            }
623            if (ch < 0x0100) {
624                buf.append('0');
625            }
626            if (ch < 0x0010) {
627                buf.append('0');
628            }
629            buf.append(Integer.toHexString(ch));
630        }
631        return buf.toString();
632    }
633
634    /* Tests the method
635     *      public int shape(char[] source, int sourceStart, int sourceLength,
636     *      char[] dest, int destStart, int destSize) throws ArabicShapingException)
637     */
638    @Test
639    public void TestShape(){
640        // Tests when
641        //      if (sourceStart < 0 || sourceLength < 0 || sourceStart + sourceLength > source.length)
642        // Is true
643        ArabicShaping as = new ArabicShaping(0);
644        char[] source = {'d','u','m','m','y'};
645        char[] dest = {'d','u','m','m','y'};
646        int[] negNum = {-1,-2,-5,-10,-100};
647
648
649        for(int i=0; i<negNum.length; i++){
650            try{
651                // Checks when "sourceStart < 0"
652                as.shape(source, negNum[i], 0, dest, 0, 0);
653                errln("ArabicShaping.shape(char[],int,int,char[],int,int) was " +
654                        "suppose to return an exception when 'sourceStart < 0'.");
655            } catch(Exception e){}
656
657            try{
658                // Checks when "sourceLength < 0"
659                as.shape(source, 0, negNum[i], dest, 0, 0);
660                errln("ArabicShaping.shape(char[],int,int,char[],int,int) was " +
661                        "suppose to return an exception when 'sourceLength < 0'.");
662            } catch(Exception e){}
663        }
664
665        // Checks when "sourceStart + sourceLength > source.length"
666        try{
667            as.shape(source, 3, 3, dest, 0, 0);
668            errln("ArabicShaping.shape(char[],int,int,char[],int,int) was " +
669                    "suppose to return an exception when 'sourceStart + sourceLength > source.length'.");
670        } catch(Exception e){}
671        try{
672            as.shape(source, 2, 4, dest, 0, 0);
673            errln("ArabicShaping.shape(char[],int,int,char[],int,int) was " +
674                    "suppose to return an exception when 'sourceStart + sourceLength > source.length'.");
675        } catch(Exception e){}
676        try{
677            as.shape(source, 1, 5, dest, 0, 0);
678            errln("ArabicShaping.shape(char[],int,int,char[],int,int) was " +
679                    "suppose to return an exception when 'sourceStart + sourceLength > source.length'.");
680        } catch(Exception e){}
681        try{
682            as.shape(source, 0, 6, dest, 0, 0);
683            errln("ArabicShaping.shape(char[],int,int,char[],int,int) was " +
684                    "suppose to return an exception when 'sourceStart + sourceLength > source.length'.");
685        } catch(Exception e){}
686
687        // Checks when "if (dest == null && destSize != 0)" is true
688        try{
689            as.shape(source, 2, 2, null, 0, 1);
690            errln("ArabicShaping.shape(char[],int,int,char[],int,int) was " +
691                    "suppose to return an exception when 'dest == null && destSize != 0'.");
692        } catch(Exception e){}
693
694        // Checks when
695        // if ((destSize != 0) && (destStart < 0 || destSize < 0 || destStart + destSize > dest.length))
696        for(int i=0; i<negNum.length; i++){
697            try{
698                as.shape(source, 2, 2, dest, negNum[i], 1);
699                errln("ArabicShaping.shape(char[],int,int,char[],int,int) was " +
700                        "suppose to return an exception when " +
701                        "(destSize != 0) && (destStart < 0 || destSize < 0 || destStart + destSize > dest.length).");
702            } catch(Exception e){}
703
704            try{
705                as.shape(source, 2, 2, dest, 0, negNum[i]);
706                errln("ArabicShaping.shape(char[],int,int,char[],int,int) was " +
707                        "suppose to return an exception when " +
708                        "(destSize != 0) && (destStart < 0 || destSize < 0 || destStart + destSize > dest.length).");
709            } catch(Exception e){}
710        }
711
712        // Checks when "destStart + destSize > dest.length"
713        try{
714            as.shape(source, 2, 2, dest, 3, 3);
715            errln("ArabicShaping.shape(char[],int,int,char[],int,int) was " +
716                    "suppose to return an exception when " +
717                    "(destSize != 0) && (destStart < 0 || destSize < 0 || destStart + destSize > dest.length).");
718        } catch(Exception e){}
719        try{
720            as.shape(source, 2, 2, dest, 2, 4);
721            errln("ArabicShaping.shape(char[],int,int,char[],int,int) was " +
722                    "suppose to return an exception when " +
723                    "(destSize != 0) && (destStart < 0 || destSize < 0 || destStart + destSize > dest.length).");
724        } catch(Exception e){}
725        try{
726            as.shape(source, 2, 2, dest, 1, 5);
727            errln("ArabicShaping.shape(char[],int,int,char[],int,int) was " +
728                    "suppose to return an exception when " +
729                    "(destSize != 0) && (destStart < 0 || destSize < 0 || destStart + destSize > dest.length).");
730        } catch(Exception e){}
731        try{
732            as.shape(source, 2, 2, dest, 0, 6);
733            errln("ArabicShaping.shape(char[],int,int,char[],int,int) was " +
734                    "suppose to return an exception when " +
735                    "(destSize != 0) && (destStart < 0 || destSize < 0 || destStart + destSize > dest.length).");
736        } catch(Exception e){}
737
738        // Tests when "throw new IllegalArgumentException("Wrong Tashkeel argument")"
739        int[] invalid_Tashkeel = {-1000, -500, -100};
740        for(int i=0; i < invalid_Tashkeel.length; i++){
741            ArabicShaping arabicShape = new ArabicShaping(invalid_Tashkeel[i]);
742            try {
743                arabicShape.shape(source,0,0,dest,0,1);
744                errln("ArabicShaping.shape(char[],int,int,char[],int,int) was " +
745                        "suppose to return an exception for 'Wrong Tashkeel argument' for " +
746                        "an option value of " + invalid_Tashkeel[i]);
747            } catch (Exception e) {}
748        }
749    }
750
751    @Test
752    public void TestCoverage() {
753        ArabicShaping shp = new ArabicShaping(LETTERS_SHAPE | TEXT_DIRECTION_VISUAL_LTR | LENGTH_FIXED_SPACES_NEAR);
754
755        // Test ArabicShaping#toString();
756        assertEquals("ArabicShaping#toString() failed.",
757                shp.toString(),
758                "android.icu.text.ArabicShaping@d[LamAlef spaces at near, visual, shape letters," +
759                        " no digit shaping, standard Arabic-Indic digits]");
760
761        // Test ArabicShaping#hashCode()
762        assertEquals("ArabicShaping#hashCode() failed.", shp.hashCode(), 13);
763    }
764
765    private boolean getStaticCharacterHelperFunctionValue(String methodName, char testValue) throws Exception {
766        Method m = ArabicShaping.class.getDeclaredMethod(methodName, Character.TYPE);
767        m.setAccessible(true);
768        Object returnValue = m.invoke(null, testValue);
769
770        if (Integer.class.isInstance(returnValue)) {
771            return (Integer)returnValue == 1;
772        }
773        return (Boolean)returnValue;
774    }
775
776    @Test
777    public void TestHelperFunctions() throws Exception {
778        // Test private static helper functions that are used internally:
779
780        // ArabicShaping.isSeenTailFamilyChar(char)
781        assertTrue("ArabicShaping.isSeenTailFamilyChar(char) failed.",
782                getStaticCharacterHelperFunctionValue("isSeenTailFamilyChar", (char)0xfeb1));
783
784        // ArabicShaping.isAlefMaksouraChar(char)
785        assertTrue("ArabicShaping.isAlefMaksouraChar(char) failed.",
786                getStaticCharacterHelperFunctionValue("isAlefMaksouraChar", (char)0xfeef));
787
788        // ArabicShaping.isTailChar(char)
789        assertTrue("ArabicShaping.isTailChar(char) failed.",
790                getStaticCharacterHelperFunctionValue("isTailChar", (char)0x200B));
791
792        // ArabicShaping.isYehHamzaChar(char)
793        assertTrue("ArabicShaping.isYehHamzaChar(char) failed.",
794                getStaticCharacterHelperFunctionValue("isYehHamzaChar", (char)0xfe89));
795
796    }
797}
798
799