michael@0: /** michael@0: * Perform all editable text tests. michael@0: */ michael@0: function editableTextTestRun() michael@0: { michael@0: this.add = function add(aTest) michael@0: { michael@0: this.seq.push(aTest); michael@0: } michael@0: michael@0: this.run = function run() michael@0: { michael@0: this.iterate(); michael@0: } michael@0: michael@0: this.index = 0; michael@0: this.seq = new Array(); michael@0: michael@0: this.iterate = function iterate() michael@0: { michael@0: if (this.index < this.seq.length) { michael@0: this.seq[this.index++].startTest(this); michael@0: return; michael@0: } michael@0: michael@0: this.seq = null; michael@0: SimpleTest.finish(); michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Used to test nsIEditableTextAccessible methods. michael@0: */ michael@0: function editableTextTest(aID) michael@0: { michael@0: /** michael@0: * Schedule a test, the given function with its arguments will be executed michael@0: * when preceding test is complete. michael@0: */ michael@0: this.scheduleTest = function scheduleTest(aFunc) michael@0: { michael@0: // A data container acts like a dummy invoker, it's never invoked but michael@0: // it's used to generate real invoker when previous invoker was handled. michael@0: var dataContainer = { michael@0: func: aFunc, michael@0: funcArgs: Array.slice(arguments, 1) michael@0: }; michael@0: this.mEventQueue.push(dataContainer); michael@0: michael@0: if (!this.mEventQueueReady) { michael@0: this.unwrapNextTest(); michael@0: this.mEventQueueReady = true; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * setTextContents test. michael@0: */ michael@0: this.setTextContents = function setTextContents(aValue) michael@0: { michael@0: var testID = "setTextContents '" + aValue + "' for " + prettyName(aID); michael@0: michael@0: function setTextContentsInvoke() michael@0: { michael@0: var acc = getAccessible(aID, nsIAccessibleEditableText); michael@0: acc.setTextContents(aValue); michael@0: } michael@0: michael@0: var insertTripple = aValue ? [0, aValue.length, aValue] : null; michael@0: var oldValue = getValue(aID); michael@0: var removeTripple = oldValue ? [0, oldValue.length, oldValue] : null; michael@0: michael@0: this.generateTest(aID, removeTripple, insertTripple, setTextContentsInvoke, michael@0: getValueChecker(aID, aValue), testID); michael@0: } michael@0: michael@0: /** michael@0: * insertText test. michael@0: */ michael@0: this.insertText = function insertText(aStr, aPos, aResStr, aResPos) michael@0: { michael@0: var testID = "insertText '" + aStr + "' at " + aPos + " for " + michael@0: prettyName(aID); michael@0: michael@0: function insertTextInvoke() michael@0: { michael@0: var acc = getAccessible(aID, nsIAccessibleEditableText); michael@0: acc.insertText(aStr, aPos); michael@0: } michael@0: michael@0: var resPos = (aResPos != undefined) ? aResPos : aPos; michael@0: this.generateTest(aID, null, [resPos, resPos + aStr.length, aStr], michael@0: insertTextInvoke, getValueChecker(aID, aResStr), testID); michael@0: } michael@0: michael@0: /** michael@0: * copyText test. michael@0: */ michael@0: this.copyText = function copyText(aStartPos, aEndPos, aClipboardStr) michael@0: { michael@0: var testID = "copyText from " + aStartPos + " to " + aEndPos + " for " + michael@0: prettyName(aID); michael@0: michael@0: function copyTextInvoke() michael@0: { michael@0: var acc = getAccessible(aID, nsIAccessibleEditableText); michael@0: acc.copyText(aStartPos, aEndPos); michael@0: } michael@0: michael@0: this.generateTest(aID, null, null, copyTextInvoke, michael@0: getClipboardChecker(aID, aClipboardStr), testID); michael@0: } michael@0: michael@0: /** michael@0: * copyText and pasteText test. michael@0: */ michael@0: this.copyNPasteText = function copyNPasteText(aStartPos, aEndPos, michael@0: aPos, aResStr) michael@0: { michael@0: var testID = "copyText from " + aStartPos + " to " + aEndPos + michael@0: "and pasteText at " + aPos + " for " + prettyName(aID); michael@0: michael@0: function copyNPasteTextInvoke() michael@0: { michael@0: var acc = getAccessible(aID, nsIAccessibleEditableText); michael@0: acc.copyText(aStartPos, aEndPos); michael@0: acc.pasteText(aPos); michael@0: } michael@0: michael@0: this.generateTest(aID, null, [aStartPos, aEndPos, getTextFromClipboard], michael@0: copyNPasteInvoke, getValueChecker(aID, aResStr), testID); michael@0: } michael@0: michael@0: /** michael@0: * cutText test. michael@0: */ michael@0: this.cutText = function cutText(aStartPos, aEndPos, aResStr, michael@0: aResStartPos, aResEndPos) michael@0: { michael@0: var testID = "cutText from " + aStartPos + " to " + aEndPos + " for " + michael@0: prettyName(aID); michael@0: michael@0: function cutTextInvoke() michael@0: { michael@0: var acc = getAccessible(aID, nsIAccessibleEditableText); michael@0: acc.cutText(aStartPos, aEndPos); michael@0: } michael@0: michael@0: var resStartPos = (aResStartPos != undefined) ? aResStartPos : aStartPos; michael@0: var resEndPos = (aResEndPos != undefined) ? aResEndPos : aEndPos; michael@0: this.generateTest(aID, [resStartPos, resEndPos, getTextFromClipboard], null, michael@0: cutTextInvoke, getValueChecker(aID, aResStr), testID); michael@0: } michael@0: michael@0: /** michael@0: * cutText and pasteText test. michael@0: */ michael@0: this.cutNPasteText = function copyNPasteText(aStartPos, aEndPos, michael@0: aPos, aResStr) michael@0: { michael@0: var testID = "cutText from " + aStartPos + " to " + aEndPos + michael@0: " and pasteText at " + aPos + " for " + prettyName(aID); michael@0: michael@0: function cutNPasteTextInvoke() michael@0: { michael@0: var acc = getAccessible(aID, nsIAccessibleEditableText); michael@0: acc.cutText(aStartPos, aEndPos); michael@0: acc.pasteText(aPos); michael@0: } michael@0: michael@0: this.generateTest(aID, [aStartPos, aEndPos, getTextFromClipboard], michael@0: [aPos, -1, getTextFromClipboard], michael@0: cutNPasteTextInvoke, getValueChecker(aID, aResStr), michael@0: testID); michael@0: } michael@0: michael@0: /** michael@0: * pasteText test. michael@0: */ michael@0: this.pasteText = function pasteText(aPos, aResStr) michael@0: { michael@0: var testID = "pasteText at " + aPos + " for " + prettyName(aID); michael@0: michael@0: function pasteTextInvoke() michael@0: { michael@0: var acc = getAccessible(aID, nsIAccessibleEditableText); michael@0: acc.pasteText(aPos); michael@0: } michael@0: michael@0: this.generateTest(aID, null, [aPos, -1, getTextFromClipboard], michael@0: pasteTextInvoke, getValueChecker(aID, aResStr), testID); michael@0: } michael@0: michael@0: /** michael@0: * deleteText test. michael@0: */ michael@0: this.deleteText = function deleteText(aStartPos, aEndPos, aResStr) michael@0: { michael@0: var testID = "deleteText from " + aStartPos + " to " + aEndPos + michael@0: " for " + prettyName(aID); michael@0: michael@0: var oldValue = getValue(aID).substring(aStartPos, aEndPos); michael@0: var removeTripple = oldValue ? [aStartPos, aEndPos, oldValue] : null; michael@0: michael@0: function deleteTextInvoke() michael@0: { michael@0: var acc = getAccessible(aID, [nsIAccessibleEditableText]); michael@0: acc.deleteText(aStartPos, aEndPos); michael@0: } michael@0: michael@0: this.generateTest(aID, removeTripple, null, deleteTextInvoke, michael@0: getValueChecker(aID, aResStr), testID); michael@0: } michael@0: michael@0: ////////////////////////////////////////////////////////////////////////////// michael@0: // Implementation details. michael@0: michael@0: function getValue(aID) michael@0: { michael@0: var value = ""; michael@0: var elm = getNode(aID); michael@0: if (elm instanceof Components.interfaces.nsIDOMNSEditableElement) michael@0: return elm.value; michael@0: michael@0: if (elm instanceof Components.interfaces.nsIDOMHTMLDocument) michael@0: return elm.body.textContent; michael@0: michael@0: return elm.textContent; michael@0: } michael@0: michael@0: /** michael@0: * Common checkers. michael@0: */ michael@0: function getValueChecker(aID, aValue) michael@0: { michael@0: var checker = { michael@0: check: function valueChecker_check() michael@0: { michael@0: is(getValue(aID), aValue, "Wrong value " + aValue); michael@0: } michael@0: }; michael@0: return checker; michael@0: } michael@0: michael@0: function getClipboardChecker(aID, aText) michael@0: { michael@0: var checker = { michael@0: check: function clipboardChecker_check() michael@0: { michael@0: is(getTextFromClipboard(), aText, "Wrong text in clipboard."); michael@0: } michael@0: }; michael@0: return checker; michael@0: } michael@0: michael@0: function getValueNClipboardChecker(aID, aValue, aText) michael@0: { michael@0: var valueChecker = getValueChecker(aID, aValue); michael@0: var clipboardChecker = getClipboardChecker(aID, aText); michael@0: michael@0: var checker = { michael@0: check: function() michael@0: { michael@0: valueChecker.check(); michael@0: clipboardChecker.check(); michael@0: } michael@0: }; michael@0: return checker; michael@0: } michael@0: michael@0: /** michael@0: * Process next scheduled test. michael@0: */ michael@0: this.unwrapNextTest = function unwrapNextTest() michael@0: { michael@0: var data = this.mEventQueue.mInvokers[this.mEventQueue.mIndex + 1]; michael@0: if (data) michael@0: data.func.apply(this, data.funcArgs); michael@0: } michael@0: michael@0: /** michael@0: * Used to generate an invoker object for the sheduled test. michael@0: */ michael@0: this.generateTest = function generateTest(aID, aRemoveTriple, aInsertTriple, michael@0: aInvokeFunc, aChecker, aInvokerID) michael@0: { michael@0: var et = this; michael@0: var invoker = { michael@0: eventSeq: [], michael@0: michael@0: invoke: aInvokeFunc, michael@0: finalCheck: function finalCheck() michael@0: { michael@0: aChecker.check(); michael@0: et.unwrapNextTest(); // replace dummy invoker on real invoker object. michael@0: }, michael@0: getID: function getID() { return aInvokerID; } michael@0: }; michael@0: michael@0: if (aRemoveTriple) { michael@0: var checker = new textChangeChecker(aID, aRemoveTriple[0], michael@0: aRemoveTriple[1], aRemoveTriple[2], michael@0: false); michael@0: invoker.eventSeq.push(checker); michael@0: } michael@0: michael@0: if (aInsertTriple) { michael@0: var checker = new textChangeChecker(aID, aInsertTriple[0], michael@0: aInsertTriple[1], aInsertTriple[2], michael@0: true); michael@0: invoker.eventSeq.push(checker); michael@0: } michael@0: michael@0: // Claim that we don't want to fail when no events are expected. michael@0: if (!aRemoveTriple && !aInsertTriple) michael@0: invoker.noEventsOnAction = true; michael@0: michael@0: this.mEventQueue.mInvokers[this.mEventQueue.mIndex + 1] = invoker; michael@0: } michael@0: michael@0: /** michael@0: * Run the tests. michael@0: */ michael@0: this.startTest = function startTest(aTestRun) michael@0: { michael@0: var testRunObj = aTestRun; michael@0: var thisObj = this; michael@0: this.mEventQueue.onFinish = function finishCallback() michael@0: { michael@0: // Notify textRun object that all tests were finished. michael@0: testRunObj.iterate(); michael@0: michael@0: // Help GC to avoid leaks (refer to aTestRun from local variable, drop michael@0: // onFinish function). michael@0: thisObj.mEventQueue.onFinish = null; michael@0: michael@0: return DO_NOT_FINISH_TEST; michael@0: } michael@0: michael@0: this.mEventQueue.invoke(); michael@0: } michael@0: michael@0: this.mEventQueue = new eventQueue(); michael@0: this.mEventQueueReady = false; michael@0: } michael@0: