You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

BidiAlgorithmTestCase.java 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /* $Id$ */
  18. package org.apache.fop.complexscripts.bidi;
  19. import org.junit.Test;
  20. import static org.junit.Assert.assertEquals;
  21. import static org.junit.Assert.fail;
  22. import org.apache.commons.logging.Log;
  23. import org.apache.commons.logging.LogFactory;
  24. /**
  25. * <p>Test case for Unicode Bidi Algorithm.</p>
  26. */
  27. public class BidiAlgorithmTestCase {
  28. /**
  29. * logging instance
  30. */
  31. private static final Log log = LogFactory.getLog(BidiAlgorithmTestCase.class);
  32. /**
  33. * Concatenated array of <test-set,test-sequence> tuples
  34. * specifying which sequences are to be excluded from testing,
  35. * where -1 for either component is a wildcard.
  36. */
  37. private static final int[] EXCLUSIONS = {
  38. // no exclusions
  39. };
  40. /**
  41. * Concatenated array of <test-set,test-sequence> tuples
  42. * specifying which sequences are to be included in testing, where
  43. * -1 for either component is a wildcard.
  44. */
  45. private static final int[] INCLUSIONS = {
  46. -1, -1 // all sequences
  47. };
  48. /**
  49. * Concatenated array of <start,end> tuples expressing ranges of
  50. * test sets to be tested, where -1 in the end position signifies
  51. * all remaining test sets.
  52. */
  53. private static final int[] TEST_SET_RANGES = {
  54. 0, -1 // all test sets
  55. };
  56. // instrumentation
  57. private int includedSequences;
  58. private int excludedSequences;
  59. private int passedSequences;
  60. @Test
  61. public void testBidiAlgorithm() throws Exception {
  62. String ldPfx = BidiTestData.LD_PFX;
  63. int ldCount = BidiTestData.LD_CNT;
  64. for (int i = 0; i < ldCount; i++) {
  65. int[] da = BidiTestData.readTestData(ldPfx, i);
  66. if (da != null) {
  67. testBidiAlgorithm(i, da);
  68. } else {
  69. fail("unable to read bidi test data for resource at index " + i);
  70. }
  71. }
  72. // ensure we passed all test sequences
  73. assertEquals("did not pass all test sequences", BidiTestData.NUM_TEST_SEQUENCES, passedSequences);
  74. if (log.isDebugEnabled()) {
  75. log.debug("Included Sequences : " + includedSequences);
  76. log.debug("Excluded Sequences : " + excludedSequences);
  77. log.debug("Passed Sequences : " + passedSequences);
  78. }
  79. }
  80. private void testBidiAlgorithm(int testSet, int[] da) throws Exception {
  81. if (da.length < 1) {
  82. fail("test data is empty");
  83. } else if (da.length < ((da[0] * 2) + 1)) {
  84. fail("test data is truncated");
  85. } else {
  86. int k = 0;
  87. // extract level count
  88. int n = da[k++];
  89. // extract level array
  90. int[] la = new int [ n ];
  91. for (int i = 0; i < n; i++) {
  92. la[i] = da[k++];
  93. }
  94. // extract reorder array
  95. int[] ra = new int [ n ];
  96. for (int i = 0; i < n; i++) {
  97. ra[i] = da[k++];
  98. }
  99. // extract and test each test sequence
  100. int testSequence = 0;
  101. int[] ta = new int [ n ];
  102. while ((k + (1 + n)) <= da.length) {
  103. int bs = da[k++];
  104. for (int i = 0; i < n; i++) {
  105. ta[i] = da[k++];
  106. }
  107. if (includeSequence(testSet, testSequence)) {
  108. includedSequences++;
  109. if (!excludeSequence(testSet, testSequence)) {
  110. if (testBidiAlgorithm(testSet, testSequence, la, ra, ta, bs)) {
  111. passedSequences++;
  112. }
  113. } else {
  114. excludedSequences++;
  115. }
  116. }
  117. testSequence++;
  118. }
  119. // ensure we exhausted test data
  120. assertEquals("extraneous test data", da.length, k);
  121. }
  122. }
  123. private boolean includeTestSet(int testSet) {
  124. for (int i = 0, n = TEST_SET_RANGES.length / 2; i < n; i++) {
  125. int s = TEST_SET_RANGES [ (i * 2) + 0 ];
  126. int e = TEST_SET_RANGES [ (i * 2) + 1 ];
  127. if (testSet >= s) {
  128. if ((e < 0) || (testSet <= e)) {
  129. return true;
  130. }
  131. }
  132. }
  133. return false;
  134. }
  135. private boolean includeSequence(int testSet, int testSequence) {
  136. if (!includeTestSet(testSet)) {
  137. return false;
  138. } else {
  139. for (int i = 0, n = INCLUSIONS.length / 2; i < n; i++) {
  140. int setno = INCLUSIONS [ (i * 2) + 0 ];
  141. int seqno = INCLUSIONS [ (i * 2) + 1 ];
  142. if (setno < 0) {
  143. if (seqno < 0) {
  144. return true;
  145. } else if (seqno == testSequence) {
  146. return true;
  147. }
  148. } else if (setno == testSet) {
  149. if (seqno < 0) {
  150. return true;
  151. } else if (seqno == testSequence) {
  152. return true;
  153. }
  154. }
  155. }
  156. return false;
  157. }
  158. }
  159. private boolean excludeSequence(int testSet, int testSequence) {
  160. for (int i = 0, n = EXCLUSIONS.length / 2; i < n; i++) {
  161. int setno = EXCLUSIONS [ (i * 2) + 0 ];
  162. int seqno = EXCLUSIONS [ (i * 2) + 1 ];
  163. if (setno < 0) {
  164. if (seqno < 0) {
  165. return true;
  166. } else if (seqno == testSequence) {
  167. return true;
  168. }
  169. } else if (setno == testSet) {
  170. if (seqno < 0) {
  171. return true;
  172. } else if (seqno == testSequence) {
  173. return true;
  174. }
  175. }
  176. }
  177. return false;
  178. }
  179. private boolean testBidiAlgorithm(int testSet, int testSequence, int[] la, int[] ra, int[] ta, int bs)
  180. throws Exception {
  181. boolean passed = true;
  182. int n = la.length;
  183. if (ra.length != n) {
  184. fail("bad reorder array length, expected " + n + ", got " + ra.length);
  185. } else if (ta.length != n) {
  186. fail("bad test array length, expected " + n + ", got " + ta.length);
  187. } else {
  188. // auto-LTR
  189. if ((bs & 1) != 0) {
  190. // auto-LTR is performed at higher level
  191. }
  192. // LTR
  193. if ((bs & 2) != 0) {
  194. int[] levels = UnicodeBidiAlgorithm.resolveLevels(null, ta, 0, new int [ n ], true);
  195. if (!verifyResults(la, levels, ta, 0, testSet, testSequence)) {
  196. passed = false;
  197. }
  198. }
  199. // RTL
  200. if ((bs & 4) != 0) {
  201. int[] levels = UnicodeBidiAlgorithm.resolveLevels(null, ta, 1, new int [ n ], true);
  202. if (!verifyResults(la, levels, ta, 1, testSet, testSequence)) {
  203. passed = false;
  204. }
  205. }
  206. }
  207. return passed;
  208. }
  209. private boolean verifyResults(int[] laExp, int[] laOut, int[] ta, int dl, int testSet, int testSequence) {
  210. if (laOut.length != laExp.length) {
  211. fail("output levels array length mismatch, expected " + laExp.length + ", got " + laOut.length);
  212. return false;
  213. } else {
  214. int numMatch = 0;
  215. for (int i = 0, n = laExp.length; i < n; i++) {
  216. if (laExp[i] >= 0) {
  217. int lo = laOut[i];
  218. int le = laExp[i];
  219. if (lo != le) {
  220. assertEquals(getMismatchMessage(testSet, testSequence, i, dl), le, lo);
  221. } else {
  222. numMatch++;
  223. }
  224. } else {
  225. numMatch++;
  226. }
  227. }
  228. return numMatch == laExp.length;
  229. }
  230. }
  231. private String getMismatchMessage(int testSet, int testSequence, int seqIndex, int defaultLevel) {
  232. StringBuffer sb = new StringBuffer();
  233. sb.append("level mismatch for default level ");
  234. sb.append(defaultLevel);
  235. sb.append(" at sequence index ");
  236. sb.append(seqIndex);
  237. sb.append(" in test sequence ");
  238. sb.append(testSequence);
  239. sb.append(" of test set ");
  240. sb.append(testSet);
  241. return sb.toString();
  242. }
  243. }