1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // Include test fixture.
6 GEN_INCLUDE(['../testing/chromevox_unittest_base.js',
7 '../testing/assert_additions.js']);
12 * @extends {ChromeVoxUnitTestBase}
14 function CvoxExpandingBrailleTranslatorUnitTest() {}
16 CvoxExpandingBrailleTranslatorUnitTest.prototype = {
17 __proto__: ChromeVoxUnitTestBase.prototype,
21 'cvox.ExpandingBrailleTranslator',
24 'cvox.ValueSelectionSpan',
30 * An implementation of {@link cvox.LibLouis.Translator} whose translation
31 * output is an array buffer of the same byte length as the input and where
32 * each byte is equal to the character code of {@code resultChar}. The
33 * position mappings are one to one in both directions.
34 * @param {string} resultChar A one character string used for each byte of the
37 * @extends {cvox.LibLouis.Translator}
39 function FakeTranslator(resultChar) {
40 /** @private {string} */
41 this.resultChar_ = resultChar;
44 FakeTranslator.prototype = {
46 translate: function(text, callback) {
47 var result = new Uint8Array(text.length);
48 var textToBraille = [];
49 var brailleToText = [];
50 for (var i = 0; i < text.length; ++i) {
51 result[i] = this.resultChar_.charCodeAt(0);
52 textToBraille.push(i);
53 brailleToText.push(i);
55 callback(result.buffer, textToBraille, brailleToText);
60 * Asserts that a array buffer, viewed as an uint8 array, matches
61 * the contents of a string. The character code of each character of the
62 * string shall match the corresponding byte in the array buffer.
63 * @param {ArrayBuffer} actual Actual array buffer.
64 * @param {string} expected Array of expected bytes.
66 function assertArrayBufferMatches(expected, actual) {
67 assertTrue(actual instanceof ArrayBuffer);
68 var a = new Uint8Array(actual);
69 assertEquals(expected.length, a.length);
70 for (var i = 0; i < a.length; ++i) {
71 assertEquals(expected.charCodeAt(i), a[i], 'Position ' + i);
75 TEST_F('CvoxExpandingBrailleTranslatorUnitTest', 'TranslationError',
77 var text = new cvox.Spannable('error ok', new cvox.ValueSpan());
78 text.setSpan(new cvox.ValueSelectionSpan, 0, 0);
79 var contractedTranslator = new FakeTranslator('c');
80 // Translator that always results in an error.
81 var uncontractedTranslator = {
82 translate: function(text, callback) {
83 callback(null, null, null);
86 var translationResult = null;
88 var expandingTranslator = new cvox.ExpandingBrailleTranslator(
89 contractedTranslator, uncontractedTranslator);
90 expandingTranslator.translate(
91 text, cvox.ExpandingBrailleTranslator.ExpansionType.SELECTION,
92 function(cells, textToBraille, brailleToText) {
93 // Expect the string ' ok' to be translated using the contracted
94 // translator. The preceding part isn't included because it resulted
95 // in a translation error.
96 assertArrayBufferMatches('ccc', cells);
97 assertEqualsJSON([0, 0, 0, 0, 0, 0, 1, 2], textToBraille);
98 assertEqualsJSON([5, 6, 7], brailleToText);
102 // Test for many variations of successful translations.
104 var totalRunTranslationTests = 0;
107 * Performs the translation and checks the output.
108 * @param {string} name Name that describes the input for error messages.
109 * @param {boolean} contracted Whether to use a contracted translator
110 * in addition to the uncontracted one.
111 * @param {cvox.ExpandingBrailleTranslator.ExpansionType} valueExpansion
112 * Value expansion argument to pass to the translator.
113 * @param {string} text Input string.
114 * @param {string} expectedOutput Expected output as a string (see
115 * {@code TESTDATA} below for a description of the format).
117 function doTranslationTest(name, contracted, valueExpansion, text,
120 totalRunTranslationTests++;
121 var uncontractedTranslator = new FakeTranslator('u');
122 var expandingTranslator;
124 var contractedTranslator = new FakeTranslator('c');
125 expandingTranslator = new cvox.ExpandingBrailleTranslator(
126 contractedTranslator, uncontractedTranslator);
128 expandingTranslator = new cvox.ExpandingBrailleTranslator(
129 uncontractedTranslator);
131 var extraCellsSpan = text.getSpanInstanceOf(cvox.ExtraCellsSpan);
133 var extraCellsSpanPos = text.getSpanStart(extraCellsSpan);
134 var expectedTextToBraille = [];
135 var expectedBrailleToText = [];
136 for (var i = 0, pos = 0; i < text.getLength(); ++i, ++pos) {
137 if (i === extraCellsSpanPos)
139 expectedTextToBraille.push(pos);
140 expectedBrailleToText.push(i);
143 expectedBrailleToText.splice(extraCellsSpanPos, 0, extraCellsSpanPos);
145 expandingTranslator.translate(
146 text, valueExpansion, function(cells, textToBraille, brailleToText) {
147 assertArrayBufferMatches(expectedOutput, cells, name);
148 assertEqualsJSON(expectedTextToBraille, textToBraille, name);
149 assertEqualsJSON(expectedBrailleToText, brailleToText, name);
152 console.error('Subtest ' + name + ' failed.');
158 * Runs two tests, one with the given values and one with the given values
159 * where the text is surrounded by a typical name and role.
160 * @param {{name: string, input: string, contractedOutput: string}}
161 * testCase An entry of {@code TESTDATA}.
162 * @param {boolean} contracted Whether to use both uncontracted
163 * and contracted translators.
164 * @param {cvox.ExpandingBrailleTranslation.ExpansionType} valueExpansion
165 * What kind of value expansion to apply.
166 * @param {boolean} withExtraCells Whether to insert an extra cells span
167 * right before the selection in the input.
169 function runTranslationTestVariants(testCase, contracted, valueExpansion,
171 var expType = cvox.ExpandingBrailleTranslator.ExpansionType;
172 // Construct the full name.
173 var fullName = contracted ? 'Contracted_' : 'Uncontracted_';
174 fullName += 'Expansion' + valueExpansion + '_';
176 fullName += 'ExtraCells_';
177 fullName += testCase.name;
178 var input = testCase.input;
179 if (withExtraCells) {
180 input = input.substring(0); // Shallow copy.
181 var selectionStart = input.getSpanStart(
182 input.getSpanInstanceOf(cvox.ValueSelectionSpan));
183 var extraCellsSpan = new cvox.ExtraCellsSpan();
184 extraCellsSpan.cells = new Uint8Array(['e'.charCodeAt(0)]).buffer;
185 input.setSpan(extraCellsSpan, selectionStart, selectionStart);
187 // The expected output depends on the contraction mode and value expansion.
188 var outputChar = contracted ? 'c' : 'u';
190 if (contracted && valueExpansion === expType.SELECTION) {
191 expectedOutput = testCase.contractedOutput;
192 } else if (contracted && valueExpansion === expType.ALL) {
193 expectedOutput = new Array(testCase.input.getLength() + 1).join('u');
196 new Array(testCase.input.getLength() + 1).join(outputChar);
198 if (withExtraCells) {
199 expectedOutput = expectedOutput.substring(0, selectionStart) + 'e' +
200 expectedOutput.substring(selectionStart);
202 doTranslationTest(fullName, contracted, valueExpansion, input,
205 // Run another test, with the value surrounded by some text.
206 var surroundedText = new cvox.Spannable('Name: ');
207 var surroundedExpectedOutput =
208 new Array('Name: '.length + 1).join(outputChar);
209 surroundedText.append(input);
210 surroundedExpectedOutput += expectedOutput;
211 if (testCase.input.getLength() > 0) {
212 surroundedText.append(' ');
213 surroundedExpectedOutput += outputChar;
215 surroundedText.append('edtxt');
216 surroundedExpectedOutput +=
217 new Array('edtxt'.length + 1).join(outputChar);
218 doTranslationTest(fullName + '_Surrounded', contracted, valueExpansion,
219 surroundedText, surroundedExpectedOutput);
223 * Creates a spannable text with optional selection.
224 * @param {string} text The text.
225 * @param {=opt_selectionStart} Selection start or caret position. No
226 * selection is added if undefined.
227 * @param {=opt_selectionEnd} Selection end if selection is not a caret.
229 function createText(text, opt_selectionStart, opt_selectionEnd) {
230 var result = new cvox.Spannable(text);
232 result.setSpan(new cvox.ValueSpan, 0, text.length);
233 if (goog.isDef(opt_selectionStart)) {
235 new cvox.ValueSelectionSpan,
237 goog.isDef(opt_selectionEnd) ? opt_selectionEnd : opt_selectionStart);
243 var TEXT = 'Hello, world!';
245 TEST_F('CvoxExpandingBrailleTranslatorUnitTest', 'successfulTranslations',
248 * Dictionary of test strings, keyed on a descriptive name for the
249 * test case. The value is an array of the input string to the translation
250 * and the expected output using a translator with both uncontracted
251 * and contracted underlying translators. The expected output is
252 * in the form of a string of the same length as the input, where an 'u'
253 * means that the uncontracted translator was used at this location and a
254 * 'c' means that the contracted translator was used.
258 input: createText(''),
259 contractedOutput: '' },
260 { name: 'emptyTextWithCaret',
261 input: createText('', 0),
262 contractedOutput: '' },
263 { name: 'textWithNoSelection',
264 input: createText(TEXT),
265 contractedOutput: 'ccccccccccccc' },
266 { name: 'textWithCaretAtStart',
267 input: createText(TEXT, 0),
268 contractedOutput: 'uuuuuuccccccc' },
269 { name: 'textWithCaretAtEnd',
270 input: createText(TEXT, TEXT.length),
271 contractedOutput: 'cccccccuuuuuu' },
272 { name: 'textWithCaretInWhitespace',
273 input: createText(TEXT, 6),
274 contractedOutput: 'uuuuuuucccccc' },
275 { name: 'textWithSelectionEndInWhitespace',
276 input: createText(TEXT, 0, 7),
277 contractedOutput: 'uuuuuuucccccc' },
278 { name: 'textWithSelectionInTwoWords',
279 input: createText(TEXT, 2, 9),
280 contractedOutput: 'uuuuuucuuuuuu' }
282 var TESTDATA_WITH_SELECTION = TESTDATA.filter(function(testCase) {
283 return testCase.input.getSpanInstanceOf(cvox.ValueSelectionSpan);
286 var expType = cvox.ExpandingBrailleTranslator.ExpansionType;
287 for (var i = 0, testCase; testCase = TESTDATA[i]; ++i) {
288 runTranslationTestVariants(testCase, false, expType.SELECTION, false);
289 runTranslationTestVariants(testCase, true, expType.NONE, false);
290 runTranslationTestVariants(testCase, true, expType.SELECTION, false);
291 runTranslationTestVariants(testCase, true, expType.ALL, false);
293 for (var i = 0, testCase; testCase = TESTDATA_WITH_SELECTION[i]; ++i)
294 runTranslationTestVariants(testCase, true, expType.SELECTION, true);
296 // Make sure that the logic above runs the tests, adjust when adding more
298 var totalExpectedTranslationTests =
299 2 * (TESTDATA.length * 4 + TESTDATA_WITH_SELECTION.length);
300 assertEquals(totalExpectedTranslationTests, totalRunTranslationTests);