/* ******************************************************************************* * Copyright (C) 2007-2010, International Business Machines * Corporation and others. All Rights Reserved. ******************************************************************************* */ package com.ibm.icu.dev.test.bidi; import java.util.Arrays; import com.ibm.icu.text.Bidi; import com.ibm.icu.text.BidiRun; /** * Regression test for Bidi class override. * * @author Lina Kemmel, Matitiahu Allouche */ public class TestBidi extends BidiTest { private static final int MAXLEN = 256; private static final String levelString = "............................"; public void testBidi() { Bidi bidi; Bidi bidiLine; logln("\nEntering TestBidi"); bidi = new Bidi(MAXLEN, 0); bidiLine = new Bidi(); doTests(bidi, bidiLine, false); doTests(bidi, bidiLine, true); doMisc(); logln("\nExiting TestBidi"); } private void doTests(Bidi bidi, Bidi bidiLine, boolean countRunsFirst) { int testNumber; String string; int lineStart; byte paraLevel; int bidiTestCount = TestData.testCount(); for (testNumber = 0; testNumber < bidiTestCount; ++testNumber) { TestData test = TestData.getTestData(testNumber); string = getStringFromDirProps(test.dirProps); paraLevel = test.paraLevel; try { bidi.setPara(string, paraLevel, null); logln("Bidi.setPara(tests[" + testNumber + "] OK, direction " + bidi.getDirection() + " paraLevel " + paraLevel); } catch (Exception e) { errln("Bidi.setPara(tests[" + testNumber + "] failed, direction " + bidi.getDirection() + " paraLevel " + paraLevel); } lineStart = test.lineStart; if (lineStart == -1) { doTest(bidi, testNumber, test, 0, countRunsFirst); } else { try { bidiLine = bidi.setLine(lineStart, test.lineLimit); logln("Bidi.setLine(" + lineStart + ", " + test.lineLimit + "), in tests[" + testNumber + "] OK, direction " + bidiLine.getDirection() + " paraLevel " + bidiLine.getBaseLevel()); doTest(bidiLine, testNumber, test, lineStart, countRunsFirst); } catch (Exception e) { errln("Bidi.setLine(" + lineStart + ", " + test.lineLimit + "), in runAll test[" + testNumber + "] failed"); } /* do it again using createLineBidi instead of setLine */ try { bidiLine = bidi.createLineBidi(lineStart, test.lineLimit); logln("Bidi.createLineBidi(" + lineStart + ", " + test.lineLimit + "), in tests[" + testNumber + "] OK, direction " + bidiLine.getDirection() + " paraLevel " + bidiLine.getBaseLevel()); doTest(bidiLine, testNumber, test, lineStart, countRunsFirst); } catch (Exception e) { errln("Bidi.createLineBidi(" + lineStart + ", " + test.lineLimit + "), in runAll test[" + testNumber + "] failed"); } } } } private void doTest(Bidi bidi, int testNumber, TestData test, int lineStart, boolean countRunsFirst) { short[] dirProps = test.dirProps; byte[] levels = test.levels; int[] visualMap = test.visualMap; int i, len = bidi.getLength(), logicalIndex = -1, runCount = 0; byte level, level2; if (countRunsFirst) { logln("Calling Bidi.countRuns() first."); try { runCount = bidi.countRuns(); } catch (IllegalStateException e) { errln("Bidi.countRuns(test[" + testNumber + "]) failed"); } } else { logln("Calling Bidi.getLogicalMap() first."); } _testReordering(bidi, testNumber); for (i = 0; i < len; ++i) { logln(i + " " + bidi.getLevelAt(i) + " " + levelString + TestData.dirPropNames[dirProps[lineStart + i]] + " " + bidi.getVisualIndex(i)); } log("\n-----levels:"); for (i = 0; i < len; ++i) { if (i > 0) { log(","); } log(" " + bidi.getLevelAt(i)); } log("\n--reordered:"); for (i = 0; i < len; ++i) { if (i > 0) { log(","); } log(" " + bidi.getVisualIndex(i)); } log("\n"); assertEquals("\nFailure in Bidi.getDirection(test[" + testNumber + "])", test.direction, bidi.getDirection()); assertEquals("\nFailure in Bidi.getParaLevel(test[" + testNumber + "])", test.resultLevel, bidi.getParaLevel()); for (i = 0; i < len; ++i) { assertEquals("\nFailure in Bidi.getLevelAt(" + i + ") in test[" + testNumber + "]", levels[i], bidi.getLevelAt(i)); } for (i = 0; i < len; ++i) { try { logicalIndex = bidi.getVisualIndex(i); } catch (Throwable th) { errln("Bidi.getVisualIndex(" + i + ") in test[" + testNumber + "] failed"); } if(visualMap[i] != logicalIndex) { assertEquals("\nFailure in Bidi.getVisualIndex(" + i + ") in test[" + testNumber + "])", visualMap[i], logicalIndex); } } if (!countRunsFirst) { try { runCount = bidi.countRuns(); } catch (IllegalStateException e) { errln("Bidi.countRuns(test[" + testNumber + "]) failed"); } } BidiRun run; for (logicalIndex = 0; logicalIndex < len; ) { level = bidi.getLevelAt(logicalIndex); run = bidi.getLogicalRun(logicalIndex); logicalIndex = run.getLimit(); level2 = run.getEmbeddingLevel(); assertEquals("Logical " + run.toString() + " in test[" + testNumber + "]: wrong level", level, level2); if (--runCount < 0) { errln("Bidi.getLogicalRun(test[" + testNumber + "]): wrong number of runs compared to Bidi.countRuns() = " + bidi.countRuns()); } } if (runCount != 0) { errln("Bidi.getLogicalRun(test[" + testNumber + "]): wrong number of runs compared to Bidi.countRuns() = " + bidi.countRuns()); } log("\n\n"); } private void _testReordering(Bidi bidi, int testNumber) { int[] logicalMap1; int[] logicalMap2; int[] logicalMap3; int[] visualMap1; int[] visualMap2; int[] visualMap3; int[] visualMap4 = new int[MAXLEN]; byte[] levels; int i, length = bidi.getLength(), destLength = bidi.getResultLength(); int runCount, visualIndex, logicalIndex = -1, logicalStart, runLength; boolean odd; if(length <= 0) { return; } /* get the logical and visual maps from the object */ logicalMap1 = bidi.getLogicalMap(); if (logicalMap1 == null) { errln("getLogicalMap in test " + testNumber + " is null"); logicalMap1 = new int[0]; } visualMap1 = bidi.getVisualMap(); if (visualMap1 == null) { errln("getVisualMap() in test " + testNumber + " is null"); visualMap1 = new int[0]; } /* invert them both */ visualMap2 = Bidi.invertMap(logicalMap1); logicalMap2 = Bidi.invertMap(visualMap1); /* get them from the levels array, too */ levels = bidi.getLevels(); if (levels == null || levels.length != length) { errln("getLevels() in test " + testNumber + " failed"); } logicalMap3 = Bidi.reorderLogical(levels); visualMap3 = Bidi.reorderVisual(levels); /* get the visual map from the runs, too */ try { runCount = bidi.countRuns(); } catch (IllegalStateException e) { errln("countRuns() in test " + testNumber + " failed"); runCount = 0; } logln("\n---- " + runCount + " runs"); visualIndex = 0; BidiRun run; for (i = 0; i < runCount; ++i) { run = bidi.getVisualRun(i); if (run == null) { errln("null visual run encountered at index " + i + ", in test " + testNumber); continue; } odd = run.isOddRun(); logicalStart = run.getStart(); runLength = run.getLength(); log("(" + (run.isOddRun() ? "R" : "L")); log(" @" + run.getStart() + '[' + run.getLength() + "])\n"); if (!odd) { do { /* LTR */ visualMap4[visualIndex++] = logicalStart++; } while (--runLength > 0); } else { logicalStart += runLength; /* logicalLimit */ do { /* RTL */ visualMap4[visualIndex++] = --logicalStart; } while (--runLength > 0); } } log("\n"); /* print all the maps */ logln("logical maps:"); for (i = 0; i < length; ++i) { log(logicalMap1[i] + " "); } log("\n"); for (i = 0; i < length; ++i) { log(logicalMap2[i] + " "); } log("\n"); for (i = 0; i < length; ++i) { log(logicalMap3[i] + " "); } log("\nvisual maps:\n"); for (i = 0; i < destLength; ++i) { log(visualMap1[i] + " "); } log("\n"); for (i = 0; i < destLength; ++i) { log(visualMap2[i] + " "); } log("\n"); for (i = 0; i < length; ++i) { log(visualMap3[i] + " "); } log("\n"); for (i = 0; i < length; ++i) { log(visualMap4[i] + " "); } log("\n"); /* check that the indexes are the same between these and Bidi.getLogical/VisualIndex() */ for (i = 0; i < length; ++i) { if (logicalMap1[i] != logicalMap2[i]) { errln("Error in tests[" + testNumber + "]: (logicalMap1[" + i + "] == " + logicalMap1[i] + ") != (logicalMap2[" + i + "] == " + logicalMap2[i] + ")"); } if (logicalMap1[i] != logicalMap3[i]) { errln("Error in tests[" + testNumber + "]: (logicalMap1[" + i + "] == " + logicalMap1[i] + ") != (logicalMap3[" + i + "] == " + logicalMap3[i] + ")"); } if (visualMap1[i] != visualMap2[i]) { errln("Error in tests[" + testNumber + "]: (visualMap1[" + i + "] == " + visualMap1[i] + ") != (visualMap2[" + i + "] == " + visualMap2[i] + ")"); } if (visualMap1[i] != visualMap3[i]) { errln("Error in tests[" + testNumber + "]: (visualMap1[" + i + "] == " + visualMap1[i] + ") != (visualMap3[" + i + "] == " + visualMap3[i] + ")"); } if (visualMap1[i] != visualMap4[i]) { errln("Error in tests[" + testNumber + "]: (visualMap1[" + i + "] == " + visualMap1[i] + ") != (visualMap4[" + i + "] == " + visualMap4[i] + ")"); } try { visualIndex = bidi.getVisualIndex(i); } catch (Exception e) { errln("Bidi.getVisualIndex(" + i + ") failed in tests[" + testNumber + "]"); } if (logicalMap1[i] != visualIndex) { errln("Error in tests[" + testNumber + "]: (logicalMap1[" + i + "] == " + logicalMap1[i] + ") != (Bidi.getVisualIndex(" + i + ") == " + visualIndex + ")"); } try { logicalIndex = bidi.getLogicalIndex(i); } catch (Exception e) { errln("Bidi.getLogicalIndex(" + i + ") failed in tests[" + testNumber + "]"); } if (visualMap1[i] != logicalIndex) { errln("Error in tests[" + testNumber + "]: (visualMap1[" + i + "] == " + visualMap1[i] + ") != (Bidi.getLogicalIndex(" + i + ") == " + logicalIndex + ")"); } } } private String getStringFromDirProps(short[] dirProps) { int i; if (dirProps == null) { return null; } int length = dirProps.length; char[] buffer = new char[length]; /* this part would have to be modified for UTF-x */ for (i = 0; i < length; ++i) { buffer[i] = charFromDirProp[dirProps[i]]; } return new String(buffer); } private void doMisc() { /* Miscellaneous tests to exercize less popular code paths */ Bidi bidi = new Bidi(120, 66), bidiLine; assertEquals("\nwriteReverse should return an empty string", "", Bidi.writeReverse("", 0)); bidi.setPara("", Bidi.LTR, null); assertEquals("\nwriteReordered should return an empty string", "", bidi.writeReordered(0)); bidi.setPara("abc", Bidi.LTR, null); assertEquals("\ngetRunStart should return 0", 0, bidi.getRunStart(0)); assertEquals("\ngetRunLimit should return 3", 3, bidi.getRunLimit(0)); bidi.setPara("abc ", Bidi.RTL, null); bidiLine = bidi.setLine(0, 6); for (int i = 3; i < 6; i++) { assertEquals("\nTrailing space at " + i + " should get paragraph level", Bidi.RTL, bidiLine.getLevelAt(i)); } bidi.setPara("abc def", Bidi.RTL, null); bidiLine = bidi.setLine(0, 6); for (int i = 3; i < 6; i++) { assertEquals("\nTrailing space at " + i + " should get paragraph level", Bidi.RTL, bidiLine.getLevelAt(i)); } bidi.setPara("abcdefghi ", Bidi.RTL, null); bidiLine = bidi.setLine(0, 6); for (int i = 3; i < 6; i++) { assertEquals("\nTrailing char at " + i + " should get level 2", 2, bidiLine.getLevelAt(i)); } bidi.setReorderingOptions(Bidi.OPTION_REMOVE_CONTROLS); bidi.setPara("\u200eabc def", Bidi.RTL, null); bidiLine = bidi.setLine(0, 6); assertEquals("\nWrong result length", 5, bidiLine.getResultLength()); bidi.setPara("abcdefghi", Bidi.LTR, null); bidiLine = bidi.setLine(0, 6); assertEquals("\nWrong direction #1", Bidi.LTR, bidiLine.getDirection()); bidi.setPara("", Bidi.LTR, null); byte[] levels = bidi.getLevels(); assertEquals("\nWrong number of level elements", 0, levels.length); assertEquals("\nWrong number of runs #1", 0, bidi.countRuns()); bidi.setPara(" ", Bidi.RTL, null); bidiLine = bidi.setLine(0, 6); assertEquals("\nWrong number of runs #2", 1, bidiLine.countRuns()); bidi.setPara("a\u05d0 bc", Bidi.RTL, null); bidiLine = bidi.setLine(0, 6); assertEquals("\nWrong direction #2", Bidi.MIXED, bidi.getDirection()); assertEquals("\nWrong direction #3", Bidi.MIXED, bidiLine.getDirection()); assertEquals("\nWrong number of runs #3", 2, bidiLine.countRuns()); int[] map = Bidi.reorderLogical(null); assertTrue("\nWe should have got a null map #1", map == null); map = Bidi.reorderLogical(new byte[] {0,99,99}); assertTrue("\nWe should have got a null map #2", map == null); map = Bidi.reorderVisual(null); assertTrue("\nWe should have got a null map #3", map == null); map = Bidi.invertMap(null); assertTrue("\nWe should have got a null map #4", map == null); map = Bidi.invertMap(new int[] {0,1,-1,5,4}); assertTrue("\nUnexpected inverted Map", Arrays.equals(map, new int[] {0,1,-1,-1,4,3})); bidi.setPara("", Bidi.LTR, null); map = bidi.getLogicalMap(); assertTrue("\nMap should have length==0 #1", map.length == 0); map = bidi.getVisualMap(); assertTrue("\nMap should have length==0 #2", map.length == 0); /* test BidiRun.toString and allocation of run memory > 1 */ bidi.setPara("abc", Bidi.LTR, null); assertEquals("\nWrong run display", "BidiRun 0 - 3 @ 0", bidi.getLogicalRun(0).toString()); /* test REMOVE_BIDI_CONTROLS together with DO_MIRRORING */ bidi.setPara("abc\u200e", Bidi.LTR, null); String out = bidi.writeReordered(Bidi.REMOVE_BIDI_CONTROLS | Bidi.DO_MIRRORING); assertEquals("\nWrong result #1", "abc", out); /* test inverse Bidi with marks and contextual orientation */ bidi.setReorderingMode(Bidi.REORDER_INVERSE_LIKE_DIRECT); bidi.setReorderingOptions(Bidi.OPTION_INSERT_MARKS); bidi.setPara("", Bidi.LEVEL_DEFAULT_RTL, null); out = bidi.writeReordered(0); assertEquals("\nWrong result #2", "", out); bidi.setPara(" ", Bidi.LEVEL_DEFAULT_RTL, null); out = bidi.writeReordered(0); assertEquals("\nWrong result #3", " ", out); bidi.setPara("abc", Bidi.LEVEL_DEFAULT_RTL, null); out = bidi.writeReordered(0); assertEquals("\nWrong result #4", "abc", out); bidi.setPara("\u05d0\u05d1", Bidi.LEVEL_DEFAULT_RTL, null); out = bidi.writeReordered(0); assertEquals("\nWrong result #5", "\u05d1\u05d0", out); bidi.setPara("abc \u05d0\u05d1", Bidi.LEVEL_DEFAULT_RTL, null); out = bidi.writeReordered(0); assertEquals("\nWrong result #6", "\u05d1\u05d0 abc", out); bidi.setPara("\u05d0\u05d1 abc", Bidi.LEVEL_DEFAULT_RTL, null); out = bidi.writeReordered(0); assertEquals("\nWrong result #7", "\u200fabc \u05d1\u05d0", out); bidi.setPara("\u05d0\u05d1 abc .-=", Bidi.LEVEL_DEFAULT_RTL, null); out = bidi.writeReordered(0); assertEquals("\nWrong result #8", "\u200f=-. abc \u05d1\u05d0", out); bidi.orderParagraphsLTR(true); bidi.setPara("\n\r \n\rabc\n\u05d0\u05d1\rabc \u05d2\u05d3\n\r" + "\u05d4\u05d5 abc\n\u05d6\u05d7 abc .-=\r\n" + "-* \u05d8\u05d9 abc .-=", Bidi.LEVEL_DEFAULT_RTL, null); out = bidi.writeReordered(0); assertEquals("\nWrong result #9", "\n\r \n\rabc\n\u05d1\u05d0\r\u05d3\u05d2 abc\n\r" + "\u200fabc \u05d5\u05d4\n\u200f=-. abc \u05d7\u05d6\r\n" + "\u200f=-. abc \u05d9\u05d8 *-", out); bidi.setPara("\u05d0 \t", Bidi.LTR, null); out = bidi.writeReordered(0); assertEquals("\nWrong result #10", "\u05D0\u200e \t", out); bidi.setPara("\u05d0 123 \t\u05d1 123 \u05d2", Bidi.LTR, null); out = bidi.writeReordered(0); assertEquals("\nWrong result #11", "\u05d0 \u200e123\u200e \t\u05d2 123 \u05d1", out); bidi.setPara("\u05d0 123 \u0660\u0661 ab", Bidi.LTR, null); out = bidi.writeReordered(0); assertEquals("\nWrong result #12", "\u05d0 \u200e123 \u200e\u0660\u0661 ab", out); bidi.setPara("ab \t", Bidi.RTL, null); out = bidi.writeReordered(0); assertEquals("\nWrong result #13", "\u200f\t ab", out); /* check exceeding para level */ bidi = new Bidi(); bidi.setPara("A\u202a\u05d0\u202aC\u202c\u05d1\u202cE", (byte)(Bidi.MAX_EXPLICIT_LEVEL - 1), null); assertEquals("\nWrong level at index 2", 61, bidi.getLevelAt(2)); /* check 1-char runs with RUNS_ONLY */ bidi.setReorderingMode(Bidi.REORDER_RUNS_ONLY); bidi.setPara("a \u05d0 b \u05d1 c \u05d2 d ", Bidi.LTR, null); assertEquals("\nWrong number of runs #4", 14, bidi.countRuns()); } public static void main(String[] args) { try { new TestBidi().run(args); } catch (Exception e) { System.out.println(e); } } }