Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 ////////////////////////////////////////////////////////////////////////////////
2 // Public
4 const BOUNDARY_CHAR = nsIAccessibleText.BOUNDARY_CHAR;
5 const BOUNDARY_WORD_START = nsIAccessibleText.BOUNDARY_WORD_START;
6 const BOUNDARY_WORD_END = nsIAccessibleText.BOUNDARY_WORD_END;
7 const BOUNDARY_LINE_START = nsIAccessibleText.BOUNDARY_LINE_START;
8 const BOUNDARY_LINE_END = nsIAccessibleText.BOUNDARY_LINE_END;
10 const kTextEndOffset = nsIAccessibleText.TEXT_OFFSET_END_OF_TEXT;
11 const kCaretOffset = nsIAccessibleText.TEXT_OFFSET_CARET;
13 const kTodo = 1; // a test is expected to fail
14 const kOk = 2; // a test doesn't fail
16 /**
17 * Test characterCount for the given array of accessibles.
18 *
19 * @param aCount [in] the expected character count
20 * @param aIDs [in] array of accessible identifiers to test
21 * @param aTodoFlag [in, optional] either kOk or kTodo
22 */
23 function testCharacterCount(aIDs, aCount, aTodoFlag)
24 {
25 var ids = (aIDs instanceof Array) ? aIDs : [ aIDs ];
26 var isFunc = (aTodoFlag == kTodo) ? todo_is : is;
27 for (var i = 0; i < ids.length; i++) {
28 var textacc = getAccessible(ids[i], [nsIAccessibleText]);
29 isFunc(textacc.characterCount, aCount,
30 "Wrong character count for " + prettyName(ids[i]));
31 }
32 }
34 /**
35 * Test text between two given offsets.
36 *
37 * @param aIDs [in] an array of accessible IDs to test
38 * @param aStartOffset [in] the start offset within the text to test
39 * @param aEndOffset [in] the end offset up to which the text is tested
40 * @param aText [in] the expected result from the test
41 * @param aTodoFlag [in, optional] either kOk or kTodo
42 */
43 function testText(aIDs, aStartOffset, aEndOffset, aText, aTodoFlag)
44 {
45 var ids = (aIDs instanceof Array) ? aIDs : [ aIDs ];
46 var isFunc = (aTodoFlag == kTodo) ? todo_is : is;
47 for (var i = 0; i < ids.length; i++) {
48 var acc = getAccessible(ids[i], nsIAccessibleText);
49 try {
50 isFunc(acc.getText(aStartOffset, aEndOffset), aText,
51 "getText: wrong text between start and end offsets '" +
52 aStartOffset + "', '" + aEndOffset + " for '" +
53 prettyName(ids[i]) + "'");
54 } catch (e) {
55 ok(false,
56 "getText fails between start and end offsets '" + aStartOffset +
57 "', '" + aEndOffset + " for '" + prettyName(ids[i]) + "'");
58 }
59 }
60 }
62 /**
63 * Test password text between two given offsets
64 *
65 * @param aIDs [in] an array of accessible IDs to test
66 * @param aStartOffset [in] the start offset within the text to test
67 * @param aEndOffset [in] the end offset up to which the text is tested
68 * @param aText [in] the expected result from the test
69 *
70 * @note All this function does is test that getText doe snot expose the
71 * password text itself, but something else.
72 */
73 function testPasswordText(aIDs, aStartOffset, aEndOffset, aText)
74 {
75 for (var i = 0; i < aIDs.length; i++)
76 {
77 var acc = getAccessible(aIDs[i], nsIAccessibleText);
78 try {
79 isnot(acc.getText(aStartOffset, aEndOffset), aText,
80 "getText: plain text between start and end offsets '" + aStartOffset +
81 "', '" + aEndOffset + " for '" + prettyName(aIDs[i]) + "'");
82 } catch (e) {
83 ok(false,
84 "getText fails between start and end offsets '" + aStartOffset +
85 "', '" + aEndOffset + " for '" + prettyName(aIDs[i]) + "'");
86 }
87 }
88 }
90 /**
91 * Test getTextAtOffset for BOUNDARY_CHAR over different elements.
92 *
93 * @param aIDs [in] the accessible identifier or array of accessible
94 * identifiers
95 * @param aOffset [in] the offset to get a character at it
96 * @param aChar [in] the expected character
97 * @param aStartOffset [in] expected start offset of the character
98 * @param aEndOffset [in] expected end offset of the character
99 */
100 function testCharAtOffset(aIDs, aOffset, aChar, aStartOffset, aEndOffset)
101 {
102 var IDs = (aIDs instanceof Array) ? aIDs : [ aIDs ];
103 for (var i = 0; i < IDs.length; i++) {
104 var acc = getAccessible(IDs[i], nsIAccessibleText);
105 testTextHelper(IDs[i], aOffset, BOUNDARY_CHAR,
106 aChar, aStartOffset, aEndOffset,
107 kOk, kOk, kOk,
108 acc.getTextAtOffset, "getTextAtOffset ");
109 }
110 }
112 /**
113 * Test getTextAtOffset function over different elements.
114 *
115 * @param aIDs [in] ID or array of IDs
116 * @param aBoundaryType [in] boundary type for text to be retrieved
117 * @param aTestList [in] array of sets:
118 * offset1 and offset2 defining the offset range
119 * the text in the range
120 * start offset of the text in the range
121 * end offset of the text in the range
122 *
123 * or
124 *
125 * @param aOffset [in] the offset to get the text at
126 * @param aBoundaryType [in] Boundary type for text to be retrieved
127 * @param aText [in] expected return text for getTextAtOffset
128 * @param aStartOffset [in] expected return start offset for getTextAtOffset
129 * @param aEndOffset [in] expected return end offset for getTextAtOffset
130 * @param ... [in] list of ids or list of tuples made of:
131 * element identifier
132 * kTodo or kOk for returned text
133 * kTodo or kOk for returned start offset
134 * kTodo or kOk for returned offset result
135 */
136 function testTextAtOffset()
137 {
138 testTextSuperHelper("getTextAtOffset", arguments);
139 }
141 /**
142 * Test getTextAfterOffset for BOUNDARY_CHAR over different elements.
143 *
144 * @param aIDs [in] the accessible identifier or array of accessible
145 * identifiers
146 * @param aOffset [in] the offset to get a character after it
147 * @param aChar [in] the expected character
148 * @param aStartOffset [in] expected start offset of the character
149 * @param aEndOffset [in] expected end offset of the character
150 */
151 function testCharAfterOffset(aIDs, aOffset, aChar, aStartOffset, aEndOffset)
152 {
153 var IDs = (aIDs instanceof Array) ? aIDs : [ aIDs ];
154 for (var i = 0; i < IDs.length; i++) {
155 var acc = getAccessible(IDs[i], nsIAccessibleText);
156 testTextHelper(IDs[i], aOffset, BOUNDARY_CHAR,
157 aChar, aStartOffset, aEndOffset,
158 kOk, kOk, kOk,
159 acc.getTextAfterOffset, "getTextAfterOffset ");
160 }
161 }
163 /**
164 * Test getTextAfterOffset function over different elements
165 *
166 * @param aIDs [in] ID or array of IDs
167 * @param aBoundaryType [in] boundary type for text to be retrieved
168 * @param aTestList [in] array of sets:
169 * offset1 and offset2 defining the offset range
170 * the text in the range
171 * start offset of the text in the range
172 * end offset of the text in the range
173 *
174 * or
175 *
176 * @param aOffset [in] the offset to get the text after
177 * @param aBoundaryType [in] Boundary type for text to be retrieved
178 * @param aText [in] expected return text for getTextAfterOffset
179 * @param aStartOffset [in] expected return start offset for getTextAfterOffset
180 * @param aEndOffset [in] expected return end offset for getTextAfterOffset
181 * @param ... [in] list of ids or list of tuples made of:
182 * element identifier
183 * kTodo or kOk for returned text
184 * kTodo or kOk for returned start offset
185 * kTodo or kOk for returned offset result
186 */
187 function testTextAfterOffset(aOffset, aBoundaryType,
188 aText, aStartOffset, aEndOffset)
189 {
190 testTextSuperHelper("getTextAfterOffset", arguments);
191 }
193 /**
194 * Test getTextBeforeOffset for BOUNDARY_CHAR over different elements.
195 *
196 * @param aIDs [in] the accessible identifier or array of accessible
197 * identifiers
198 * @param aOffset [in] the offset to get a character before it
199 * @param aChar [in] the expected character
200 * @param aStartOffset [in] expected start offset of the character
201 * @param aEndOffset [in] expected end offset of the character
202 */
203 function testCharBeforeOffset(aIDs, aOffset, aChar, aStartOffset, aEndOffset)
204 {
205 var IDs = (aIDs instanceof Array) ? aIDs : [ aIDs ];
206 for (var i = 0; i < IDs.length; i++) {
207 var acc = getAccessible(IDs[i], nsIAccessibleText);
208 testTextHelper(IDs[i], aOffset, BOUNDARY_CHAR,
209 aChar, aStartOffset, aEndOffset,
210 kOk, kOk, kOk,
211 acc.getTextBeforeOffset, "getTextBeforeOffset ");
212 }
213 }
215 /**
216 * Test getTextBeforeOffset function over different elements
217 *
218 * @param aIDs [in] ID or array of IDs
219 * @param aBoundaryType [in] boundary type for text to be retrieved
220 * @param aTestList [in] array of sets:
221 * offset1 and offset2 defining the offset range
222 * the text in the range
223 * start offset of the text in the range
224 * end offset of the text in the range
225 *
226 * or
227 *
228 * @param aOffset [in] the offset to get the text before
229 * @param aBoundaryType [in] Boundary type for text to be retrieved
230 * @param aText [in] expected return text for getTextBeforeOffset
231 * @param aStartOffset [in] expected return start offset for getTextBeforeOffset
232 * @param aEndOffset [in] expected return end offset for getTextBeforeOffset
233 * @param ... [in] list of ids or list of tuples made of:
234 * element identifier
235 * kTodo or kOk for returned text
236 * kTodo or kOk for returned start offset
237 * kTodo or kOk for returned offset result
238 */
239 function testTextBeforeOffset(aOffset, aBoundaryType,
240 aText, aStartOffset, aEndOffset)
241 {
242 testTextSuperHelper("getTextBeforeOffset", arguments);
243 }
245 /**
246 * Test word count for an element.
247 *
248 * @param aElement [in] element identifier
249 * @param aCount [in] Expected word count
250 * @param aToDoFlag [in] kTodo or kOk for returned text
251 */
252 function testWordCount(aElement, aCount, aToDoFlag)
253 {
254 var isFunc = (aToDoFlag == kTodo) ? todo_is : is;
255 var acc = getAccessible(aElement, nsIAccessibleText);
256 var startOffsetObj = {}, endOffsetObj = {};
257 var length = acc.characterCount;
258 var offset = 0;
259 var wordCount = 0;
260 while (true) {
261 var text = acc.getTextAtOffset(offset, BOUNDARY_WORD_START,
262 startOffsetObj, endOffsetObj);
263 if (offset >= length)
264 break;
266 wordCount++;
267 offset = endOffsetObj.value;
268 }
269 isFunc(wordCount, aCount,
270 "wrong words count for '" + acc.getText(0, -1) + "': " + wordCount +
271 " in " + prettyName(aElement));
272 }
274 /**
275 * Test word at a position for an element.
276 *
277 * @param aElement [in] element identifier
278 * @param aWordIndex [in] index of the word to test
279 * @param aText [in] expected text for that word
280 * @param aToDoFlag [in] kTodo or kOk for returned text
281 */
282 function testWordAt(aElement, aWordIndex, aText, aToDoFlag)
283 {
284 var isFunc = (aToDoFlag == kTodo) ? todo_is : is;
285 var acc = getAccessible(aElement, nsIAccessibleText);
287 var textLength = acc.characterCount;
288 var wordIdx = aWordIndex;
289 var startOffsetObj = { value: 0 }, endOffsetObj = { value: 0 };
290 for (offset = 0; offset < textLength; offset = endOffsetObj.value) {
291 acc.getTextAtOffset(offset, BOUNDARY_WORD_START,
292 startOffsetObj, endOffsetObj);
294 wordIdx--;
295 if (wordIdx < 0)
296 break;
297 }
299 if (wordIdx >= 0) {
300 ok(false,
301 "the given word index '" + aWordIndex + "' exceeds words amount in " +
302 prettyName(aElement));
304 return;
305 }
307 var startWordOffset = startOffsetObj.value;
308 var endWordOffset = endOffsetObj.value;
310 // Calculate the end word offset.
311 acc.getTextAtOffset(endOffsetObj.value, BOUNDARY_WORD_END,
312 startOffsetObj, endOffsetObj);
313 if (startOffsetObj.value != textLength)
314 endWordOffset = startOffsetObj.value
316 if (endWordOffset <= startWordOffset) {
317 todo(false,
318 "wrong start and end offset for word at index '" + aWordIndex + "': " +
319 " of text '" + acc.getText(0, -1) + "' in " + prettyName(aElement));
321 return;
322 }
324 text = acc.getText(startWordOffset, endWordOffset);
325 isFunc(text, aText, "wrong text for word at index '" + aWordIndex + "': " +
326 " of text '" + acc.getText(0, -1) + "' in " + prettyName(aElement));
327 }
329 /**
330 * Test words in a element.
331 *
332 * @param aElement [in] element identifier
333 * @param aWords [in] array of expected words
334 * @param aToDoFlag [in, optional] kTodo or kOk for returned text
335 */
336 function testWords(aElement, aWords, aToDoFlag)
337 {
338 if (aToDoFlag == null)
339 aToDoFlag = kOk;
341 testWordCount(aElement, aWords.length, aToDoFlag);
343 for (var i = 0; i < aWords.length; i++) {
344 testWordAt(aElement, i, aWords[i], aToDoFlag);
345 }
346 }
348 /**
349 * Remove all selections.
350 *
351 * @param aID [in] Id, DOM node, or acc obj
352 */
353 function cleanTextSelections(aID)
354 {
355 var acc = getAccessible(aID, [nsIAccessibleText]);
357 while (acc.selectionCount > 0)
358 acc.removeSelection(0);
359 }
361 /**
362 * Test addSelection method.
363 *
364 * @param aID [in] Id, DOM node, or acc obj
365 * @param aStartOffset [in] start offset for the new selection
366 * @param aEndOffset [in] end offset for the new selection
367 * @param aSelectionsCount [in] expected number of selections after addSelection
368 */
369 function testTextAddSelection(aID, aStartOffset, aEndOffset, aSelectionsCount)
370 {
371 var acc = getAccessible(aID, [nsIAccessibleText]);
372 var text = acc.getText(0, -1);
374 acc.addSelection(aStartOffset, aEndOffset);
376 ok(acc.selectionCount, aSelectionsCount,
377 text + ": failed to add selection from offset '" + aStartOffset +
378 "' to offset '" + aEndOffset + "': selectionCount after");
379 }
381 /**
382 * Test removeSelection method.
383 *
384 * @param aID [in] Id, DOM node, or acc obj
385 * @param aSelectionIndex [in] index of the selection to be removed
386 * @param aSelectionsCount [in] expected number of selections after
387 * removeSelection
388 */
389 function testTextRemoveSelection(aID, aSelectionIndex, aSelectionsCount)
390 {
391 var acc = getAccessible(aID, [nsIAccessibleText]);
392 var text = acc.getText(0, -1);
394 acc.removeSelection(aSelectionIndex);
396 ok(acc.selectionCount, aSelectionsCount,
397 text + ": failed to remove selection at index '" +
398 aSelectionIndex + "': selectionCount after");
399 }
401 /**
402 * Test setSelectionBounds method.
403 *
404 * @param aID [in] Id, DOM node, or acc obj
405 * @param aStartOffset [in] new start offset for the selection
406 * @param aEndOffset [in] new end offset for the selection
407 * @param aSelectionIndex [in] index of the selection to set
408 * @param aSelectionsCount [in] expected number of selections after
409 * setSelectionBounds
410 */
411 function testTextSetSelection(aID, aStartOffset, aEndOffset,
412 aSelectionIndex, aSelectionsCount)
413 {
414 var acc = getAccessible(aID, [nsIAccessibleText]);
415 var text = acc.getText(0, -1);
417 acc.setSelectionBounds(aSelectionIndex, aStartOffset, aEndOffset);
419 is(acc.selectionCount, aSelectionsCount,
420 text + ": failed to set selection at index '" +
421 aSelectionIndex + "': selectionCount after");
422 }
424 /**
425 * Test selectionCount method.
426 *
427 * @param aID [in] Id, DOM node, or acc obj
428 * @param aCount [in] expected selection count
429 */
430 function testTextSelectionCount(aID, aCount)
431 {
432 var acc = getAccessible(aID, [nsIAccessibleText]);
433 var text = acc.getText(0, -1);
435 is(acc.selectionCount, aCount, text + ": wrong selectionCount: ");
436 }
438 /**
439 * Test getSelectionBounds method.
440 *
441 * @param aID [in] Id, DOM node, or acc obj
442 * @param aStartOffset [in] expected start offset for the selection
443 * @param aEndOffset [in] expected end offset for the selection
444 * @param aSelectionIndex [in] index of the selection to get
445 */
446 function testTextGetSelection(aID, aStartOffset, aEndOffset, aSelectionIndex)
447 {
448 var acc = getAccessible(aID, [nsIAccessibleText]);
449 var text = acc.getText(0, -1);
451 var startObj = {}, endObj = {};
452 acc.getSelectionBounds(aSelectionIndex, startObj, endObj);
454 is(startObj.value, aStartOffset, text + ": wrong start offset for index '" +
455 aSelectionIndex + "'");
456 is(endObj.value, aEndOffset, text + ": wrong end offset for index '" +
457 aSelectionIndex + "'");
458 }
460 function testTextRange(aRange, aStartContainer, aStartOffset,
461 aEndContainer, aEndOffset)
462 {
463 is(aRange.startContainer, getAccessible(aStartContainer),
464 "Wrong start container");
465 is(aRange.startOffset, aStartOffset,
466 "Wrong start offset");
467 is(aRange.endContainer, getAccessible(aEndContainer),
468 "Wrong end container");
469 is(aRange.endOffset, aEndOffset,
470 "Wrong end offset");
471 }
473 ////////////////////////////////////////////////////////////////////////////////
474 // Private
476 function testTextSuperHelper(aFuncName, aArgs)
477 {
478 // List of tests.
479 if (aArgs[2] instanceof Array) {
480 var ids = (aArgs[0] instanceof Array) ? aArgs[0] : [ aArgs[0] ];
481 var boundaryType = aArgs[1];
482 var list = aArgs[2];
483 for (var i = 0; i < list.length; i++) {
484 var offset1 = list[i][0], offset2 = list[i][1];
485 var text = list[i][2], startOffset = list[i][3], endOffset = list[i][4];
486 var failureList = list[i][5];
487 for (var offset = offset1; offset <= offset2; offset++) {
488 for (var idIdx = 0; idIdx < ids.length; idIdx++) {
489 var id = ids[idIdx];
491 var flagOk1 = kOk, flagOk2 = kOk, flagOk3 = kOk;
492 if (failureList) {
493 for (var fIdx = 0; fIdx < failureList.length; fIdx++) {
494 if (offset == failureList[fIdx][0] && id == failureList[fIdx][1]) {
495 flagOk1 = failureList[fIdx][2];
496 flagOk2 = failureList[fIdx][3];
497 flagOk3 = failureList[fIdx][4];
498 break;
499 }
500 }
501 }
503 var acc = getAccessible(id, nsIAccessibleText);
504 testTextHelper(id, offset, boundaryType,
505 text, startOffset, endOffset,
506 flagOk1, flagOk2, flagOk3,
507 acc[aFuncName], aFuncName + " ");
508 }
509 }
510 }
511 return;
512 }
514 // Test at single offset. List of IDs.
515 var offset = aArgs[0];
516 var boundaryType = aArgs[1];
517 var text = aArgs[2];
518 var startOffset = aArgs[3];
519 var endOffset = aArgs[4];
520 if (aArgs[5] instanceof Array) {
521 var ids = aArgs[5];
522 for (var i = 0; i < ids.length; i++) {
523 var acc = getAccessible(ids[i], nsIAccessibleText);
524 testTextHelper(ids[i], offset, boundaryType,
525 text, startOffset, endOffset,
526 kOk, kOk, kOk,
527 acc[aFuncName], aFuncName + " ");
528 }
530 return;
531 }
533 // Each ID is tested separately.
534 for (var i = 5; i < aArgs.length; i = i + 4) {
535 var ID = aArgs[i];
536 var acc = getAccessible(ID, nsIAccessibleText);
537 var toDoFlag1 = aArgs[i + 1];
538 var toDoFlag2 = aArgs[i + 2];
539 var toDoFlag3 = aArgs[i + 3];
541 testTextHelper(ID, offset, boundaryType,
542 text, startOffset, endOffset,
543 toDoFlag1, toDoFlag2, toDoFlag3,
544 acc[aFuncName], aFuncName + " ");
545 }
546 }
548 function testTextHelper(aID, aOffset, aBoundaryType,
549 aText, aStartOffset, aEndOffset,
550 aToDoFlag1, aToDoFlag2, aToDoFlag3,
551 aTextFunc, aTextFuncName)
552 {
553 var exceptionFlag = aToDoFlag1 == undefined ||
554 aToDoFlag2 == undefined ||
555 aToDoFlag3 == undefined;
557 var startMsg = aTextFuncName + "(" + boundaryToString(aBoundaryType) + "): ";
558 var endMsg = ", id: " + prettyName(aID) + ";";
560 try {
561 var startOffsetObj = {}, endOffsetObj = {};
562 var text = aTextFunc(aOffset, aBoundaryType,
563 startOffsetObj, endOffsetObj);
565 if (exceptionFlag) {
566 ok(false, startMsg + "no expected failure at offset " + aOffset + endMsg);
567 return;
568 }
570 var isFunc1 = (aToDoFlag1 == kTodo) ? todo : ok;
571 var isFunc2 = (aToDoFlag2 == kTodo) ? todo : ok;
572 var isFunc3 = (aToDoFlag3 == kTodo) ? todo : ok;
574 isFunc1(text == aText,
575 startMsg + "wrong text " +
576 "(got '" + text + "', expected: '" + aText + "')" +
577 ", offset: " + aOffset + endMsg);
578 isFunc2(startOffsetObj.value == aStartOffset,
579 startMsg + "wrong start offset" +
580 "(got '" + startOffsetObj.value + "', expected: '" + aStartOffset + "')" +
581 ", offset: " + aOffset + endMsg);
582 isFunc3(endOffsetObj.value == aEndOffset,
583 startMsg + "wrong end offset" +
584 "(got '" + endOffsetObj.value + "', expected: '" + aEndOffset + "')" +
585 ", offset: " + aOffset + endMsg);
587 } catch (e) {
588 var okFunc = exceptionFlag ? todo : ok;
589 okFunc(false, startMsg + "failed at offset " + aOffset + endMsg +
590 ", exception: " + e);
591 }
592 }
594 function boundaryToString(aBoundaryType)
595 {
596 switch (aBoundaryType) {
597 case BOUNDARY_CHAR:
598 return "char";
599 case BOUNDARY_WORD_START:
600 return "word start";
601 case BOUNDARY_WORD_END:
602 return "word end";
603 case BOUNDARY_LINE_START:
604 return "line start";
605 case BOUNDARY_LINE_END:
606 return "line end";
607 }
608 }