| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // Include test fixture. | 5 // Include test fixture. |
| 6 GEN_INCLUDE(['../testing/chromevox_unittest_base.js']); | 6 GEN_INCLUDE(['../testing/chromevox_unittest_base.js']); |
| 7 | 7 |
| 8 GEN_INCLUDE(['../testing/fake_objects.js']); | 8 GEN_INCLUDE(['../testing/fake_objects.js']); |
| 9 | 9 |
| 10 // Fake out the Chrome API namespace we depend on. | 10 // Fake out the Chrome API namespace we depend on. |
| (...skipping 20 matching lines...) Expand all Loading... |
| 31 /** @private {string} */ | 31 /** @private {string} */ |
| 32 this.text_ = ''; | 32 this.text_ = ''; |
| 33 /** @private {number} */ | 33 /** @private {number} */ |
| 34 this.selectionStart_ = 0; | 34 this.selectionStart_ = 0; |
| 35 /** @private {number} */ | 35 /** @private {number} */ |
| 36 this.selectionEnd_ = 0; | 36 this.selectionEnd_ = 0; |
| 37 /** @private {number} */ | 37 /** @private {number} */ |
| 38 this.contextID_ = 0; | 38 this.contextID_ = 0; |
| 39 /** @private {boolean} */ | 39 /** @private {boolean} */ |
| 40 this.allowDeletes_ = false; | 40 this.allowDeletes_ = false; |
| 41 /** @private {string} */ |
| 42 this.uncommittedText_ = ''; |
| 43 /** @private {?Array<number>} */ |
| 44 this.extraCells_ = []; |
| 41 port.postMessage = goog.bind(this.handleMessage_, this); | 45 port.postMessage = goog.bind(this.handleMessage_, this); |
| 42 } | 46 } |
| 43 | 47 |
| 44 | 48 |
| 45 /** | 49 /** |
| 46 * Sets the content and selection (or cursor) of the edit field. | 50 * Sets the content and selection (or cursor) of the edit field. |
| 47 * This fakes what happens when the field is edited by other means than | 51 * This fakes what happens when the field is edited by other means than |
| 48 * via the braille keyboard. | 52 * via the braille keyboard. |
| 49 * @param {string} text Text to replace the current content of the field. | 53 * @param {string} text Text to replace the current content of the field. |
| 50 * @param {number} selectionStart Start of the selection or cursor position. | 54 * @param {number} selectionStart Start of the selection or cursor position. |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 127 text, selectionStart, opt_selectionEnd) { | 131 text, selectionStart, opt_selectionEnd) { |
| 128 var selectionEnd = goog.isDef(opt_selectionEnd) ? opt_selectionEnd : | 132 var selectionEnd = goog.isDef(opt_selectionEnd) ? opt_selectionEnd : |
| 129 selectionStart; | 133 selectionStart; |
| 130 assertEquals(text, this.text_); | 134 assertEquals(text, this.text_); |
| 131 assertEquals(selectionStart, this.selectionStart_); | 135 assertEquals(selectionStart, this.selectionStart_); |
| 132 assertEquals(selectionEnd, this.selectionEnd_); | 136 assertEquals(selectionEnd, this.selectionEnd_); |
| 133 }; | 137 }; |
| 134 | 138 |
| 135 | 139 |
| 136 /** | 140 /** |
| 141 * Asserts that the uncommitted text last sent to the IME is the given text. |
| 142 * @param {string} text |
| 143 */ |
| 144 FakeEditor.prototype.assertUncommittedTextIs = function(text) { |
| 145 assertEquals(text, this.uncommittedText_); |
| 146 }; |
| 147 |
| 148 |
| 149 /** |
| 150 * Asserts that the input handler has added 'extra cells' for uncommitted |
| 151 * text into the braille content. |
| 152 * @param {string} cells Cells as a space-separated list of numbers. |
| 153 */ |
| 154 FakeEditor.prototype.assertExtraCellsAre = function(cells) { |
| 155 assertEqualsJSON(cellsToArray(cells), this.extraCells_); |
| 156 }; |
| 157 |
| 158 |
| 159 /** |
| 137 * Sends a message from the IME to the input handler. | 160 * Sends a message from the IME to the input handler. |
| 138 * @param {Object} msg The message to send. | 161 * @param {Object} msg The message to send. |
| 139 * @private | 162 * @private |
| 140 */ | 163 */ |
| 141 FakeEditor.prototype.message_ = function(msg) { | 164 FakeEditor.prototype.message_ = function(msg) { |
| 142 var listener = this.port_.onMessage.getListener(); | 165 var listener = this.port_.onMessage.getListener(); |
| 143 assertNotEquals(null, listener); | 166 assertNotEquals(null, listener); |
| 144 listener(msg); | 167 listener(msg); |
| 145 }; | 168 }; |
| 146 | 169 |
| 147 | 170 |
| 148 /** | 171 /** |
| 149 * Calls the {@code onDisplayContentChanged} method of the input handler | 172 * Calls the {@code onDisplayContentChanged} method of the input handler |
| 150 * with the current editor content and selection. | 173 * with the current editor content and selection. |
| 151 * @private | 174 * @private |
| 152 */ | 175 */ |
| 153 FakeEditor.prototype.callOnDisplayContentChanged_ = function() { | 176 FakeEditor.prototype.callOnDisplayContentChanged_ = function() { |
| 154 this.inputHandler_.onDisplayContentChanged( | 177 var content = cvox.BrailleUtil.createValue( |
| 155 cvox.BrailleUtil.createValue( | 178 this.text_, this.selectionStart_, this.selectionEnd_) |
| 156 this.text_, this.selectionStart_, this.selectionEnd_)); | 179 var grabExtraCells = function() { |
| 180 var span = content.getSpanInstanceOf(cvox.ExtraCellsSpan); |
| 181 assertNotEquals(null, span); |
| 182 // Convert the ArrayBuffer to a normal array for easier comparision. |
| 183 this.extraCells_ = Array.prototype.map.call(new Uint8Array(span.cells), |
| 184 function(a) {return a;}); |
| 185 }.bind(this); |
| 186 this.inputHandler_.onDisplayContentChanged(content, grabExtraCells); |
| 187 grabExtraCells(); |
| 157 }; | 188 }; |
| 158 | 189 |
| 159 | 190 |
| 160 /** | 191 /** |
| 161 * Informs the input handler that a new text field is focused. The content | 192 * Informs the input handler that a new text field is focused. The content |
| 162 * of the field is not cleared and should be updated separately. | 193 * of the field is not cleared and should be updated separately. |
| 163 * @param {string} fieldType The type of the field (see the documentation | 194 * @param {string} fieldType The type of the field (see the documentation |
| 164 * for the {@code chrome.input.ime} API). | 195 * for the {@code chrome.input.ime} API). |
| 165 */ | 196 */ |
| 166 FakeEditor.prototype.focus = function(fieldType) { | 197 FakeEditor.prototype.focus = function(fieldType) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 179 this.contextID_ = 0; | 210 this.contextID_ = 0; |
| 180 }; | 211 }; |
| 181 | 212 |
| 182 | 213 |
| 183 /** | 214 /** |
| 184 * Handles a message from the input handler to the IME. | 215 * Handles a message from the input handler to the IME. |
| 185 * @param {Object} msg The message. | 216 * @param {Object} msg The message. |
| 186 * @private | 217 * @private |
| 187 */ | 218 */ |
| 188 FakeEditor.prototype.handleMessage_ = function(msg) { | 219 FakeEditor.prototype.handleMessage_ = function(msg) { |
| 189 assertEquals('replaceText', msg.type); | |
| 190 assertEquals(this.contextID_, msg.contextID); | 220 assertEquals(this.contextID_, msg.contextID); |
| 191 var deleteBefore = msg.deleteBefore; | 221 switch(msg.type) { |
| 192 var newText = msg.newText; | 222 case 'replaceText': |
| 193 assertTrue(goog.isNumber(deleteBefore)); | 223 var deleteBefore = msg.deleteBefore; |
| 194 assertTrue(goog.isString(newText)); | 224 var newText = msg.newText; |
| 195 assertTrue(deleteBefore <= this.selectionStart_); | 225 assertTrue(goog.isNumber(deleteBefore)); |
| 196 if (deleteBefore > 0) { | 226 assertTrue(goog.isString(newText)); |
| 197 assertTrue(this.allowDeletes_); | 227 assertTrue(deleteBefore <= this.selectionStart_); |
| 198 this.text_ = | 228 if (deleteBefore > 0) { |
| 199 this.text_.substring(0, this.selectionStart_ - deleteBefore) + | 229 assertTrue(this.allowDeletes_); |
| 200 this.text_.substring(this.selectionEnd_); | 230 this.text_ = |
| 201 this.selectionStart_ -= deleteBefore; | 231 this.text_.substring(0, this.selectionStart_ - deleteBefore) + |
| 202 this.selectionEnd_ = this.selectionStart_; | 232 this.text_.substring(this.selectionEnd_); |
| 203 this.callOnDisplayContentChanged_(); | 233 this.selectionStart_ -= deleteBefore; |
| 234 this.selectionEnd_ = this.selectionStart_; |
| 235 this.callOnDisplayContentChanged_(); |
| 236 } |
| 237 this.insert(newText); |
| 238 break; |
| 239 case 'setUncommitted': |
| 240 assertTrue(goog.isString(msg.text)); |
| 241 this.uncommittedText_ = msg.text; |
| 242 break; |
| 243 case 'commitUncommitted': |
| 244 this.insert(this.uncommittedText_); |
| 245 this.uncommittedText_ = ''; |
| 246 break; |
| 247 default: |
| 248 throw new Error('Unexpected message to IME: ' + JSON.stringify(msg)); |
| 204 } | 249 } |
| 205 this.insert(newText); | |
| 206 }; | 250 }; |
| 207 | 251 |
| 208 /* | 252 /* |
| 209 * Fakes a {@code Port} used for message passing in the Chrome extension APIs. | 253 * Fakes a {@code Port} used for message passing in the Chrome extension APIs. |
| 210 * @constructor | 254 * @constructor |
| 211 */ | 255 */ |
| 212 function FakePort() { | 256 function FakePort() { |
| 213 /** @type {FakeChromeEvent} */ | 257 /** @type {FakeChromeEvent} */ |
| 214 this.onDisconnect = new FakeChromeEvent(); | 258 this.onDisconnect = new FakeChromeEvent(); |
| 215 /** @type {FakeChromeEvent} */ | 259 /** @type {FakeChromeEvent} */ |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 355 /** | 399 /** |
| 356 * Converts a list of cells, represented as a string, to an array. | 400 * Converts a list of cells, represented as a string, to an array. |
| 357 * @param {string} cells A string with space separated groups of digits. | 401 * @param {string} cells A string with space separated groups of digits. |
| 358 * Each group corresponds to one braille cell and each digit in a group | 402 * Each group corresponds to one braille cell and each digit in a group |
| 359 * corresponds to a particular dot in the cell (1 to 8). As a special | 403 * corresponds to a particular dot in the cell (1 to 8). As a special |
| 360 * case, the digit 0 by itself represents a blank cell. | 404 * case, the digit 0 by itself represents a blank cell. |
| 361 * @return {Array.<number>} An array with each cell encoded as a bit | 405 * @return {Array.<number>} An array with each cell encoded as a bit |
| 362 * pattern (dot 1 uses bit 0, etc). | 406 * pattern (dot 1 uses bit 0, etc). |
| 363 */ | 407 */ |
| 364 function cellsToArray(cells) { | 408 function cellsToArray(cells) { |
| 409 if (!cells) |
| 410 return []; |
| 365 return cells.split(/\s+/).map(function(cellString) { | 411 return cells.split(/\s+/).map(function(cellString) { |
| 366 var cell = 0; | 412 var cell = 0; |
| 367 assertTrue(cellString.length > 0); | 413 assertTrue(cellString.length > 0); |
| 368 if (cellString != '0') { | 414 if (cellString != '0') { |
| 369 for (var i = 0; i < cellString.length; ++i) { | 415 for (var i = 0; i < cellString.length; ++i) { |
| 370 var dot = cellString.charCodeAt(i) - '0'.charCodeAt(0); | 416 var dot = cellString.charCodeAt(i) - '0'.charCodeAt(0); |
| 371 assertTrue(dot >= 1); | 417 assertTrue(dot >= 1); |
| 372 assertTrue(dot <= 8); | 418 assertTrue(dot <= 8); |
| 373 cell |= 1 << (dot - 1); | 419 cell |= 1 << (dot - 1); |
| 374 } | 420 } |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 525 | 571 |
| 526 editor.blur(); | 572 editor.blur(); |
| 527 editor.setActive(false); | 573 editor.setActive(false); |
| 528 }); | 574 }); |
| 529 | 575 |
| 530 | 576 |
| 531 TEST_F('CvoxBrailleInputHandlerUnitTest', 'InputContracted', function() { | 577 TEST_F('CvoxBrailleInputHandlerUnitTest', 'InputContracted', function() { |
| 532 var editor = this.createEditor(); | 578 var editor = this.createEditor(); |
| 533 this.translatorManager.setTranslators(this.contractedTranslator, | 579 this.translatorManager.setTranslators(this.contractedTranslator, |
| 534 this.uncontractedTranslator); | 580 this.uncontractedTranslator); |
| 581 editor.setContent('', 0); |
| 535 editor.setActive(true); | 582 editor.setActive(true); |
| 536 editor.focus('text'); | 583 editor.focus('text'); |
| 537 this.assertExpandingSelection(); | 584 this.assertExpandingSelection(); |
| 538 | 585 |
| 539 // First, type a 'b'. | 586 // First, type a 'b'. |
| 540 assertTrue(this.sendCells('12')); | 587 assertTrue(this.sendCells('12')); |
| 588 editor.assertContentIs('', 0); |
| 541 // Remember that the contracted translator produces uppercase. | 589 // Remember that the contracted translator produces uppercase. |
| 542 editor.assertContentIs('BUT', 'BUT'.length); | 590 editor.assertUncommittedTextIs('BUT'); |
| 591 editor.assertExtraCellsAre('12'); |
| 543 this.assertExpandingNone(); | 592 this.assertExpandingNone(); |
| 544 | 593 |
| 545 // From here on, the input handler needs to replace already entered text. | |
| 546 editor.setAllowDeletes(true); | |
| 547 // Typing 'rl' changes to a different contraction. | 594 // Typing 'rl' changes to a different contraction. |
| 548 assertTrue(this.sendCells('1235 123')); | 595 assertTrue(this.sendCells('1235 123')); |
| 549 editor.assertContentIs('BRAILLE', 'BRAILLE'.length); | 596 editor.assertUncommittedTextIs('BRAILLE'); |
| 597 editor.assertContentIs('', 0); |
| 598 editor.assertExtraCellsAre('12 1235 123'); |
| 599 this.assertExpandingNone(); |
| 600 |
| 550 // Now, finish the word. | 601 // Now, finish the word. |
| 551 assertTrue(this.sendCells('0')); | 602 assertTrue(this.sendCells('0')); |
| 552 editor.assertContentIs('BRAILLE ', 'BRAILLE '.length); | 603 editor.assertContentIs('BRAILLE ', 'BRAILLE '.length); |
| 553 this.assertExpandingNone(); | 604 editor.assertUncommittedTextIs(''); |
| 605 editor.assertExtraCellsAre(''); |
| 606 this.assertExpandingSelection(); |
| 554 | 607 |
| 555 // Move the cursor to the beginning. | 608 // Move the cursor to the beginning. |
| 556 editor.select(0); | 609 editor.select(0); |
| 557 this.assertExpandingSelection(); | 610 this.assertExpandingSelection(); |
| 558 | 611 |
| 559 // Typing now uses the uncontracted table. | 612 // Typing now uses the uncontracted table. |
| 560 assertTrue(this.sendCells('12')); // 'b' | 613 assertTrue(this.sendCells('12')); // 'b' |
| 561 editor.assertContentIs('bBRAILLE ', 1); | 614 editor.assertContentIs('bBRAILLE ', 1); |
| 562 this.assertExpandingSelection(); | 615 this.assertExpandingSelection(); |
| 563 editor.select('bBRAILLE'.length); | 616 editor.select('bBRAILLE'.length); |
| 564 this.assertExpandingSelection(); | 617 this.assertExpandingSelection(); |
| 565 assertTrue(this.sendCells('12')); // 'b' | 618 assertTrue(this.sendCells('12')); // 'b' |
| 566 editor.assertContentIs('bBRAILLEb ', 'bBRAILLEb'.length); | 619 editor.assertContentIs('bBRAILLEb ', 'bBRAILLEb'.length); |
| 567 // Move to the end, where contracted typing should work. | 620 // Move to the end, where contracted typing should work. |
| 568 editor.select('bBRAILLEb '.length); | 621 editor.select('bBRAILLEb '.length); |
| 569 assertTrue(this.sendCells('1456 0')); // Symbol for 'this', then space. | 622 assertTrue(this.sendCells('1456 0')); // Symbol for 'this', then space. |
| 570 this.assertExpandingNone(); | 623 this.assertExpandingSelection(); |
| 571 editor.assertContentIs('bBRAILLEb THIS ', 'bBRAILLEb this '.length); | 624 editor.assertContentIs('bBRAILLEb THIS ', 'bBRAILLEb THIS '.length); |
| 572 | 625 |
| 573 // Move between the two words. | 626 // Move to between the two words. |
| 574 editor.select('bBRAILLEb'.length); | 627 editor.select('bBRAILLEb'.length); |
| 575 this.assertExpandingSelection(); | 628 this.assertExpandingSelection(); |
| 576 assertTrue(this.sendCells('0')); | 629 assertTrue(this.sendCells('0 12')); // Space plus 'b' for 'but' |
| 577 assertTrue(this.sendCells('12')); // 'b' for 'but' | 630 editor.assertUncommittedTextIs('BUT'); |
| 578 editor.assertContentIs('bBRAILLEb BUT THIS ', 'bBRAILLEb BUT'.length); | 631 editor.assertExtraCellsAre('12'); |
| 632 editor.assertContentIs('bBRAILLEb THIS ', 'bBRAILLEb '.length); |
| 579 this.assertExpandingNone(); | 633 this.assertExpandingNone(); |
| 580 }); | 634 }); |
| 581 | 635 |
| 582 | 636 |
| 583 TEST_F('CvoxBrailleInputHandlerUnitTest', 'TypingUrlWithContracted', | 637 TEST_F('CvoxBrailleInputHandlerUnitTest', 'TypingUrlWithContracted', |
| 584 function() { | 638 function() { |
| 585 var editor = this.createEditor(); | 639 var editor = this.createEditor(); |
| 586 this.translatorManager.setTranslators(this.contractedTranslator, | 640 this.translatorManager.setTranslators(this.contractedTranslator, |
| 587 this.uncontractedTranslator); | 641 this.uncontractedTranslator); |
| 588 editor.setActive(true); | 642 editor.setActive(true); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 607 TEST_F('CvoxBrailleInputHandlerUnitTest', 'Backspace', function() { | 661 TEST_F('CvoxBrailleInputHandlerUnitTest', 'Backspace', function() { |
| 608 var editor = this.createEditor(); | 662 var editor = this.createEditor(); |
| 609 this.translatorManager.setTranslators(this.contractedTranslator, | 663 this.translatorManager.setTranslators(this.contractedTranslator, |
| 610 this.uncontractedTranslator); | 664 this.uncontractedTranslator); |
| 611 editor.setActive(true); | 665 editor.setActive(true); |
| 612 editor.focus('text'); | 666 editor.focus('text'); |
| 613 | 667 |
| 614 // Add some text that we can delete later. | 668 // Add some text that we can delete later. |
| 615 editor.setContent('Text ', 'Text '.length); | 669 editor.setContent('Text ', 'Text '.length); |
| 616 | 670 |
| 617 // The IME needs to delete text, even when typing. | |
| 618 editor.setAllowDeletes(true); | |
| 619 // Type 'brl' to make sure replacement works when deleting text. | 671 // Type 'brl' to make sure replacement works when deleting text. |
| 620 assertTrue(this.sendCells('12 1235 123')); | 672 assertTrue(this.sendCells('12 1235 123')); |
| 621 editor.assertContentIs('Text BRAILLE', 'Text BRAILLE'.length); | 673 editor.assertUncommittedTextIs('BRAILLE'); |
| 622 | 674 |
| 623 // Delete what we just typed, one cell at a time. | 675 // Delete what we just typed, one cell at a time. |
| 624 this.sendKeyEvent('Backspace'); | 676 this.sendKeyEvent('Backspace'); |
| 625 editor.assertContentIs('Text BR', 'Text BR'.length); | 677 editor.assertUncommittedTextIs('BR'); |
| 626 this.sendKeyEvent('Backspace'); | 678 this.sendKeyEvent('Backspace'); |
| 627 editor.assertContentIs('Text BUT', 'Text BUT'.length); | 679 editor.assertUncommittedTextIs('BUT'); |
| 628 this.sendKeyEvent('Backspace'); | 680 this.sendKeyEvent('Backspace'); |
| 629 editor.assertContentIs('Text ', 'Text '.length); | 681 editor.assertUncommittedTextIs(''); |
| 630 | 682 |
| 631 // Now, backspace should be handled as usual, synthetizing key events. | 683 // Now, backspace should be handled as usual, synthetizing key events. |
| 632 assertEquals(0, this.keyEvents.length); | 684 assertEquals(0, this.keyEvents.length); |
| 633 this.sendKeyEvent('Backspace'); | 685 this.sendKeyEvent('Backspace'); |
| 634 assertEqualsJSON([{keyCode: 8, keyName: 'Backspace', charValue: 8}], | 686 assertEqualsJSON([{keyCode: 8, keyName: 'Backspace', charValue: 8}], |
| 635 this.keyEvents); | 687 this.keyEvents); |
| 636 }); | 688 }); |
| 637 | 689 |
| 638 | 690 |
| 639 TEST_F('CvoxBrailleInputHandlerUnitTest', 'KeysImeNotActive', function() { | 691 TEST_F('CvoxBrailleInputHandlerUnitTest', 'KeysImeNotActive', function() { |
| 640 var editor = this.createEditor(); | 692 var editor = this.createEditor(); |
| 641 this.sendKeyEvent('Enter'); | 693 this.sendKeyEvent('Enter'); |
| 642 this.sendKeyEvent('ArrowUp'); | 694 this.sendKeyEvent('ArrowUp'); |
| 643 assertEqualsJSON([{keyCode: 13, keyName: 'Enter', charValue: 0x0A}, | 695 assertEqualsJSON([{keyCode: 13, keyName: 'Enter', charValue: 0x0A}, |
| 644 {keyCode: 38, keyName: 'ArrowUp', charValue: 0x41}], | 696 {keyCode: 38, keyName: 'ArrowUp', charValue: 0x41}], |
| 645 this.keyEvents); | 697 this.keyEvents); |
| 646 }); | 698 }); |
| OLD | NEW |