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 |