| /* |
| * 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.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| import org.apache.fop.layoutmgr.BidiUtil; |
| import org.apache.fop.text.bidi.BidiClassUtils; |
| import org.apache.fop.util.BidiConstants; |
| |
| import org.junit.Test; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.fail; |
| |
| /** |
| * <p>Test case for Unicode Bidi Algorithm.</p> |
| * @author Glenn Adams |
| */ |
| public class BidiAlgorithmTestCase { |
| |
| /** |
| * logging instance |
| */ |
| private static final Log log = LogFactory.getLog(BidiAlgorithmTestCase.class); // CSOK: ConstantNameCheck |
| |
| /** |
| * 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 = BidiUtil.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 = BidiUtil.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(); |
| } |
| |
| } |