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) 2001-2009, International Business Machines 6* Corporation and others. All Rights Reserved. 7******************************************************************************* 8*/ 9 10package com.ibm.icu.dev.test.shaping; 11 12import org.junit.Ignore; 13import org.junit.Test; 14 15import com.ibm.icu.text.ArabicShaping; 16import com.ibm.icu.text.ArabicShapingException; 17 18/** 19 * Interactive test for Arabic shaping. 20 * Invoke from a command line passing args and strings. Use '-help' to see description of arguments. 21 */ 22// TODO(junit): wasn't running before - needs to be fixed 23public class ArabicShapingTest{ 24 private static final int COPY = 0; 25 private static final int INPLACE = 1; 26 private static final int STRING = 2; 27 28 // TODO(junit): marked with a test to keep from failing during ant run 29 @Ignore 30 @Test 31 public void dummyTest() { 32 } 33 34 public static final void main(String[] args) { 35 int testtype = COPY; 36 int options = 0; 37 int ss = 0; 38 int sl = -1; 39 int ds = 0; 40 int dl = -1; 41 String text = "$22.4 test 123 \ufef6\u0644\u0622 456 \u0664\u0665\u0666!"; 42 43 for (int i = 0; i < args.length; ++i) { 44 String arg = args[i]; 45 if (arg.charAt(0) == '-') { 46 String opt = arg.substring(1); 47 String val = opt; 48 int index = arg.indexOf(':'); 49 if (index != -1) { 50 opt = opt.substring(0, Math.min(index, 3)); 51 val = arg.substring(index + 1); 52 } 53 54 if (opt.equalsIgnoreCase("len")) { 55 options &= ~ArabicShaping.LENGTH_MASK; 56 if (val.equalsIgnoreCase("gs")) { 57 options |= ArabicShaping.LENGTH_GROW_SHRINK; 58 } else if (val.equalsIgnoreCase("sn")) { 59 options |= ArabicShaping.LENGTH_FIXED_SPACES_NEAR; 60 } else if (val.equalsIgnoreCase("se")) { 61 options |= ArabicShaping.LENGTH_FIXED_SPACES_AT_END; 62 } else if (val.equalsIgnoreCase("sb")) { 63 options |= ArabicShaping.LENGTH_FIXED_SPACES_AT_BEGINNING; 64 } else { 65 throwValError(opt, val); 66 } 67 } else if (opt.equalsIgnoreCase("dir")) { 68 options &= ~ArabicShaping.TEXT_DIRECTION_MASK; 69 if (val.equalsIgnoreCase("log")) { 70 options |= ArabicShaping.TEXT_DIRECTION_LOGICAL; 71 } else if (val.equalsIgnoreCase("vis")) { 72 options |= ArabicShaping.TEXT_DIRECTION_VISUAL_LTR; 73 } else { 74 throwValError(opt, val); 75 } 76 } else if (opt.equalsIgnoreCase("let")) { 77 options &= ~ArabicShaping.LETTERS_MASK; 78 if (val.equalsIgnoreCase("no")) { 79 options |= ArabicShaping.LETTERS_NOOP; 80 } else if (val.equalsIgnoreCase("sh")) { 81 options |= ArabicShaping.LETTERS_SHAPE; 82 } else if (val.equalsIgnoreCase("un")) { 83 options |= ArabicShaping.LETTERS_UNSHAPE; 84 } else if (val.equalsIgnoreCase("ta")) { 85 options |= ArabicShaping.LETTERS_SHAPE_TASHKEEL_ISOLATED; 86 } else { 87 throwValError(opt, val); 88 } 89 } else if (opt.equalsIgnoreCase("dig")) { 90 options &= ~ArabicShaping.DIGITS_MASK; 91 if (val.equalsIgnoreCase("no")) { 92 options |= ArabicShaping.DIGITS_NOOP; 93 } else if (val.equalsIgnoreCase("ea")) { 94 options |= ArabicShaping.DIGITS_EN2AN; 95 } else if (val.equalsIgnoreCase("ae")) { 96 options |= ArabicShaping.DIGITS_AN2EN; 97 } else if (val.equalsIgnoreCase("lr")) { 98 options |= ArabicShaping.DIGITS_EN2AN_INIT_LR; 99 } else if (val.equalsIgnoreCase("al")) { 100 options |= ArabicShaping.DIGITS_EN2AN_INIT_AL; 101 } else { 102 throwValError(opt, val); 103 } 104 } else if (opt.equalsIgnoreCase("typ")) { 105 options &= ~ArabicShaping.DIGIT_TYPE_MASK; 106 if (val.equalsIgnoreCase("an")) { 107 options |= ArabicShaping.DIGIT_TYPE_AN; 108 } else if (val.equalsIgnoreCase("ex")) { 109 options |= ArabicShaping.DIGIT_TYPE_AN_EXTENDED; 110 } else { 111 throwValError(opt, val); 112 } 113 } else if (opt.equalsIgnoreCase("dst")) { 114 try { 115 ds = Integer.parseInt(val); 116 } 117 catch (Exception e) { 118 throwValError(opt, val); 119 } 120 } else if (opt.equalsIgnoreCase("dln")) { 121 try { 122 dl = Integer.parseInt(val); 123 } 124 catch (Exception e) { 125 throwValError(opt, val); 126 } 127 } else if (opt.equalsIgnoreCase("sst")) { 128 try { 129 ss = Integer.parseInt(val); 130 } 131 catch (Exception e) { 132 throwValError(opt, val); 133 } 134 } else if (opt.equalsIgnoreCase("sln")) { 135 try { 136 sl = Integer.parseInt(val); 137 } 138 catch (Exception e) { 139 throwValError(opt, val); 140 } 141 } else if (opt.equalsIgnoreCase("tes")) { 142 if (val.equalsIgnoreCase("cp")) { 143 testtype = COPY; 144 } else if (val.equalsIgnoreCase("ip")) { 145 testtype = INPLACE; 146 } else if (val.equalsIgnoreCase("st")) { 147 testtype = STRING; 148 } else { 149 throwValError(opt, val); 150 } 151 } else if (opt.equalsIgnoreCase("help")) { 152 System.out.println(usage); 153 } else { 154 throwOptError(opt); 155 } 156 } else { 157 // assume text 158 text = parseText(arg); 159 } 160 } 161 162 if (sl < 0) { 163 sl = text.length() - ss; 164 System.out.println("sl defaulting to " + sl); 165 } 166 if (dl < 0) { 167 dl = 2 * sl; 168 System.out.println("dl defaulting to " + dl); 169 } 170 171 ArabicShaping shaper = new ArabicShaping(options); 172 System.out.println("shaper: " + shaper); 173 174 char[] src = text.toCharArray(); 175 System.out.println(" input: '" + escapedText(src, ss, sl) + "'"); 176 if (testtype != STRING) { 177 System.out.println("start: " + ss + " length: " + sl + " total length: " + src.length); 178 } 179 180 int result = -1; 181 char[] dest = null; 182 183 try { 184 switch (testtype) { 185 case COPY: 186 dest = new char[ds + dl]; 187 result = shaper.shape(src, ss, sl, dest, ds, dl); 188 break; 189 190 case INPLACE: 191 shaper.shape(src, ss, sl); 192 ds = ss; 193 result = sl; 194 dest = src; 195 break; 196 197 case STRING: 198 dest = shaper.shape(text).toCharArray(); 199 ds = 0; 200 result = dest.length; 201 break; 202 } 203 204 System.out.println("output: '" + escapedText(dest, ds, result) + "'"); 205 System.out.println("length: " + result); 206 if (ds != 0 || result != dest.length) { 207 System.out.println("full output: '" + escapedText(dest, 0, dest.length) + "'"); 208 } 209 } 210 catch (ArabicShapingException e) { 211 System.out.println("Caught ArabicShapingException"); 212 System.out.println(e); 213 } 214 catch (Exception e) { 215 System.out.println("Caught Exception"); 216 System.out.println(e); 217 } 218 } 219 220 private static void throwOptError(String opt) { 221 throwUsageError("unknown option: " + opt); 222 } 223 224 private static void throwValError(String opt, String val) { 225 throwUsageError("unknown value: " + val + " for option: " + opt); 226 } 227 228 private static void throwUsageError(String message) { 229 StringBuffer buf = new StringBuffer("*** usage error ***\n"); 230 buf.append(message); 231 buf.append("\n"); 232 buf.append(usage); 233 throw new Error(buf.toString()); 234 } 235 236 private static final String usage = 237 "Usage: [option]* [text]\n" + 238 " where option is in the format '-opt[:val]'\n" + 239 " options are:\n" + 240 " -len:[gs|sn|se|sb] (length: grow/shrink, spaces near, spaces end, spaces beginning)\n" + 241 " -dir:[log|vis] (direction: logical, visual)\n" + 242 " -let:[no|sh|un|ta] (letters: noop, shape, unshape, tashkeel)\n" + 243 // " -let:[no|sh|un] (letters: noop, shape, unshape)\n" + 244 " -dig:[no|ea|ae|lr|al] (digits: noop, en2an, an2en, en2an_lr, en2an_al)\n" + 245 " -typ:[an|ex] (digit type: arabic, arabic extended)\n" + 246 " -dst:# (dest start: [integer])\n" + 247 " -dln:# (dest length (max size): [integer])\n" + 248 " -sst:# (source start: [integer])\n" + 249 " -sln:# (source length: [integer])\n" + 250 " -tes:[cp|ip|st] (test type: copy, in place, string)\n" + 251 " -help (print this help message)\n" + 252 " text can contain unicode escape values in the format '\\uXXXX' only\n"; 253 254 private static String escapedText(char[] text, int start, int length) { 255 StringBuffer buf = new StringBuffer(); 256 for (int i = start, e = start + length; i < e; ++i) { 257 char ch = text[i]; 258 if (ch < 0x20 || ch > 0x7e) { 259 buf.append("\\u"); 260 if (ch < 0x1000) { 261 buf.append('0'); 262 } 263 if (ch < 0x100) { 264 buf.append('0'); 265 } 266 if (ch < 0x10) { 267 buf.append('0'); 268 } 269 buf.append(Integer.toHexString(ch)); 270 } else { 271 buf.append(ch); 272 } 273 } 274 return buf.toString(); 275 } 276 277 private static String parseText(String text) { 278 // process unicode escapes (only) 279 StringBuffer buf = new StringBuffer(); 280 char[] chars = text.toCharArray(); 281 for (int i = 0; i < chars.length; ++i) { 282 char ch = chars[i]; 283 if (ch == '\\') { 284 if ((i < chars.length - 1) && 285 (chars[i+1] == 'u')) { 286 int val = Integer.parseInt(text.substring(i+2, i+6), 16); 287 buf.append((char)val); 288 i += 5; 289 } else { 290 buf.append('\\'); 291 } 292 } else { 293 buf.append(ch); 294 } 295 } 296 return buf.toString(); 297 } 298} 299