/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* $Id$ */ package org.apache.fop.complexscripts.bidi; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * <p>Test case for Unicode Bidi Algorithm.</p> */ public class BidiAlgorithmTestCase { /** * logging instance */ private static final Log log = LogFactory.getLog(BidiAlgorithmTestCase.class); /** * Concatenated array of <test-set,test-sequence> tuples * specifying which sequences are to be excluded from testing, * where -1 for either component is a wildcard. */ private static final int[] EXCLUSIONS = { // no exclusions }; /** * Concatenated array of <test-set,test-sequence> tuples * specifying which sequences are to be included in testing, where * -1 for either component is a wildcard. */ private static final int[] INCLUSIONS = { -1, -1 // all sequences }; /** * Concatenated array of <start,end> tuples expressing ranges of * test sets to be tested, where -1 in the end position signifies * all remaining test sets. */ private static final int[] TEST_SET_RANGES = { 0, -1 // all test sets }; // instrumentation private int includedSequences; private int excludedSequences; private int passedSequences; @Test public void testBidiAlgorithm() throws Exception { String ldPfx = BidiTestData.LD_PFX; int ldCount = BidiTestData.LD_CNT; for (int i = 0; i < ldCount; i++) { int[] da = BidiTestData.readTestData(ldPfx, i); if (da != null) { testBidiAlgorithm(i, da); } else { fail("unable to read bidi test data for resource at index " + i); } } // ensure we passed all test sequences assertEquals("did not pass all test sequences", BidiTestData.NUM_TEST_SEQUENCES, passedSequences); if (log.isDebugEnabled()) { log.debug("Included Sequences : " + includedSequences); log.debug("Excluded Sequences : " + excludedSequences); log.debug("Passed Sequences : " + passedSequences); } } private void testBidiAlgorithm(int testSet, int[] da) throws Exception { if (da.length < 1) { fail("test data is empty"); } else if (da.length < ((da[0] * 2) + 1)) { fail("test data is truncated"); } else { int k = 0; // extract level count int n = da[k++]; // extract level array int[] la = new int [ n ]; for (int i = 0; i < n; i++) { la[i] = da[k++]; } // extract reorder array int[] ra = new int [ n ]; for (int i = 0; i < n; i++) { ra[i] = da[k++]; } // extract and test each test sequence int testSequence = 0; int[] ta = new int [ n ]; while ((k + (1 + n)) <= da.length) { int bs = da[k++]; for (int i = 0; i < n; i++) { ta[i] = da[k++]; } if (includeSequence(testSet, testSequence)) { includedSequences++; if (!excludeSequence(testSet, testSequence)) { if (testBidiAlgorithm(testSet, testSequence, la, ra, ta, bs)) { passedSequences++; } } else { excludedSequences++; } } testSequence++; } // ensure we exhausted test data assertEquals("extraneous test data", da.length, k); } } private boolean includeTestSet(int testSet) { for (int i = 0, n = TEST_SET_RANGES.length / 2; i < n; i++) { int s = TEST_SET_RANGES [ (i * 2) + 0 ]; int e = TEST_SET_RANGES [ (i * 2) + 1 ]; if (testSet >= s) { if ((e < 0) || (testSet <= e)) { return true; } } } return false; } private boolean includeSequence(int testSet, int testSequence) { if (!includeTestSet(testSet)) { return false; } else { for (int i = 0, n = INCLUSIONS.length / 2; i < n; i++) { int setno = INCLUSIONS [ (i * 2) + 0 ]; int seqno = INCLUSIONS [ (i * 2) + 1 ]; if (setno < 0) { if (seqno < 0) { return true; } else if (seqno == testSequence) { return true; } } else if (setno == testSet) { if (seqno < 0) { return true; } else if (seqno == testSequence) { return true; } } } return false; } } private boolean excludeSequence(int testSet, int testSequence) { for (int i = 0, n = EXCLUSIONS.length / 2; i < n; i++) { int setno = EXCLUSIONS [ (i * 2) + 0 ]; int seqno = EXCLUSIONS [ (i * 2) + 1 ]; if (setno < 0) { if (seqno < 0) { return true; } else if (seqno == testSequence) { return true; } } else if (setno == testSet) { if (seqno < 0) { return true; } else if (seqno == testSequence) { return true; } } } return false; } private boolean testBidiAlgorithm(int testSet, int testSequence, int[] la, int[] ra, int[] ta, int bs) throws Exception { boolean passed = true; int n = la.length; if (ra.length != n) { fail("bad reorder array length, expected " + n + ", got " + ra.length); } else if (ta.length != n) { fail("bad test array length, expected " + n + ", got " + ta.length); } else { // auto-LTR if ((bs & 1) != 0) { // auto-LTR is performed at higher level } // LTR if ((bs & 2) != 0) { int[] levels = UnicodeBidiAlgorithm.resolveLevels(null, ta, 0, new int [ n ], true); if (!verifyResults(la, levels, ta, 0, testSet, testSequence)) { passed = false; } } // RTL if ((bs & 4) != 0) { int[] levels = UnicodeBidiAlgorithm.resolveLevels(null, ta, 1, new int [ n ], true); if (!verifyResults(la, levels, ta, 1, testSet, testSequence)) { passed = false; } } } return passed; } private boolean verifyResults(int[] laExp, int[] laOut, int[] ta, int dl, int testSet, int testSequence) { if (laOut.length != laExp.length) { fail("output levels array length mismatch, expected " + laExp.length + ", got " + laOut.length); return false; } else { int numMatch = 0; for (int i = 0, n = laExp.length; i < n; i++) { if (laExp[i] >= 0) { int lo = laOut[i]; int le = laExp[i]; if (lo != le) { assertEquals(getMismatchMessage(testSet, testSequence, i, dl), le, lo); } else { numMatch++; } } else { numMatch++; } } return numMatch == laExp.length; } } private String getMismatchMessage(int testSet, int testSequence, int seqIndex, int defaultLevel) { StringBuffer sb = new StringBuffer(); sb.append("level mismatch for default level "); sb.append(defaultLevel); sb.append(" at sequence index "); sb.append(seqIndex); sb.append(" in test sequence "); sb.append(testSequence); sb.append(" of test set "); sb.append(testSet); return sb.toString(); } }