Remove tests from toolkit.
This commit is contained in:
parent
35b20eff09
commit
275db572d9
|
@ -4,7 +4,4 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
||||
with Files('**'):
|
||||
BUG_COMPONENT = ('Core', 'Panning and Zooming')
|
||||
JAR_MANIFESTS += ['jar.mn']
|
|
@ -4,9 +4,4 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
MOCHITEST_CHROME_MANIFESTS += ['tests/chrome.ini']
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
||||
with Files('**'):
|
||||
BUG_COMPONENT = ('Toolkit', 'about:memory')
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"../../../../testing/mochitest/chrome.eslintrc.js"
|
||||
]
|
||||
};
|
|
@ -1,28 +0,0 @@
|
|||
[DEFAULT]
|
||||
skip-if = os == 'android'
|
||||
support-files =
|
||||
crash-dump-diff1.json
|
||||
crash-dump-diff2.json
|
||||
crash-dump-good.json
|
||||
memory-reports-bad.json
|
||||
memory-reports-diff1.json
|
||||
memory-reports-diff2.json
|
||||
memory-reports-good.json
|
||||
remote.xul
|
||||
|
||||
[test_aboutmemory.xul]
|
||||
subsuite = clipboard
|
||||
[test_aboutmemory2.xul]
|
||||
subsuite = clipboard
|
||||
[test_aboutmemory3.xul]
|
||||
subsuite = clipboard
|
||||
[test_aboutmemory4.xul]
|
||||
subsuite = clipboard
|
||||
[test_aboutmemory5.xul]
|
||||
subsuite = clipboard
|
||||
skip-if = asan # Bug 1116230
|
||||
[test_aboutmemory6.xul]
|
||||
[test_memoryReporters.xul]
|
||||
[test_memoryReporters2.xul]
|
||||
[test_sqliteMultiReporter.xul]
|
||||
[test_dumpGCAndCCLogsToFile.xul]
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"foo": 1,
|
||||
"blah": 2,
|
||||
"memory_report": {
|
||||
"version": 1,
|
||||
"hasMozMallocUsableSize": true,
|
||||
"reports": [
|
||||
{"process": "Main Process (pid NNN)", "path": "heap-allocated", "kind": 2, "units": 0, "amount": 262144000, "description": "Heap allocated."}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"foo": 3,
|
||||
"blah": 4,
|
||||
"memory_report": {
|
||||
"version": 1,
|
||||
"hasMozMallocUsableSize": true,
|
||||
"reports": [
|
||||
{"process": "Main Process (pid NNN)", "path": "heap-allocated", "kind": 2, "units": 0, "amount": 262144001, "description": "Heap allocated."}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
"foo": 1,
|
||||
"blah": 2,
|
||||
"memory_report": {
|
||||
"version": 1,
|
||||
"hasMozMallocUsableSize": true,
|
||||
"reports": [
|
||||
{"process": "Main Process (pid NNN)", "path": "heap-allocated", "kind": 2, "units": 0, "amount": 262144000, "description": "Heap allocated."},
|
||||
{"process": "Main Process (pid NNN)", "path": "other/b", "kind": 2, "units": 0, "amount": 104857, "description": "Other b."},
|
||||
{"process": "Main Process (pid NNN)", "path": "other/a", "kind": 2, "units": 0, "amount": 209715, "description": "Other a."},
|
||||
{"process": "Main Process (pid NNN)", "path": "explicit/a/b", "kind": 1, "units": 0, "amount": 52428800, "description": "A b."}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"version": 1
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
{
|
||||
"version": 1,
|
||||
"hasMozMallocUsableSize": true,
|
||||
"reports": [
|
||||
{"process": "P", "path": "explicit/xpcom/category-manager", "kind": 1, "units": 0, "amount": 56848, "description": "Desc."},
|
||||
{"process": "P", "path": "explicit/storage/prefixset/goog-phish-shavar", "kind": 1, "units": 0, "amount": 680000, "description": "Desc."},
|
||||
|
||||
{"process": "P", "path": "explicit/spell-check", "kind": 1, "units": 0, "amount": 4, "description": "Desc."},
|
||||
{"process": "P", "path": "explicit/spell-check", "kind": 1, "units": 0, "amount": 5, "description": "Desc."},
|
||||
|
||||
{"process": "P", "path": "page-faults-soft", "kind": 2, "units": 2, "amount": 61013, "description": "Desc."},
|
||||
|
||||
{"process": "P", "path": "foobar", "kind": 2, "units": 0, "amount": 100, "description": "Desc."},
|
||||
{"process": "P", "path": "zero1", "kind": 2, "units": 0, "amount": 0, "description": "Desc."},
|
||||
|
||||
{"process": "P", "path": "a/b", "kind": 2, "units": 0, "amount": 1000000, "description": "Desc."},
|
||||
{"process": "P", "path": "a/c/d", "kind": 2, "units": 0, "amount": 2000000, "description": "Desc."},
|
||||
{"process": "P", "path": "a/c/e", "kind": 2, "units": 0, "amount": 2000000, "description": "Desc."},
|
||||
{"process": "P", "path": "a/c/f", "kind": 2, "units": 0, "amount": 3000000, "description": "Desc."},
|
||||
{"process": "P", "path": "a/c/g", "kind": 2, "units": 0, "amount": 3000000, "description": "Desc."},
|
||||
{"process": "P", "path": "a/h", "kind": 2, "units": 0, "amount": 1000, "description": "Desc."},
|
||||
|
||||
{"process": "P2 (pid 22)", "path": "p1 (pid 123)", "kind": 2, "units": 0, "amount": 33, "description": "Desc."},
|
||||
{"process": "P2 (pid 22)", "path": "p2 (blah, pid=123)", "kind": 2, "units": 0, "amount": 33, "description": "Desc."},
|
||||
{"process": "P2 (pid 22)", "path": "p3/zone(0x1234)/p3", "kind": 2, "units": 0, "amount": 33, "description": "Desc."},
|
||||
{"process": "P2 (pid 22)", "path": "p4/js-zone(0x1234)/p4", "kind": 2, "units": 0, "amount": 33, "description": "Desc."},
|
||||
{"process": "P2 (pid 22)", "path": "p5/worker(foo.com, 0x1234)/p5", "kind": 2, "units": 0, "amount": 33, "description": "Desc."},
|
||||
{"process": "P2 (pid 22)", "path": "explicit/window-objects/top(bar.com, id=123)/...", "kind": 0, "units": 0, "amount": 33, "description": "Desc."},
|
||||
{"process": "P2 (pid 22)", "path": "p6/z-moz-nullprincipal:{85e250f3-57ae-46c4-a11e-4176dd39d9c5}/p6", "kind": 2, "units": 0, "amount": 33, "description": "Desc."},
|
||||
{"process": "P2 (pid 22)", "path": "p7/js-main-runtime-compartments/system/jar:file:\\\\\\temp_xyz\\firefox\\omni.ja!/p7", "kind": 2, "units": 0, "amount": 33, "description": "Desc."},
|
||||
|
||||
{"process": "P3", "path": "p3", "kind": 2, "units": 0, "amount": 55, "description": "Desc."},
|
||||
|
||||
{"process": "P5", "path": "p5", "kind": 2, "units": 0, "amount": 0, "description": "Desc."},
|
||||
|
||||
{"process": "P7", "path": "p7", "kind": 2, "units": 0, "amount": 5, "description": "Desc."},
|
||||
|
||||
{"process": "P8", "path": "p8/a/b/c/d", "kind": 2, "units": 0, "amount": 3, "description": "Desc."},
|
||||
{"process": "P8", "path": "p8/a/b/c/e", "kind": 2, "units": 0, "amount": 4, "description": "Desc."},
|
||||
{"process": "P8", "path": "p8/a/b/f", "kind": 2, "units": 0, "amount": 5, "description": "Desc."},
|
||||
{"process": "P8", "path": "p8/a/g/h", "kind": 2, "units": 0, "amount": 6, "description": "Desc."},
|
||||
{"process": "P8", "path": "p8/a/g/i", "kind": 2, "units": 0, "amount": 7, "description": "Desc."}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
{
|
||||
"version": 1,
|
||||
"hasMozMallocUsableSize": true,
|
||||
"reports": [
|
||||
{"process": "P", "path": "explicit/xpcom/category-manager", "kind": 1, "units": 0, "amount": 56849, "description": "Desc."},
|
||||
{"process": "P", "path": "explicit/storage/prefixset/goog-phish-shavar", "kind": 1, "units": 0, "amount": 670000, "description": "Desc."},
|
||||
|
||||
{"process": "P", "path": "explicit/spell-check", "kind": 1, "units": 0, "amount": 3, "description": "Desc."},
|
||||
|
||||
{"process": "P", "path": "page-faults-soft", "kind": 2, "units": 2, "amount": 61013, "description": "Desc."},
|
||||
|
||||
{"process": "P", "path": "canvas-2d-pixel-bytes", "kind": 2, "units": 0, "amount": 1000, "description": "Desc."},
|
||||
{"process": "P", "path": "canvas-2d-pixel-bytes", "kind": 2, "units": 0, "amount": 2000, "description": "Desc."},
|
||||
|
||||
{"process": "P", "path": "foobaz", "kind": 2, "units": 0, "amount": 0, "description": "Desc."},
|
||||
|
||||
{"process": "P", "path": "a/b", "kind": 2, "units": 0, "amount": 2000000, "description": "Desc."},
|
||||
{"process": "P", "path": "a/c/d", "kind": 2, "units": 0, "amount": 2998000, "description": "Desc."},
|
||||
{"process": "P", "path": "a/c/e", "kind": 2, "units": 0, "amount": 1001000, "description": "Desc."},
|
||||
{"process": "P", "path": "a/c/f", "kind": 2, "units": 0, "amount": 3001000, "description": "Desc."},
|
||||
{"process": "P", "path": "a/c/g", "kind": 2, "units": 0, "amount": 3001000, "description": "Desc."},
|
||||
{"process": "P", "path": "a/h", "kind": 2, "units": 0, "amount": 2000, "description": "Desc."},
|
||||
|
||||
{"process": "P2 (pid 22)", "path": "p1 (pid 456)", "kind": 2, "units": 0, "amount": 44, "description": "Desc."},
|
||||
{"process": "P2 (pid 22)", "path": "p2 (blah, pid=456)", "kind": 2, "units": 0, "amount": 44, "description": "Desc."},
|
||||
{"process": "P2 (pid 22)", "path": "p3/zone(0x5678)/p3", "kind": 2, "units": 0, "amount": 44, "description": "Desc."},
|
||||
{"process": "P2 (pid 22)", "path": "p4/js-zone(0x5678)/p4", "kind": 2, "units": 0, "amount": 44, "description": "Desc."},
|
||||
{"process": "P2 (pid 22)", "path": "p5/worker(foo.com, 0x5678)/p5", "kind": 2, "units": 0, "amount": 44, "description": "Desc."},
|
||||
{"process": "P2 (pid 22)", "path": "explicit/window-objects/top(bar.com, id=456)/...", "kind": 0, "units": 0, "amount": 44, "description": "Desc."},
|
||||
{"process": "P2 (pid 22)", "path": "p6/z-moz-nullprincipal:{161effaa-c1f7-4010-a08e-e7c9aea01aed}/p6", "kind": 2, "units": 0, "amount": 44, "description": "Desc."},
|
||||
{"process": "P2 (pid 22)", "path": "p7/js-main-runtime-compartments/system/jar:file:\\\\\\temp_abc\\firefox\\omni.ja!/p7", "kind": 2, "units": 0, "amount": 44, "description": "Desc."},
|
||||
|
||||
{"process": "P4", "path": "p4", "kind": 2, "units": 0, "amount": 66, "description": "Desc."},
|
||||
|
||||
{"process": "P6", "path": "p6", "kind": 2, "units": 0, "amount": 0, "description": "Desc."},
|
||||
|
||||
{"process": "P7", "path": "p7/b", "kind": 2, "units": 0, "amount": 3, "description": "Desc."},
|
||||
{"process": "P7", "path": "p7/c", "kind": 2, "units": 0, "amount": 4, "description": "Desc."},
|
||||
|
||||
{"process": "P8", "path": "p8/a/b", "kind": 2, "units": 0, "amount": 1, "description": "Desc."},
|
||||
{"process": "P8", "path": "p8/a/g", "kind": 2, "units": 0, "amount": 2, "description": "Desc."}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
{
|
||||
"version": 1,
|
||||
"hasMozMallocUsableSize": true,
|
||||
"reports": [
|
||||
{"process": "Main Process (pid NNN)", "path": "heap-allocated", "kind": 2, "units": 0, "amount": 262144000, "description": "Heap allocated."},
|
||||
{"process": "Main Process (pid NNN)", "path": "other/b", "kind": 2, "units": 0, "amount": 104857, "description": "Other b."},
|
||||
{"process": "Main Process (pid NNN)", "path": "other/a", "kind": 2, "units": 0, "amount": 209715, "description": "Other a."},
|
||||
{"process": "Main Process (pid NNN)", "path": "explicit/a/b", "kind": 1, "units": 0, "amount": 52428800, "description": "A b."},
|
||||
|
||||
{"process": "Main Process (pid NNN)", "path": "size/a", "kind": 1, "units": 0, "amount": 1024, "description": "non-sentence"},
|
||||
{"process": "Main Process (pid NNN)", "path": "rss/a", "kind": 1, "units": 0, "amount": 1024, "description": "non-sentence"},
|
||||
{"process": "Main Process (pid NNN)", "path": "pss/a", "kind": 1, "units": 0, "amount": 1024, "description": "non-sentence"},
|
||||
{"process": "Main Process (pid NNN)", "path": "swap/a", "kind": 1, "units": 0, "amount": 1024, "description": "non-sentence"},
|
||||
{"process": "Main Process (pid NNN)", "path": "compartments/system/a", "kind": 1, "units": 0, "amount": 1024, "description": ""},
|
||||
{"process": "Main Process (pid NNN)", "path": "ghost-windows/a", "kind": 1, "units": 0, "amount": 1024, "description": ""},
|
||||
|
||||
{"process": "Main Process (pid NNN)", "path": "redundant/should-be-ignored", "kind": 1, "units": 0, "amount": 1024, "description": ""},
|
||||
|
||||
{"process": "Heap-unclassified process", "path": "heap-allocated", "kind": 2, "units": 0, "amount": 262144000, "description": "Heap allocated."},
|
||||
{"process": "Heap-unclassified process", "path": "explicit/a/b", "kind": 1, "units": 0, "amount": 52428800, "description": "A b."},
|
||||
{"process": "Heap-unclassified process", "path": "explicit/heap-unclassified", "kind": 1, "units": 0, "amount": 209715200, "description": "Heap unclassified"},
|
||||
|
||||
{"process": "Explicit-only process", "path": "explicit/a/b", "kind": 1, "units": 0, "amount": 100000, "description": "A b."},
|
||||
|
||||
{"process": "Other-only process", "path": "a/b", "kind": 1, "units": 0, "amount": 100000, "description": "A b."},
|
||||
{"process": "Other-only process", "path": "a/c", "kind": 1, "units": 0, "amount": 100000, "description": "A c."},
|
||||
{"process": "Other-only process", "path": "heap-allocated", "kind": 1, "units": 0, "amount": 500000, "description": "D."}
|
||||
]
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
<window title="Remote browser"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<p>Remote browser</p>
|
||||
|
||||
<browser type="content" src="about:blank" id="remote" remote="true"/>
|
||||
</window>
|
|
@ -1,602 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
|
||||
<window title="about:memory"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
|
||||
<!-- This file uses fake memory reporters to test the presentation of memory
|
||||
reports in about:memory. test_memoryReporters.xul uses the real
|
||||
memory reporters to test whether the memory reporters are producing
|
||||
sensible results. -->
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml"></body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
"use strict";
|
||||
|
||||
SimpleTest.expectAssertions(27);
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
let mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
|
||||
getService(Ci.nsIMemoryReporterManager);
|
||||
|
||||
// Hide all the real reporters; we'll restore them at the end.
|
||||
mgr.blockRegistrationAndHideExistingReporters();
|
||||
|
||||
// Setup various fake-but-deterministic reporters.
|
||||
const KB = 1024;
|
||||
const MB = KB * KB;
|
||||
const NONHEAP = Ci.nsIMemoryReporter.KIND_NONHEAP;
|
||||
const HEAP = Ci.nsIMemoryReporter.KIND_HEAP;
|
||||
const OTHER = Ci.nsIMemoryReporter.KIND_OTHER;
|
||||
|
||||
const BYTES = Ci.nsIMemoryReporter.UNITS_BYTES;
|
||||
const COUNT = Ci.nsIMemoryReporter.UNITS_COUNT;
|
||||
const COUNT_CUMULATIVE = Ci.nsIMemoryReporter.UNITS_COUNT_CUMULATIVE;
|
||||
const PERCENTAGE = Ci.nsIMemoryReporter.UNITS_PERCENTAGE;
|
||||
|
||||
let fakeReporters = [
|
||||
{ collectReports: function(aCbObj, aClosure, aAnonymize) {
|
||||
function f(aP, aK, aU, aA) {
|
||||
aCbObj.callback("", aP, aK, aU, aA, "Desc.", aClosure);
|
||||
}
|
||||
f("heap-allocated", OTHER, BYTES, 500 * MB);
|
||||
f("heap-unallocated", OTHER, BYTES, 100 * MB);
|
||||
f("explicit/a", HEAP, BYTES, 222 * MB);
|
||||
f("explicit/b/a", HEAP, BYTES, 85 * MB);
|
||||
f("explicit/b/b", HEAP, BYTES, 75 * MB);
|
||||
f("explicit/b/c/a", HEAP, BYTES, 70 * MB);
|
||||
f("explicit/b/c/b", HEAP, BYTES, 2 * MB); // omitted
|
||||
f("explicit/g/a", HEAP, BYTES, 6 * MB);
|
||||
f("explicit/g/b", HEAP, BYTES, 5 * MB);
|
||||
f("explicit/g/other", HEAP, BYTES, 4 * MB);
|
||||
// A degenerate tree with the same name as a non-degenerate tree should
|
||||
// work ok.
|
||||
f("explicit", OTHER, BYTES, 888 * MB);
|
||||
f("other1/a/b", OTHER, BYTES, 111 * MB);
|
||||
f("other1/c/d", OTHER, BYTES, 22 * MB);
|
||||
f("other1/c/e", OTHER, BYTES, 33 * MB);
|
||||
f("other4", OTHER, COUNT_CUMULATIVE, 777);
|
||||
f("other4", OTHER, COUNT_CUMULATIVE, 111);
|
||||
f("other3/a/b/c/d/e", OTHER, PERCENTAGE, 2000);
|
||||
f("other3/a/b/c/d/f", OTHER, PERCENTAGE, 10);
|
||||
f("other3/a/b/c/d/g", OTHER, PERCENTAGE, 5);
|
||||
f("other3/a/b/c/d/g", OTHER, PERCENTAGE, 5);
|
||||
// Check that a rounded-up-to-100.00% value is shown as "100.0%" (i.e. one
|
||||
// decimal point).
|
||||
f("other6/big", OTHER, COUNT, 99999);
|
||||
f("other6/small", OTHER, COUNT, 1);
|
||||
// Check that a 0 / 0 is handled correctly.
|
||||
f("other7/zero", OTHER, BYTES, 0);
|
||||
// These compartments ones shouldn't be displayed.
|
||||
f("compartments/user/foo", OTHER, COUNT, 1);
|
||||
f("compartments/system/foo", OTHER, COUNT, 1);
|
||||
}
|
||||
},
|
||||
{ collectReports: function(aCbObj, aClosure, aAnonymize) {
|
||||
function f(aP, aK, aU, aA) {
|
||||
aCbObj.callback("", aP, aK, aU, aA, "Desc.", aClosure);
|
||||
}
|
||||
f("explicit/c/d", NONHEAP, BYTES, 13 * MB);
|
||||
f("explicit/c/d", NONHEAP, BYTES, 10 * MB); // dup
|
||||
f("explicit/c/other", NONHEAP, BYTES, 77 * MB);
|
||||
f("explicit/cc", NONHEAP, BYTES, 13 * MB);
|
||||
f("explicit/cc", NONHEAP, BYTES, 10 * MB); // dup
|
||||
f("explicit/d", NONHEAP, BYTES, 499 * KB); // omitted
|
||||
f("explicit/e", NONHEAP, BYTES, 100 * KB); // omitted
|
||||
f("explicit/f/g/h/i", HEAP, BYTES, 10 * MB);
|
||||
f("explicit/f/g/h/j", HEAP, BYTES, 10 * MB);
|
||||
}
|
||||
},
|
||||
{ collectReports: function(aCbObj, aClosure, aAnonymize) {
|
||||
function f(aP, aK, aU, aA) {
|
||||
aCbObj.callback("", aP, aK, aU, aA, "Desc.", aClosure);
|
||||
}
|
||||
f("other3", OTHER, COUNT, 777);
|
||||
f("other2", OTHER, BYTES, 222 * MB);
|
||||
f("perc2", OTHER, PERCENTAGE, 10000);
|
||||
f("perc1", OTHER, PERCENTAGE, 4567);
|
||||
f("compartments/user/https:\\\\very-long-url.com\\very-long\\oh-so-long\\really-quite-long.html?a=2&b=3&c=4&d=5&e=abcdefghijklmnopqrstuvwxyz&f=123456789123456789123456789", OTHER, COUNT, 1);
|
||||
}
|
||||
},
|
||||
{ collectReports: function(aCbObj, aClosure, aAnonymize) {
|
||||
function f(aP) {
|
||||
aCbObj.callback("", aP, OTHER, COUNT, 1, "Desc.", aClosure);
|
||||
}
|
||||
f("compartments/user/bar");
|
||||
f("compartments/system/bar");
|
||||
}
|
||||
}
|
||||
];
|
||||
for (let i = 0; i < fakeReporters.length; i++) {
|
||||
mgr.registerStrongReporterEvenIfBlocked(fakeReporters[i]);
|
||||
}
|
||||
|
||||
// The main process always comes first when we display about:memory. The
|
||||
// remaining processes are sorted by their |resident| values (starting with
|
||||
// the largest). Processes without a |resident| memory reporter are saved
|
||||
// for the end.
|
||||
let fakeReporters2 = [
|
||||
{ collectReports: function(aCbObj, aClosure, aAnonymize) {
|
||||
function f(aP1, aP2, aK, aU, aA) {
|
||||
aCbObj.callback(aP1, aP2, aK, aU, aA, "Desc.", aClosure);
|
||||
}
|
||||
f("2nd", "heap-allocated", OTHER, BYTES,1000* MB);
|
||||
f("2nd", "heap-unallocated",OTHER, BYTES,100 * MB);
|
||||
f("2nd", "explicit/a/b/c", HEAP, BYTES,497 * MB);
|
||||
f("2nd", "explicit/a/b/c", HEAP, BYTES, 1 * MB); // dup: merge
|
||||
f("2nd", "explicit/a/b/c", HEAP, BYTES, 1 * MB); // dup: merge
|
||||
f("2nd", "explicit/flip\\the\\backslashes",
|
||||
HEAP, BYTES,200 * MB);
|
||||
f("2nd", "explicit/compartment(compartment-url)",
|
||||
HEAP, BYTES,200 * MB);
|
||||
f("2nd", "other0", OTHER, BYTES,666 * MB);
|
||||
f("2nd", "other1", OTHER, BYTES,111 * MB);
|
||||
|
||||
// Check that we can handle "heap-allocated" not being present.
|
||||
f("3rd", "explicit/a/b", HEAP, BYTES,333 * MB);
|
||||
f("3rd", "explicit/a/c", HEAP, BYTES,444 * MB);
|
||||
f("3rd", "other1", OTHER, BYTES, 1 * MB);
|
||||
f("3rd", "resident", OTHER, BYTES,100 * MB);
|
||||
|
||||
// Invalid values (negative, too-big) should be identified.
|
||||
f("4th", "heap-allocated", OTHER, BYTES,100 * MB);
|
||||
f("4th", "resident", OTHER, BYTES,200 * MB);
|
||||
f("4th", "explicit/js/compartment(http:\\\\too-big.com\\)/stuff",
|
||||
HEAP, BYTES,150 * MB);
|
||||
f("4th", "explicit/ok", HEAP, BYTES, 5 * MB);
|
||||
f("4th", "explicit/neg1", NONHEAP, BYTES, -2 * MB);
|
||||
// -111 becomes "-0.00MB" in non-verbose mode, and getting the negative
|
||||
// sign in there correctly is non-trivial.
|
||||
f("4th", "other1", OTHER, BYTES,-111);
|
||||
f("4th", "other2", OTHER, BYTES,-222 * MB);
|
||||
f("4th", "other3", OTHER, COUNT, -333);
|
||||
f("4th", "other4", OTHER, COUNT_CUMULATIVE, -444);
|
||||
f("4th", "other5", OTHER, PERCENTAGE, -555);
|
||||
f("4th", "other6", OTHER, PERCENTAGE, 66666);
|
||||
|
||||
// If a negative value is within a collapsed sub-tree in non-verbose mode,
|
||||
// we should get the warning at the top and the relevant sub-trees should
|
||||
// be expanded, even in non-verbose mode.
|
||||
f("5th", "heap-allocated", OTHER, BYTES,100 * MB);
|
||||
f("5th", "explicit/big", HEAP, BYTES, 99 * MB);
|
||||
f("5th", "explicit/a/pos", HEAP, BYTES, 40 * KB);
|
||||
f("5th", "explicit/a/neg1", NONHEAP, BYTES,-20 * KB);
|
||||
f("5th", "explicit/a/neg2", NONHEAP, BYTES,-10 * KB);
|
||||
f("5th", "explicit/b/c/d/e", NONHEAP, BYTES, 20 * KB);
|
||||
f("5th", "explicit/b/c/d/f", NONHEAP, BYTES,-60 * KB);
|
||||
f("5th", "explicit/b/c/g/h", NONHEAP, BYTES, 10 * KB);
|
||||
f("5th", "explicit/b/c/i/j", NONHEAP, BYTES, 5 * KB);
|
||||
}
|
||||
}
|
||||
];
|
||||
for (let i = 0; i < fakeReporters2.length; i++) {
|
||||
mgr.registerStrongReporterEvenIfBlocked(fakeReporters2[i]);
|
||||
}
|
||||
fakeReporters = fakeReporters.concat(fakeReporters2);
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<iframe id="amFrame" height="300" src="about:memory"></iframe>
|
||||
<!-- vary the capitalization to make sure that works -->
|
||||
<iframe id="amvFrame" height="300" src="About:Memory"></iframe>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
let amExpectedText =
|
||||
"\
|
||||
Main Process\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
623.58 MB (100.0%) -- explicit\n\
|
||||
├──232.00 MB (37.20%) -- b\n\
|
||||
│ ├───85.00 MB (13.63%) ── a\n\
|
||||
│ ├───75.00 MB (12.03%) ── b\n\
|
||||
│ └───72.00 MB (11.55%) -- c\n\
|
||||
│ ├──70.00 MB (11.23%) ── a\n\
|
||||
│ └───2.00 MB (00.32%) ── b\n\
|
||||
├──222.00 MB (35.60%) ── a\n\
|
||||
├──100.00 MB (16.04%) -- c\n\
|
||||
│ ├───77.00 MB (12.35%) ── other\n\
|
||||
│ └───23.00 MB (03.69%) ── d [2]\n\
|
||||
├───23.00 MB (03.69%) ── cc [2]\n\
|
||||
├───20.00 MB (03.21%) -- f/g/h\n\
|
||||
│ ├──10.00 MB (01.60%) ── i\n\
|
||||
│ └──10.00 MB (01.60%) ── j\n\
|
||||
├───15.00 MB (02.41%) ++ g\n\
|
||||
├───11.00 MB (01.76%) ── heap-unclassified\n\
|
||||
└────0.58 MB (00.09%) ++ (2 tiny)\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
5 (100.0%) -- compartments\n\
|
||||
├──3 (60.00%) -- user\n\
|
||||
│ ├──1 (20.00%) ── bar\n\
|
||||
│ ├──1 (20.00%) ── foo\n\
|
||||
│ └──1 (20.00%) ── https://very-long-url.com/very-long/oh-so-long/really-quite-long.html?a=2&b=3&c=4&d=5&e=abcdefghijklmnopqrstuvwxyz&f=123456789123456789123456789\n\
|
||||
└──2 (40.00%) -- system\n\
|
||||
├──1 (20.00%) ── bar\n\
|
||||
└──1 (20.00%) ── foo\n\
|
||||
\n\
|
||||
166.00 MB (100.0%) -- other1\n\
|
||||
├──111.00 MB (66.87%) ── a/b\n\
|
||||
└───55.00 MB (33.13%) -- c\n\
|
||||
├──33.00 MB (19.88%) ── e\n\
|
||||
└──22.00 MB (13.25%) ── d\n\
|
||||
\n\
|
||||
20.20% (100.0%) -- other3\n\
|
||||
└──20.20% (100.0%) -- a/b/c/d\n\
|
||||
├──20.00% (99.01%) ── e\n\
|
||||
└───0.20% (00.99%) ++ (2 tiny)\n\
|
||||
\n\
|
||||
100,000 (100.0%) -- other6\n\
|
||||
├───99,999 (100.0%) ── big\n\
|
||||
└────────1 (00.00%) ── small\n\
|
||||
\n\
|
||||
0.00 MB (100.0%) -- other7\n\
|
||||
└──0.00 MB (100.0%) ── zero\n\
|
||||
\n\
|
||||
888.00 MB ── explicit\n\
|
||||
500.00 MB ── heap-allocated\n\
|
||||
100.00 MB ── heap-unallocated\n\
|
||||
222.00 MB ── other2\n\
|
||||
777 ── other3\n\
|
||||
888 ── other4 [2]\n\
|
||||
45.67% ── perc1\n\
|
||||
100.00% ── perc2\n\
|
||||
\n\
|
||||
End of Main Process\n\
|
||||
4th\n\
|
||||
\n\
|
||||
WARNING: the following values are negative or unreasonably large.\n\
|
||||
\n\
|
||||
explicit/js/compartment(http://too-big.com/)/stuff\n\
|
||||
explicit/(2 tiny)\n\
|
||||
explicit/(2 tiny)/neg1\n\
|
||||
explicit/(2 tiny)/heap-unclassified\n\
|
||||
other1\n\
|
||||
other2\n\
|
||||
other3\n\
|
||||
other4\n\
|
||||
other5 \n\
|
||||
\n\
|
||||
This indicates a defect in one or more memory reporters. The invalid values are highlighted.\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
98.00 MB (100.0%) -- explicit\n\
|
||||
├──150.00 MB (153.06%) ── js/compartment(http://too-big.com/)/stuff [?!]\n\
|
||||
├───5.00 MB (05.10%) ── ok\n\
|
||||
└──-57.00 MB (-58.16%) -- (2 tiny) [?!]\n\
|
||||
├───-2.00 MB (-2.04%) ── neg1 [?!]\n\
|
||||
└──-55.00 MB (-56.12%) ── heap-unclassified [?!]\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
100.00 MB ── heap-allocated\n\
|
||||
-0.00 MB ── other1 [?!]\n\
|
||||
-222.00 MB ── other2 [?!]\n\
|
||||
-333 ── other3 [?!]\n\
|
||||
-444 ── other4 [?!]\n\
|
||||
-5.55% ── other5 [?!]\n\
|
||||
666.66% ── other6\n\
|
||||
200.00 MB ── resident\n\
|
||||
\n\
|
||||
End of 4th\n\
|
||||
3rd\n\
|
||||
\n\
|
||||
WARNING: the 'heap-allocated' memory reporter does not work for this platform and/or configuration. This means that 'heap-unclassified' is not shown and the 'explicit' tree shows less memory than it should.\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
777.00 MB (100.0%) -- explicit\n\
|
||||
└──777.00 MB (100.0%) -- a\n\
|
||||
├──444.00 MB (57.14%) ── c\n\
|
||||
└──333.00 MB (42.86%) ── b\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
1.00 MB ── other1\n\
|
||||
100.00 MB ── resident\n\
|
||||
\n\
|
||||
End of 3rd\n\
|
||||
2nd\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
1,000.00 MB (100.0%) -- explicit\n\
|
||||
├────499.00 MB (49.90%) ── a/b/c [3]\n\
|
||||
├────200.00 MB (20.00%) ── compartment(compartment-url)\n\
|
||||
├────200.00 MB (20.00%) ── flip/the/backslashes\n\
|
||||
└────101.00 MB (10.10%) ── heap-unclassified\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
1,000.00 MB ── heap-allocated\n\
|
||||
100.00 MB ── heap-unallocated\n\
|
||||
666.00 MB ── other0\n\
|
||||
111.00 MB ── other1\n\
|
||||
\n\
|
||||
End of 2nd\n\
|
||||
5th\n\
|
||||
\n\
|
||||
WARNING: the following values are negative or unreasonably large.\n\
|
||||
\n\
|
||||
explicit/(3 tiny)/a/neg2\n\
|
||||
explicit/(3 tiny)/a/neg1\n\
|
||||
explicit/(3 tiny)/b/c\n\
|
||||
explicit/(3 tiny)/b/c/d\n\
|
||||
explicit/(3 tiny)/b/c/d/f \n\
|
||||
\n\
|
||||
This indicates a defect in one or more memory reporters. The invalid values are highlighted.\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
99.95 MB (100.0%) -- explicit\n\
|
||||
├──99.00 MB (99.05%) ── big\n\
|
||||
└───0.95 MB (00.95%) -- (3 tiny)\n\
|
||||
├──0.96 MB (00.96%) ── heap-unclassified\n\
|
||||
├──0.01 MB (00.01%) -- a\n\
|
||||
│ ├──0.04 MB (00.04%) ── pos\n\
|
||||
│ ├──-0.01 MB (-0.01%) ── neg2 [?!]\n\
|
||||
│ └──-0.02 MB (-0.02%) ── neg1 [?!]\n\
|
||||
└──-0.02 MB (-0.02%) -- b/c [?!]\n\
|
||||
├───0.01 MB (00.01%) ── g/h\n\
|
||||
├───0.00 MB (00.00%) ── i/j\n\
|
||||
└──-0.04 MB (-0.04%) -- d [?!]\n\
|
||||
├───0.02 MB (00.02%) ── e\n\
|
||||
└──-0.06 MB (-0.06%) ── f [?!]\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
100.00 MB ── heap-allocated\n\
|
||||
\n\
|
||||
End of 5th\n\
|
||||
";
|
||||
|
||||
let amvExpectedText =
|
||||
"\
|
||||
Main Process\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
653,876,224 B (100.0%) -- explicit\n\
|
||||
├──243,269,632 B (37.20%) -- b\n\
|
||||
│ ├───89,128,960 B (13.63%) ── a\n\
|
||||
│ ├───78,643,200 B (12.03%) ── b\n\
|
||||
│ └───75,497,472 B (11.55%) -- c\n\
|
||||
│ ├──73,400,320 B (11.23%) ── a\n\
|
||||
│ └───2,097,152 B (00.32%) ── b\n\
|
||||
├──232,783,872 B (35.60%) ── a\n\
|
||||
├──104,857,600 B (16.04%) -- c\n\
|
||||
│ ├───80,740,352 B (12.35%) ── other\n\
|
||||
│ └───24,117,248 B (03.69%) ── d [2]\n\
|
||||
├───24,117,248 B (03.69%) ── cc [2]\n\
|
||||
├───20,971,520 B (03.21%) -- f/g/h\n\
|
||||
│ ├──10,485,760 B (01.60%) ── i\n\
|
||||
│ └──10,485,760 B (01.60%) ── j\n\
|
||||
├───15,728,640 B (02.41%) -- g\n\
|
||||
│ ├───6,291,456 B (00.96%) ── a\n\
|
||||
│ ├───5,242,880 B (00.80%) ── b\n\
|
||||
│ └───4,194,304 B (00.64%) ── other\n\
|
||||
├───11,534,336 B (01.76%) ── heap-unclassified\n\
|
||||
├──────510,976 B (00.08%) ── d\n\
|
||||
└──────102,400 B (00.02%) ── e\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
5 (100.0%) -- compartments\n\
|
||||
├──3 (60.00%) -- user\n\
|
||||
│ ├──1 (20.00%) ── bar\n\
|
||||
│ ├──1 (20.00%) ── foo\n\
|
||||
│ └──1 (20.00%) ── https://very-long-url.com/very-long/oh-so-long/really-quite-long.html?a=2&b=3&c=4&d=5&e=abcdefghijklmnopqrstuvwxyz&f=123456789123456789123456789\n\
|
||||
└──2 (40.00%) -- system\n\
|
||||
├──1 (20.00%) ── bar\n\
|
||||
└──1 (20.00%) ── foo\n\
|
||||
\n\
|
||||
174,063,616 B (100.0%) -- other1\n\
|
||||
├──116,391,936 B (66.87%) ── a/b\n\
|
||||
└───57,671,680 B (33.13%) -- c\n\
|
||||
├──34,603,008 B (19.88%) ── e\n\
|
||||
└──23,068,672 B (13.25%) ── d\n\
|
||||
\n\
|
||||
20.20% (100.0%) -- other3\n\
|
||||
└──20.20% (100.0%) -- a/b/c/d\n\
|
||||
├──20.00% (99.01%) ── e\n\
|
||||
├───0.10% (00.50%) ── f\n\
|
||||
└───0.10% (00.50%) ── g [2]\n\
|
||||
\n\
|
||||
100,000 (100.0%) -- other6\n\
|
||||
├───99,999 (100.0%) ── big\n\
|
||||
└────────1 (00.00%) ── small\n\
|
||||
\n\
|
||||
0 B (100.0%) -- other7\n\
|
||||
└──0 B (100.0%) ── zero\n\
|
||||
\n\
|
||||
931,135,488 B ── explicit\n\
|
||||
524,288,000 B ── heap-allocated\n\
|
||||
104,857,600 B ── heap-unallocated\n\
|
||||
232,783,872 B ── other2\n\
|
||||
777 ── other3\n\
|
||||
888 ── other4 [2]\n\
|
||||
45.67% ── perc1\n\
|
||||
100.00% ── perc2\n\
|
||||
\n\
|
||||
End of Main Process\n\
|
||||
4th\n\
|
||||
\n\
|
||||
WARNING: the following values are negative or unreasonably large.\n\
|
||||
\n\
|
||||
explicit/js/compartment(http://too-big.com/)/stuff\n\
|
||||
explicit/neg1\n\
|
||||
explicit/heap-unclassified\n\
|
||||
other1\n\
|
||||
other2\n\
|
||||
other3\n\
|
||||
other4\n\
|
||||
other5 \n\
|
||||
\n\
|
||||
This indicates a defect in one or more memory reporters. The invalid values are highlighted.\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
102,760,448 B (100.0%) -- explicit\n\
|
||||
├──157,286,400 B (153.06%) ── js/compartment(http://too-big.com/)/stuff [?!]\n\
|
||||
├────5,242,880 B (05.10%) ── ok\n\
|
||||
├───-2,097,152 B (-2.04%) ── neg1 [?!]\n\
|
||||
└──-57,671,680 B (-56.12%) ── heap-unclassified [?!]\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
104,857,600 B ── heap-allocated\n\
|
||||
-111 B ── other1 [?!]\n\
|
||||
-232,783,872 B ── other2 [?!]\n\
|
||||
-333 ── other3 [?!]\n\
|
||||
-444 ── other4 [?!]\n\
|
||||
-5.55% ── other5 [?!]\n\
|
||||
666.66% ── other6\n\
|
||||
209,715,200 B ── resident\n\
|
||||
\n\
|
||||
End of 4th\n\
|
||||
3rd\n\
|
||||
\n\
|
||||
WARNING: the 'heap-allocated' memory reporter does not work for this platform and/or configuration. This means that 'heap-unclassified' is not shown and the 'explicit' tree shows less memory than it should.\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
814,743,552 B (100.0%) -- explicit\n\
|
||||
└──814,743,552 B (100.0%) -- a\n\
|
||||
├──465,567,744 B (57.14%) ── c\n\
|
||||
└──349,175,808 B (42.86%) ── b\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
1,048,576 B ── other1\n\
|
||||
104,857,600 B ── resident\n\
|
||||
\n\
|
||||
End of 3rd\n\
|
||||
2nd\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
1,048,576,000 B (100.0%) -- explicit\n\
|
||||
├────523,239,424 B (49.90%) ── a/b/c [3]\n\
|
||||
├────209,715,200 B (20.00%) ── compartment(compartment-url)\n\
|
||||
├────209,715,200 B (20.00%) ── flip/the/backslashes\n\
|
||||
└────105,906,176 B (10.10%) ── heap-unclassified\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
1,048,576,000 B ── heap-allocated\n\
|
||||
104,857,600 B ── heap-unallocated\n\
|
||||
698,351,616 B ── other0\n\
|
||||
116,391,936 B ── other1\n\
|
||||
\n\
|
||||
End of 2nd\n\
|
||||
5th\n\
|
||||
\n\
|
||||
WARNING: the following values are negative or unreasonably large.\n\
|
||||
\n\
|
||||
explicit/a/neg2\n\
|
||||
explicit/a/neg1\n\
|
||||
explicit/b/c\n\
|
||||
explicit/b/c/d\n\
|
||||
explicit/b/c/d/f \n\
|
||||
\n\
|
||||
This indicates a defect in one or more memory reporters. The invalid values are highlighted.\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
104,801,280 B (100.0%) -- explicit\n\
|
||||
├──103,809,024 B (99.05%) ── big\n\
|
||||
├────1,007,616 B (00.96%) ── heap-unclassified\n\
|
||||
├───────10,240 B (00.01%) -- a\n\
|
||||
│ ├──40,960 B (00.04%) ── pos\n\
|
||||
│ ├──-10,240 B (-0.01%) ── neg2 [?!]\n\
|
||||
│ └──-20,480 B (-0.02%) ── neg1 [?!]\n\
|
||||
└──────-25,600 B (-0.02%) -- b/c [?!]\n\
|
||||
├───10,240 B (00.01%) ── g/h\n\
|
||||
├────5,120 B (00.00%) ── i/j\n\
|
||||
└──-40,960 B (-0.04%) -- d [?!]\n\
|
||||
├───20,480 B (00.02%) ── e\n\
|
||||
└──-61,440 B (-0.06%) ── f [?!]\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
104,857,600 B ── heap-allocated\n\
|
||||
\n\
|
||||
End of 5th\n\
|
||||
";
|
||||
|
||||
function finish()
|
||||
{
|
||||
mgr.unblockRegistrationAndRestoreOriginalReporters();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
// Cut+paste the entire page and check that the cut text matches what we
|
||||
// expect. This tests the output in general and also that the cutting and
|
||||
// pasting works as expected.
|
||||
function test(aFrameId, aVerbose, aExpected, aNext) {
|
||||
SimpleTest.executeSoon(function() {
|
||||
ok(document.title === "about:memory", "document.title is correct");
|
||||
let mostRecentActual;
|
||||
let frame = document.getElementById(aFrameId);
|
||||
frame.focus();
|
||||
|
||||
// Set the verbose checkbox value and click the go button.
|
||||
let doc = frame.contentWindow.document;
|
||||
let measureButton = doc.getElementById("measureButton");
|
||||
let verbose = doc.getElementById("verbose");
|
||||
verbose.checked = aVerbose;
|
||||
measureButton.click();
|
||||
|
||||
SimpleTest.waitForClipboard(
|
||||
function(aActual) {
|
||||
mostRecentActual = aActual;
|
||||
let rslt = aActual.trim() === aExpected.trim();
|
||||
if (!rslt) {
|
||||
// Try copying again.
|
||||
synthesizeKey("A", {accelKey: true});
|
||||
synthesizeKey("C", {accelKey: true});
|
||||
}
|
||||
|
||||
return rslt;
|
||||
},
|
||||
function() {
|
||||
synthesizeKey("A", {accelKey: true});
|
||||
synthesizeKey("C", {accelKey: true});
|
||||
},
|
||||
aNext,
|
||||
function() {
|
||||
ok(false, "pasted text doesn't match for " + aFrameId);
|
||||
dump("******EXPECTED******\n");
|
||||
dump("<<<" + aExpected + ">>>\n");
|
||||
dump("*******ACTUAL*******\n");
|
||||
dump("<<<" + mostRecentActual + ">>>\n");
|
||||
dump("********************\n");
|
||||
finish();
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
SimpleTest.waitForFocus(function() {
|
||||
test(
|
||||
"amFrame",
|
||||
/* verbose = */ false,
|
||||
amExpectedText,
|
||||
function() {
|
||||
test(
|
||||
"amvFrame",
|
||||
/* verbose = */ true,
|
||||
amvExpectedText,
|
||||
function() {
|
||||
finish()
|
||||
}
|
||||
)
|
||||
}
|
||||
);
|
||||
});
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
|
@ -1,423 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
|
||||
<window title="about:memory"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
|
||||
<!-- This file tests the collapsing and expanding of sub-trees in
|
||||
about:memory. -->
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml"></body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
"use strict";
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
let mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
|
||||
getService(Ci.nsIMemoryReporterManager);
|
||||
|
||||
// Hide all the real reporters; we'll restore them at the end.
|
||||
mgr.blockRegistrationAndHideExistingReporters();
|
||||
|
||||
// Setup various fake-but-deterministic reporters.
|
||||
const KB = 1024;
|
||||
const MB = KB * KB;
|
||||
const HEAP = Ci.nsIMemoryReporter.KIND_HEAP;
|
||||
const OTHER = Ci.nsIMemoryReporter.KIND_OTHER;
|
||||
const BYTES = Ci.nsIMemoryReporter.UNITS_BYTES;
|
||||
|
||||
let hiPath = "explicit/h/i";
|
||||
let hi2Path = "explicit/h/i2";
|
||||
let jkPath = "explicit/j/k";
|
||||
let jk2Path = "explicit/j/k2";
|
||||
|
||||
let fakeReporters = [
|
||||
{ collectReports: function(aCbObj, aClosure, aAnonymize) {
|
||||
function f(aP, aK, aA) {
|
||||
aCbObj.callback("", aP, aK, BYTES, aA, "Desc.", aClosure);
|
||||
}
|
||||
f("heap-allocated", OTHER, 250 * MB);
|
||||
f("explicit/a/b", HEAP, 50 * MB);
|
||||
f("explicit/a/c/d", HEAP, 25 * MB);
|
||||
f("explicit/a/c/e", HEAP, 15 * MB);
|
||||
f("explicit/a/f", HEAP, 30 * MB);
|
||||
f("explicit/g", HEAP, 100 * MB);
|
||||
f(hiPath, HEAP, 10 * MB);
|
||||
f(hi2Path, HEAP, 9 * MB);
|
||||
f(jkPath, HEAP, 0.5 * MB);
|
||||
f(jk2Path, HEAP, 0.3 * MB);
|
||||
f("explicit/a/l/m", HEAP, 0.1 * MB);
|
||||
f("explicit/a/l/n", HEAP, 0.1 * MB);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
for (let i = 0; i < fakeReporters.length; i++) {
|
||||
mgr.registerStrongReporterEvenIfBlocked(fakeReporters[i]);
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<iframe id="amFrame" height="500" src="about:memory"></iframe>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
function finish()
|
||||
{
|
||||
mgr.unblockRegistrationAndRestoreOriginalReporters();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
// Click on the identified element, then cut+paste the entire page and
|
||||
// check that the cut text matches what we expect.
|
||||
function test(aId, aSwap, aExpected, aNext) {
|
||||
let win = document.getElementById("amFrame").contentWindow;
|
||||
if (aId) {
|
||||
let node = win.document.getElementById(aId);
|
||||
|
||||
// Yuk: clicking a button is easy; but for tree entries we need to
|
||||
// click on a child of the span identified via |id|.
|
||||
if (node.nodeName === "button") {
|
||||
if (aSwap) {
|
||||
// We swap hipath/hi2Path and jkPath/jk2Path just before updating, to
|
||||
// test what happens when significant nodes become insignificant and
|
||||
// vice versa.
|
||||
hiPath = "explicit/j/k";
|
||||
hi2Path = "explicit/j/k2";
|
||||
jkPath = "explicit/h/i";
|
||||
jk2Path = "explicit/h/i2";
|
||||
}
|
||||
node.click();
|
||||
} else {
|
||||
node.childNodes[0].click();
|
||||
}
|
||||
}
|
||||
|
||||
SimpleTest.executeSoon(function() {
|
||||
let mostRecentActual;
|
||||
document.getElementById("amFrame").focus();
|
||||
SimpleTest.waitForClipboard(
|
||||
function(aActual) {
|
||||
mostRecentActual = aActual;
|
||||
let rslt = aActual.trim() === aExpected.trim();
|
||||
if (!rslt) {
|
||||
// Try copying again.
|
||||
synthesizeKey("A", {accelKey: true});
|
||||
synthesizeKey("C", {accelKey: true});
|
||||
}
|
||||
|
||||
return rslt;
|
||||
},
|
||||
function() {
|
||||
synthesizeKey("A", {accelKey: true});
|
||||
synthesizeKey("C", {accelKey: true});
|
||||
},
|
||||
aNext,
|
||||
function() {
|
||||
ok(false, "pasted text doesn't match");
|
||||
dump("******EXPECTED******\n");
|
||||
dump(aExpected);
|
||||
dump("*******ACTUAL*******\n");
|
||||
dump(mostRecentActual);
|
||||
dump("********************\n");
|
||||
finish();
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// Returns a function that chains together one test() call per id.
|
||||
function chain(aIds) {
|
||||
let x = aIds.shift();
|
||||
if (x) {
|
||||
return function() { test(x.id, x.swap, x.expected, chain(aIds)); }
|
||||
} else {
|
||||
return function() { finish(); };
|
||||
}
|
||||
}
|
||||
|
||||
let startExpected =
|
||||
"\
|
||||
Main Process\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
250.00 MB (100.0%) -- explicit\n\
|
||||
├──120.20 MB (48.08%) -- a\n\
|
||||
│ ├───50.00 MB (20.00%) ── b\n\
|
||||
│ ├───40.00 MB (16.00%) -- c\n\
|
||||
│ │ ├──25.00 MB (10.00%) ── d\n\
|
||||
│ │ └──15.00 MB (06.00%) ── e\n\
|
||||
│ ├───30.00 MB (12.00%) ── f\n\
|
||||
│ └────0.20 MB (00.08%) ++ l\n\
|
||||
├──100.00 MB (40.00%) ── g\n\
|
||||
├───19.00 MB (07.60%) -- h\n\
|
||||
│ ├──10.00 MB (04.00%) ── i\n\
|
||||
│ └───9.00 MB (03.60%) ── i2\n\
|
||||
├───10.00 MB (04.00%) ── heap-unclassified\n\
|
||||
└────0.80 MB (00.32%) ++ j\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
250.00 MB ── heap-allocated\n\
|
||||
\n\
|
||||
End of Main Process\n\
|
||||
";
|
||||
|
||||
let acCollapsedExpected =
|
||||
"\
|
||||
Main Process\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
250.00 MB (100.0%) -- explicit\n\
|
||||
├──120.20 MB (48.08%) -- a\n\
|
||||
│ ├───50.00 MB (20.00%) ── b\n\
|
||||
│ ├───40.00 MB (16.00%) ++ c\n\
|
||||
│ ├───30.00 MB (12.00%) ── f\n\
|
||||
│ └────0.20 MB (00.08%) ++ l\n\
|
||||
├──100.00 MB (40.00%) ── g\n\
|
||||
├───19.00 MB (07.60%) -- h\n\
|
||||
│ ├──10.00 MB (04.00%) ── i\n\
|
||||
│ └───9.00 MB (03.60%) ── i2\n\
|
||||
├───10.00 MB (04.00%) ── heap-unclassified\n\
|
||||
└────0.80 MB (00.32%) ++ j\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
250.00 MB ── heap-allocated\n\
|
||||
\n\
|
||||
End of Main Process\n\
|
||||
";
|
||||
|
||||
let alExpandedExpected =
|
||||
"\
|
||||
Main Process\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
250.00 MB (100.0%) -- explicit\n\
|
||||
├──120.20 MB (48.08%) -- a\n\
|
||||
│ ├───50.00 MB (20.00%) ── b\n\
|
||||
│ ├───40.00 MB (16.00%) ++ c\n\
|
||||
│ ├───30.00 MB (12.00%) ── f\n\
|
||||
│ └────0.20 MB (00.08%) -- l\n\
|
||||
│ ├──0.10 MB (00.04%) ── m\n\
|
||||
│ └──0.10 MB (00.04%) ── n\n\
|
||||
├──100.00 MB (40.00%) ── g\n\
|
||||
├───19.00 MB (07.60%) -- h\n\
|
||||
│ ├──10.00 MB (04.00%) ── i\n\
|
||||
│ └───9.00 MB (03.60%) ── i2\n\
|
||||
├───10.00 MB (04.00%) ── heap-unclassified\n\
|
||||
└────0.80 MB (00.32%) ++ j\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
250.00 MB ── heap-allocated\n\
|
||||
\n\
|
||||
End of Main Process\n\
|
||||
";
|
||||
|
||||
let aCollapsedExpected =
|
||||
"\
|
||||
Main Process\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
250.00 MB (100.0%) -- explicit\n\
|
||||
├──120.20 MB (48.08%) ++ a\n\
|
||||
├──100.00 MB (40.00%) ── g\n\
|
||||
├───19.00 MB (07.60%) -- h\n\
|
||||
│ ├──10.00 MB (04.00%) ── i\n\
|
||||
│ └───9.00 MB (03.60%) ── i2\n\
|
||||
├───10.00 MB (04.00%) ── heap-unclassified\n\
|
||||
└────0.80 MB (00.32%) ++ j\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
250.00 MB ── heap-allocated\n\
|
||||
\n\
|
||||
End of Main Process\n\
|
||||
";
|
||||
|
||||
let hCollapsedExpected =
|
||||
"\
|
||||
Main Process\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
250.00 MB (100.0%) -- explicit\n\
|
||||
├──120.20 MB (48.08%) ++ a\n\
|
||||
├──100.00 MB (40.00%) ── g\n\
|
||||
├───19.00 MB (07.60%) ++ h\n\
|
||||
├───10.00 MB (04.00%) ── heap-unclassified\n\
|
||||
└────0.80 MB (00.32%) ++ j\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
250.00 MB ── heap-allocated\n\
|
||||
\n\
|
||||
End of Main Process\n\
|
||||
";
|
||||
|
||||
let jExpandedExpected =
|
||||
"\
|
||||
Main Process\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
250.00 MB (100.0%) -- explicit\n\
|
||||
├──120.20 MB (48.08%) ++ a\n\
|
||||
├──100.00 MB (40.00%) ── g\n\
|
||||
├───19.00 MB (07.60%) ++ h\n\
|
||||
├───10.00 MB (04.00%) ── heap-unclassified\n\
|
||||
└────0.80 MB (00.32%) -- j\n\
|
||||
├──0.50 MB (00.20%) ── k\n\
|
||||
└──0.30 MB (00.12%) ── k2\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
250.00 MB ── heap-allocated\n\
|
||||
\n\
|
||||
End of Main Process\n\
|
||||
";
|
||||
|
||||
// The important thing here is that two values have been swapped.
|
||||
// explicit/h/i should remain collapsed, and explicit/j/k should remain
|
||||
// expanded. See bug 724863.
|
||||
let updatedExpected =
|
||||
"\
|
||||
Main Process\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
250.00 MB (100.0%) -- explicit\n\
|
||||
├──120.20 MB (48.08%) ++ a\n\
|
||||
├──100.00 MB (40.00%) ── g\n\
|
||||
├───19.00 MB (07.60%) -- j\n\
|
||||
│ ├──10.00 MB (04.00%) ── k\n\
|
||||
│ └───9.00 MB (03.60%) ── k2\n\
|
||||
├───10.00 MB (04.00%) ── heap-unclassified\n\
|
||||
└────0.80 MB (00.32%) ++ h\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
250.00 MB ── heap-allocated\n\
|
||||
\n\
|
||||
End of Main Process\n\
|
||||
";
|
||||
|
||||
let aExpandedExpected =
|
||||
"\
|
||||
Main Process\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
250.00 MB (100.0%) -- explicit\n\
|
||||
├──120.20 MB (48.08%) -- a\n\
|
||||
│ ├───50.00 MB (20.00%) ── b\n\
|
||||
│ ├───40.00 MB (16.00%) ++ c\n\
|
||||
│ ├───30.00 MB (12.00%) ── f\n\
|
||||
│ └────0.20 MB (00.08%) -- l\n\
|
||||
│ ├──0.10 MB (00.04%) ── m\n\
|
||||
│ └──0.10 MB (00.04%) ── n\n\
|
||||
├──100.00 MB (40.00%) ── g\n\
|
||||
├───19.00 MB (07.60%) -- j\n\
|
||||
│ ├──10.00 MB (04.00%) ── k\n\
|
||||
│ └───9.00 MB (03.60%) ── k2\n\
|
||||
├───10.00 MB (04.00%) ── heap-unclassified\n\
|
||||
└────0.80 MB (00.32%) ++ h\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
250.00 MB ── heap-allocated\n\
|
||||
\n\
|
||||
End of Main Process\n\
|
||||
";
|
||||
|
||||
let acExpandedExpected =
|
||||
"\
|
||||
Main Process\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
250.00 MB (100.0%) -- explicit\n\
|
||||
├──120.20 MB (48.08%) -- a\n\
|
||||
│ ├───50.00 MB (20.00%) ── b\n\
|
||||
│ ├───40.00 MB (16.00%) -- c\n\
|
||||
│ │ ├──25.00 MB (10.00%) ── d\n\
|
||||
│ │ └──15.00 MB (06.00%) ── e\n\
|
||||
│ ├───30.00 MB (12.00%) ── f\n\
|
||||
│ └────0.20 MB (00.08%) -- l\n\
|
||||
│ ├──0.10 MB (00.04%) ── m\n\
|
||||
│ └──0.10 MB (00.04%) ── n\n\
|
||||
├──100.00 MB (40.00%) ── g\n\
|
||||
├───19.00 MB (07.60%) -- j\n\
|
||||
│ ├──10.00 MB (04.00%) ── k\n\
|
||||
│ └───9.00 MB (03.60%) ── k2\n\
|
||||
├───10.00 MB (04.00%) ── heap-unclassified\n\
|
||||
└────0.80 MB (00.32%) ++ h\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
250.00 MB ── heap-allocated\n\
|
||||
\n\
|
||||
End of Main Process\n\
|
||||
";
|
||||
|
||||
let alCollapsedExpected =
|
||||
"\
|
||||
Main Process\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
250.00 MB (100.0%) -- explicit\n\
|
||||
├──120.20 MB (48.08%) -- a\n\
|
||||
│ ├───50.00 MB (20.00%) ── b\n\
|
||||
│ ├───40.00 MB (16.00%) -- c\n\
|
||||
│ │ ├──25.00 MB (10.00%) ── d\n\
|
||||
│ │ └──15.00 MB (06.00%) ── e\n\
|
||||
│ ├───30.00 MB (12.00%) ── f\n\
|
||||
│ └────0.20 MB (00.08%) ++ l\n\
|
||||
├──100.00 MB (40.00%) ── g\n\
|
||||
├───19.00 MB (07.60%) -- j\n\
|
||||
│ ├──10.00 MB (04.00%) ── k\n\
|
||||
│ └───9.00 MB (03.60%) ── k2\n\
|
||||
├───10.00 MB (04.00%) ── heap-unclassified\n\
|
||||
└────0.80 MB (00.32%) ++ h\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
250.00 MB ── heap-allocated\n\
|
||||
\n\
|
||||
End of Main Process\n\
|
||||
";
|
||||
|
||||
// Test the following cases:
|
||||
// - explicit/a/c is significant, we collapse it, it's unchanged upon
|
||||
// update, we re-expand it
|
||||
// - explicit/a/l is insignificant, we expand it, it's unchanged upon
|
||||
// update, we re-collapse it
|
||||
// - explicit/a is significant, we collapse it (which hides its
|
||||
// sub-trees), it's unchanged upon update, we re-expand it
|
||||
// - explicit/h is significant, we collapse it, it becomes insignificant
|
||||
// upon update (and should remain collapsed)
|
||||
// - explicit/j is insignificant, we expand it, it becomes significant
|
||||
// upon update (and should remain expanded)
|
||||
//
|
||||
let idsToClick = [
|
||||
{ id: "measureButton", swap: 0, expected: startExpected },
|
||||
{ id: "Main Process:explicit/a/c", swap: 0, expected: acCollapsedExpected },
|
||||
{ id: "Main Process:explicit/a/l", swap: 0, expected: alExpandedExpected },
|
||||
{ id: "Main Process:explicit/a", swap: 0, expected: aCollapsedExpected },
|
||||
{ id: "Main Process:explicit/h", swap: 0, expected: hCollapsedExpected },
|
||||
{ id: "Main Process:explicit/j", swap: 0, expected: jExpandedExpected },
|
||||
{ id: "measureButton", swap: 1, expected: updatedExpected },
|
||||
{ id: "Main Process:explicit/a", swap: 0, expected: aExpandedExpected },
|
||||
{ id: "Main Process:explicit/a/c", swap: 0, expected: acExpandedExpected },
|
||||
{ id: "Main Process:explicit/a/l", swap: 0, expected: alCollapsedExpected }
|
||||
];
|
||||
|
||||
SimpleTest.waitForFocus(chain(idsToClick));
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
|
@ -1,515 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
|
||||
<window title="about:memory"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
|
||||
<!-- This file tests the saving and loading of memory reports to/from file in
|
||||
about:memory. -->
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml"></body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
"use strict";
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
let mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
|
||||
getService(Ci.nsIMemoryReporterManager);
|
||||
|
||||
// Hide all the real reporters; we'll restore them at the end.
|
||||
mgr.blockRegistrationAndHideExistingReporters();
|
||||
|
||||
// Setup a minimal number of fake reporters.
|
||||
const KB = 1024;
|
||||
const MB = KB * KB;
|
||||
const HEAP = Ci.nsIMemoryReporter.KIND_HEAP;
|
||||
const OTHER = Ci.nsIMemoryReporter.KIND_OTHER;
|
||||
const BYTES = Ci.nsIMemoryReporter.UNITS_BYTES;
|
||||
|
||||
let fakeReporters = [
|
||||
{ collectReports: function(aCbObj, aClosure, aAnonymize) {
|
||||
function f(aP, aK, aA, aD) {
|
||||
aCbObj.callback("", aP, aK, BYTES, aA, aD, aClosure);
|
||||
}
|
||||
f("heap-allocated", OTHER, 250 * MB, "Heap allocated.");
|
||||
f("explicit/a/b", HEAP, 50 * MB, "A b.");
|
||||
f("other/a", OTHER, 0.2 * MB, "Other a.");
|
||||
f("other/b", OTHER, 0.1 * MB, "Other b.");
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
for (let i = 0; i < fakeReporters.length; i++) {
|
||||
mgr.registerStrongReporterEvenIfBlocked(fakeReporters[i]);
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<iframe id="amFrame" height="400" src="about:memory"></iframe>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
function finish()
|
||||
{
|
||||
mgr.unblockRegistrationAndRestoreOriginalReporters();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
// Load the given file into the frame, then copy+paste the entire frame and
|
||||
// check that the cut text matches what we expect.
|
||||
function test(aFilename, aFilename2, aExpected, aDumpFirst, aVerbose, aNext) {
|
||||
let frame = document.getElementById("amFrame");
|
||||
frame.focus();
|
||||
|
||||
let doc = frame.contentWindow.document;
|
||||
let verbosity = doc.getElementById("verbose");
|
||||
verbosity.checked = aVerbose;
|
||||
|
||||
function getFilePath(aFilename) {
|
||||
let file = Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Components.interfaces.nsIProperties)
|
||||
.get("CurWorkD", Components.interfaces.nsIFile);
|
||||
file.append("chrome");
|
||||
file.append("toolkit");
|
||||
file.append("components");
|
||||
file.append("aboutmemory");
|
||||
file.append("tests");
|
||||
file.append(aFilename);
|
||||
return file.path;
|
||||
}
|
||||
|
||||
let filePath = getFilePath(aFilename);
|
||||
|
||||
let e = document.createEvent('Event');
|
||||
e.initEvent('change', true, true);
|
||||
|
||||
function check() {
|
||||
// Initialize the clipboard contents.
|
||||
SpecialPowers.clipboardCopyString("initial clipboard value");
|
||||
|
||||
let numFailures = 0, maxFailures = 30;
|
||||
|
||||
// Because the file load is async, we don't know when it will finish and
|
||||
// the output will show up. So we poll.
|
||||
function copyPasteAndCheck() {
|
||||
// Copy and paste frame contents, and filter out non-deterministic
|
||||
// differences.
|
||||
synthesizeKey("A", {accelKey: true});
|
||||
synthesizeKey("C", {accelKey: true});
|
||||
let actual = SpecialPowers.getClipboardData("text/unicode");
|
||||
actual = actual.replace(/\(pid \d+\)/g, "(pid NNN)");
|
||||
|
||||
if (actual.trim() === aExpected.trim()) {
|
||||
SimpleTest.ok(true, "Clipboard has the expected contents");
|
||||
aNext();
|
||||
} else {
|
||||
numFailures++;
|
||||
if (numFailures === maxFailures) {
|
||||
ok(false, "pasted text doesn't match");
|
||||
dump("******EXPECTED******\n");
|
||||
dump(aExpected);
|
||||
dump("*******ACTUAL*******\n");
|
||||
dump(actual);
|
||||
dump("********************\n");
|
||||
finish();
|
||||
} else {
|
||||
setTimeout(copyPasteAndCheck, 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
copyPasteAndCheck();
|
||||
}
|
||||
|
||||
if (!aFilename2) {
|
||||
function loadAndCheck() {
|
||||
let fileInput1 =
|
||||
frame.contentWindow.document.getElementById("fileInput1");
|
||||
fileInput1.value = filePath; // this works because it's a chrome test
|
||||
|
||||
fileInput1.dispatchEvent(e);
|
||||
check();
|
||||
}
|
||||
|
||||
if (aDumpFirst) {
|
||||
let dumper = Cc["@mozilla.org/memory-info-dumper;1"].
|
||||
getService(Ci.nsIMemoryInfoDumper);
|
||||
dumper.dumpMemoryReportsToNamedFile(filePath, loadAndCheck, null,
|
||||
/* anonymize = */ false);
|
||||
} else {
|
||||
loadAndCheck();
|
||||
}
|
||||
|
||||
} else {
|
||||
let fileInput2 =
|
||||
frame.contentWindow.document.getElementById("fileInput2");
|
||||
fileInput2.value = filePath; // this works because it's a chrome test
|
||||
|
||||
// Hack alert: fileInput2's onchange handler calls fileInput2.click().
|
||||
// But we don't want that to happen, because we want to bypass the file
|
||||
// picker for the test. So we set |e.skipClick|, which causes
|
||||
// fileInput2.click() to be skipped, and dispatch the second change event
|
||||
// directly ourselves.
|
||||
|
||||
e.skipClick = true;
|
||||
fileInput2.dispatchEvent(e);
|
||||
|
||||
let filePath2 = getFilePath(aFilename2);
|
||||
fileInput2.value = filePath2; // this works because it's a chrome test
|
||||
|
||||
let e2 = document.createEvent('Event');
|
||||
e2.initEvent('change', true, true);
|
||||
fileInput2.dispatchEvent(e);
|
||||
|
||||
check();
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a function that chains together multiple test() calls.
|
||||
function chain(aPieces) {
|
||||
let x = aPieces.shift();
|
||||
if (x) {
|
||||
return function() { test(x.filename, x.filename2, x.expected, x.dumpFirst, x.verbose, chain(aPieces)); }
|
||||
} else {
|
||||
return function() { finish(); };
|
||||
}
|
||||
}
|
||||
|
||||
let expectedGood =
|
||||
"\
|
||||
Explicit-only process\n\
|
||||
\n\
|
||||
WARNING: the 'heap-allocated' memory reporter does not work for this platform and/or configuration. This means that 'heap-unclassified' is not shown and the 'explicit' tree shows less memory than it should.\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
100,000 B (100.0%) -- explicit\n\
|
||||
└──100,000 B (100.0%) ── a/b\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
End of Explicit-only process\n\
|
||||
Heap-unclassified process\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
262,144,000 B (100.0%) -- explicit\n\
|
||||
├──209,715,200 B (80.00%) ── heap-unclassified\n\
|
||||
└───52,428,800 B (20.00%) ── a/b\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
262,144,000 B ── heap-allocated\n\
|
||||
\n\
|
||||
End of Heap-unclassified process\n\
|
||||
Main Process (pid NNN)\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
262,144,000 B (100.0%) -- explicit\n\
|
||||
├──209,715,200 B (80.00%) ── heap-unclassified\n\
|
||||
└───52,428,800 B (20.00%) ── a/b\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
1,024 B (100.0%) -- compartments\n\
|
||||
└──1,024 B (100.0%) ── system/a\n\
|
||||
\n\
|
||||
1,024 B (100.0%) -- ghost-windows\n\
|
||||
└──1,024 B (100.0%) ── a\n\
|
||||
\n\
|
||||
314,572 B (100.0%) -- other\n\
|
||||
├──209,715 B (66.67%) ── a\n\
|
||||
└──104,857 B (33.33%) ── b\n\
|
||||
\n\
|
||||
1,024 B (100.0%) -- pss\n\
|
||||
└──1,024 B (100.0%) ── a\n\
|
||||
\n\
|
||||
1,024 B (100.0%) -- rss\n\
|
||||
└──1,024 B (100.0%) ── a\n\
|
||||
\n\
|
||||
1,024 B (100.0%) -- size\n\
|
||||
└──1,024 B (100.0%) ── a\n\
|
||||
\n\
|
||||
1,024 B (100.0%) -- swap\n\
|
||||
└──1,024 B (100.0%) ── a\n\
|
||||
\n\
|
||||
262,144,000 B ── heap-allocated\n\
|
||||
\n\
|
||||
End of Main Process (pid NNN)\n\
|
||||
Other-only process\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
200,000 B (100.0%) -- a\n\
|
||||
├──100,000 B (50.00%) ── b\n\
|
||||
└──100,000 B (50.00%) ── c\n\
|
||||
\n\
|
||||
500,000 B ── heap-allocated\n\
|
||||
\n\
|
||||
End of Other-only process\n\
|
||||
";
|
||||
|
||||
let expectedGood2 =
|
||||
"\
|
||||
Main Process (pid NNN)\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
262,144,000 B (100.0%) -- explicit\n\
|
||||
├──209,715,200 B (80.00%) ── heap-unclassified\n\
|
||||
└───52,428,800 B (20.00%) ── a/b\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
314,572 B (100.0%) -- other\n\
|
||||
├──209,715 B (66.67%) ── a\n\
|
||||
└──104,857 B (33.33%) ── b\n\
|
||||
\n\
|
||||
262,144,000 B ── heap-allocated\n\
|
||||
\n\
|
||||
End of Main Process (pid NNN)\n\
|
||||
";
|
||||
|
||||
// This is the output for a malformed data file.
|
||||
let expectedBad =
|
||||
"\
|
||||
Error: Invalid memory report(s): missing 'hasMozMallocUsableSize' property\
|
||||
";
|
||||
|
||||
// This is the output for a non-verbose diff.
|
||||
let expectedDiffNonVerbose =
|
||||
"\
|
||||
P\n\
|
||||
\n\
|
||||
WARNING: the 'heap-allocated' memory reporter does not work for this platform and/or configuration. This means that 'heap-unclassified' is not shown and the 'explicit' tree shows less memory than it should.\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
-0.01 MB (100.0%) -- explicit\n\
|
||||
├──-0.01 MB (99.95%) ── storage/prefixset/goog-phish-shavar\n\
|
||||
└──-0.00 MB (00.05%) ++ (2 tiny)\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
0.96 MB (100.0%) -- a\n\
|
||||
├──0.95 MB (99.80%) ── b\n\
|
||||
├──0.00 MB (00.10%) -- c\n\
|
||||
│ ├──-0.95 MB (-99.70%) ── e\n\
|
||||
│ ├──0.95 MB (99.60%) ── d\n\
|
||||
│ └──0.00 MB (00.20%) ++ (2 tiny)\n\
|
||||
└──0.00 MB (00.10%) ── h\n\
|
||||
\n\
|
||||
0.00 MB ── canvas-2d-pixel-bytes [2] [+]\n\
|
||||
-0.00 MB ── foobar [-]\n\
|
||||
\n\
|
||||
End of P\n\
|
||||
P2 (pid NNN)\n\
|
||||
\n\
|
||||
WARNING: the 'heap-allocated' memory reporter does not work for this platform and/or configuration. This means that 'heap-unclassified' is not shown and the 'explicit' tree shows less memory than it should.\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
0.00 MB (100.0%) -- explicit\n\
|
||||
└──0.00 MB (100.0%) ── window-objects/top(bar.com, id=NNN)/...\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
0.00 MB (100.0%) -- p3\n\
|
||||
└──0.00 MB (100.0%) ── zone(0xNNN)/p3\n\
|
||||
\n\
|
||||
0.00 MB (100.0%) -- p4\n\
|
||||
└──0.00 MB (100.0%) ── js-zone(0xNNN)/p4\n\
|
||||
\n\
|
||||
0.00 MB (100.0%) -- p5\n\
|
||||
└──0.00 MB (100.0%) ── worker(foo.com, 0xNNN)/p5\n\
|
||||
\n\
|
||||
0.00 MB (100.0%) -- p6\n\
|
||||
└──0.00 MB (100.0%) ── z-moz-nullprincipal:{NNNNNNNN-NNNN-NNNN-NNNN-NNNNNNNNNNNN}/p6\n\
|
||||
\n\
|
||||
0.00 MB (100.0%) -- p7\n\
|
||||
└──0.00 MB (100.0%) ── js-main-runtime-compartments/system/jar:file:///.../omni.ja!/p7\n\
|
||||
\n\
|
||||
0.00 MB ── p1 (pid NNN)\n\
|
||||
0.00 MB ── p2 (blah, pid=NNN)\n\
|
||||
\n\
|
||||
End of P2 (pid NNN)\n\
|
||||
P3\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
-0.00 MB ── p3 [-]\n\
|
||||
\n\
|
||||
End of P3\n\
|
||||
P4\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
0.00 MB ── p4 [+]\n\
|
||||
\n\
|
||||
End of P4\n\
|
||||
P7\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
0.00 MB (100.0%) -- p7\n\
|
||||
├──0.00 MB (57.14%) ── c [+]\n\
|
||||
└──0.00 MB (42.86%) ── b [+]\n\
|
||||
\n\
|
||||
-0.00 MB ── p7 [-]\n\
|
||||
\n\
|
||||
End of P7\n\
|
||||
P8\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
-0.00 MB (100.0%) -- p8\n\
|
||||
└──-0.00 MB (100.0%) -- a\n\
|
||||
├──-0.00 MB (50.00%) -- b\n\
|
||||
│ ├──-0.00 MB (31.82%) -- c\n\
|
||||
│ │ ├──-0.00 MB (18.18%) ── e [-]\n\
|
||||
│ │ └──-0.00 MB (13.64%) ── d [-]\n\
|
||||
│ ├──-0.00 MB (22.73%) ── f [-]\n\
|
||||
│ └───0.00 MB (-4.55%) ── (fake child) [!]\n\
|
||||
└──-0.00 MB (50.00%) -- g\n\
|
||||
├──-0.00 MB (31.82%) ── i [-]\n\
|
||||
├──-0.00 MB (27.27%) ── h [-]\n\
|
||||
└───0.00 MB (-9.09%) ── (fake child) [!]\n\
|
||||
\n\
|
||||
End of P8\n\
|
||||
";
|
||||
|
||||
// This is the output for a verbose diff.
|
||||
let expectedDiffVerbose =
|
||||
"\
|
||||
P\n\
|
||||
\n\
|
||||
WARNING: the 'heap-allocated' memory reporter does not work for this platform and/or configuration. This means that 'heap-unclassified' is not shown and the 'explicit' tree shows less memory than it should.\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
-10,005 B (100.0%) -- explicit\n\
|
||||
├──-10,000 B (99.95%) ── storage/prefixset/goog-phish-shavar\n\
|
||||
├───────-6 B (00.06%) ── spell-check [2]\n\
|
||||
└────────1 B (-0.01%) ── xpcom/category-manager\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
1,002,000 B (100.0%) -- a\n\
|
||||
├──1,000,000 B (99.80%) ── b\n\
|
||||
├──────1,000 B (00.10%) -- c\n\
|
||||
│ ├──-999,000 B (-99.70%) ── e\n\
|
||||
│ ├──998,000 B (99.60%) ── d\n\
|
||||
│ ├──1,000 B (00.10%) ── f\n\
|
||||
│ └──1,000 B (00.10%) ── g\n\
|
||||
└──────1,000 B (00.10%) ── h\n\
|
||||
\n\
|
||||
3,000 B ── canvas-2d-pixel-bytes [2] [+]\n\
|
||||
-100 B ── foobar [-]\n\
|
||||
\n\
|
||||
End of P\n\
|
||||
P2 (pid NNN)\n\
|
||||
\n\
|
||||
WARNING: the 'heap-allocated' memory reporter does not work for this platform and/or configuration. This means that 'heap-unclassified' is not shown and the 'explicit' tree shows less memory than it should.\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
11 B (100.0%) -- explicit\n\
|
||||
└──11 B (100.0%) ── window-objects/top(bar.com, id=NNN)/...\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
11 B (100.0%) -- p3\n\
|
||||
└──11 B (100.0%) ── zone(0xNNN)/p3\n\
|
||||
\n\
|
||||
11 B (100.0%) -- p4\n\
|
||||
└──11 B (100.0%) ── js-zone(0xNNN)/p4\n\
|
||||
\n\
|
||||
11 B (100.0%) -- p5\n\
|
||||
└──11 B (100.0%) ── worker(foo.com, 0xNNN)/p5\n\
|
||||
\n\
|
||||
11 B (100.0%) -- p6\n\
|
||||
└──11 B (100.0%) ── z-moz-nullprincipal:{NNNNNNNN-NNNN-NNNN-NNNN-NNNNNNNNNNNN}/p6\n\
|
||||
\n\
|
||||
11 B (100.0%) -- p7\n\
|
||||
└──11 B (100.0%) ── js-main-runtime-compartments/system/jar:file:///.../omni.ja!/p7\n\
|
||||
\n\
|
||||
11 B ── p1 (pid NNN)\n\
|
||||
11 B ── p2 (blah, pid=NNN)\n\
|
||||
\n\
|
||||
End of P2 (pid NNN)\n\
|
||||
P3\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
-55 B ── p3 [-]\n\
|
||||
\n\
|
||||
End of P3\n\
|
||||
P4\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
66 B ── p4 [+]\n\
|
||||
\n\
|
||||
End of P4\n\
|
||||
P7\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
7 B (100.0%) -- p7\n\
|
||||
├──4 B (57.14%) ── c [+]\n\
|
||||
└──3 B (42.86%) ── b [+]\n\
|
||||
\n\
|
||||
-5 B ── p7 [-]\n\
|
||||
\n\
|
||||
End of P7\n\
|
||||
P8\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
-22 B (100.0%) -- p8\n\
|
||||
└──-22 B (100.0%) -- a\n\
|
||||
├──-11 B (50.00%) -- b\n\
|
||||
│ ├───-7 B (31.82%) -- c\n\
|
||||
│ │ ├──-4 B (18.18%) ── e [-]\n\
|
||||
│ │ └──-3 B (13.64%) ── d [-]\n\
|
||||
│ ├───-5 B (22.73%) ── f [-]\n\
|
||||
│ └────1 B (-4.55%) ── (fake child) [!]\n\
|
||||
└──-11 B (50.00%) -- g\n\
|
||||
├───-7 B (31.82%) ── i [-]\n\
|
||||
├───-6 B (27.27%) ── h [-]\n\
|
||||
└────2 B (-9.09%) ── (fake child) [!]\n\
|
||||
\n\
|
||||
End of P8\n\
|
||||
";
|
||||
|
||||
// This is the output for the crash reports diff.
|
||||
let expectedDiff2 =
|
||||
"\
|
||||
Main Process (pid NNN)\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
1 B ── heap-allocated\n\
|
||||
\n\
|
||||
End of Main Process (pid NNN)\n\
|
||||
";
|
||||
|
||||
let frames = [
|
||||
// This loads a pre-existing memory reports file that is valid.
|
||||
{ filename: "memory-reports-good.json", expected: expectedGood, dumpFirst: false, verbose: true },
|
||||
|
||||
// This loads a pre-existing crash dump file that is valid.
|
||||
{ filename: "crash-dump-good.json", expected: expectedGood2, dumpFirst: false, verbose: true },
|
||||
|
||||
// This dumps to a file and then reads it back in. (The result is the same
|
||||
// as the previous test.)
|
||||
{ filename: "memory-reports-dumped.json.gz", expected: expectedGood2, dumpFirst: true, verbose: true },
|
||||
|
||||
// This loads a pre-existing file that is invalid.
|
||||
{ filename: "memory-reports-bad.json", expected: expectedBad, dumpFirst: false, verbose: true },
|
||||
|
||||
// This diffs two pre-existing memory reports files.
|
||||
{ filename: "memory-reports-diff1.json", filename2: "memory-reports-diff2.json", expected: expectedDiffNonVerbose, dumpFirst: false, verbose: false },
|
||||
|
||||
// Ditto.
|
||||
{ filename: "memory-reports-diff1.json", filename2: "memory-reports-diff2.json", expected: expectedDiffVerbose, dumpFirst: false, verbose: true },
|
||||
|
||||
// This diffs two pre-existing crash report files.
|
||||
{ filename: "crash-dump-diff1.json", filename2: "crash-dump-diff2.json", expected: expectedDiff2, dumpFirst: false, verbose: true }
|
||||
];
|
||||
|
||||
SimpleTest.waitForFocus(chain(frames));
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
|
@ -1,179 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
|
||||
<window title="about:memory"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
|
||||
<!-- This file tests the loading of memory reports from file when specified
|
||||
in about:memory's URL (via the "file=" suffix). -->
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml"></body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
"use strict";
|
||||
|
||||
function makePathname(aFilename) {
|
||||
let file = Components.classes["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Components.interfaces.nsIProperties)
|
||||
.get("CurWorkD", Components.interfaces.nsIFile);
|
||||
file.append("chrome");
|
||||
file.append("toolkit");
|
||||
file.append("components");
|
||||
file.append("aboutmemory");
|
||||
file.append("tests");
|
||||
file.append(aFilename);
|
||||
return file.path;
|
||||
}
|
||||
|
||||
// Load the given file into the frame, then copy+paste the entire frame and
|
||||
// check that the cut text matches what we expect.
|
||||
function test(aFilename, aExpected, aNext) {
|
||||
let frame = document.createElementNS("http://www.w3.org/1999/xhtml", "iframe")
|
||||
frame.height = 300;
|
||||
frame.src = "about:memory?file=" + makePathname(aFilename);
|
||||
document.documentElement.appendChild(frame);
|
||||
frame.focus();
|
||||
|
||||
// Initialize the clipboard contents.
|
||||
SpecialPowers.clipboardCopyString("initial clipboard value");
|
||||
|
||||
let numFailures = 0, maxFailures = 30;
|
||||
|
||||
// Because the file load is async, we don't know when it will finish and
|
||||
// the output will show up. So we poll.
|
||||
function copyPasteAndCheck() {
|
||||
// Copy and paste frame contents, and filter out non-deterministic
|
||||
// differences.
|
||||
synthesizeKey("A", {accelKey: true});
|
||||
synthesizeKey("C", {accelKey: true});
|
||||
let actual = SpecialPowers.getClipboardData("text/unicode");
|
||||
actual = actual.replace(/\(pid \d+\)/, "(pid NNN)");
|
||||
|
||||
if (actual.trim() === aExpected.trim()) {
|
||||
SimpleTest.ok(true, "Clipboard has the expected contents");
|
||||
aNext();
|
||||
} else {
|
||||
numFailures++;
|
||||
if (numFailures === maxFailures) {
|
||||
ok(false, "pasted text doesn't match");
|
||||
dump("******EXPECTED******\n");
|
||||
dump(aExpected);
|
||||
dump("*******ACTUAL*******\n");
|
||||
dump(actual);
|
||||
dump("********************\n");
|
||||
SimpleTest.finish();
|
||||
} else {
|
||||
setTimeout(copyPasteAndCheck, 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
copyPasteAndCheck();
|
||||
}
|
||||
|
||||
// Returns a function that chains together multiple test() calls.
|
||||
function chain(aFrameIds) {
|
||||
let x = aFrameIds.shift();
|
||||
if (x) {
|
||||
return function() { test(x.filename, x.expected, chain(aFrameIds)); }
|
||||
} else {
|
||||
return function() { SimpleTest.finish(); };
|
||||
}
|
||||
}
|
||||
|
||||
// This is pretty simple output, but that's ok; this file is about testing
|
||||
// the loading of data from file. If we got this far, we're doing fine.
|
||||
let expectedGood =
|
||||
"\
|
||||
Explicit-only process\n\
|
||||
\n\
|
||||
WARNING: the 'heap-allocated' memory reporter does not work for this platform and/or configuration. This means that 'heap-unclassified' is not shown and the 'explicit' tree shows less memory than it should.\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
0.10 MB (100.0%) -- explicit\n\
|
||||
└──0.10 MB (100.0%) ── a/b\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
End of Explicit-only process\n\
|
||||
Heap-unclassified process\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
250.00 MB (100.0%) -- explicit\n\
|
||||
├──200.00 MB (80.00%) ── heap-unclassified\n\
|
||||
└───50.00 MB (20.00%) ── a/b\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
250.00 MB ── heap-allocated\n\
|
||||
\n\
|
||||
End of Heap-unclassified process\n\
|
||||
Main Process (pid NNN)\n\
|
||||
Explicit Allocations\n\
|
||||
\n\
|
||||
250.00 MB (100.0%) -- explicit\n\
|
||||
├──200.00 MB (80.00%) ── heap-unclassified\n\
|
||||
└───50.00 MB (20.00%) ── a/b\n\
|
||||
\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
0.00 MB (100.0%) -- compartments\n\
|
||||
└──0.00 MB (100.0%) ── system/a\n\
|
||||
\n\
|
||||
0.00 MB (100.0%) -- ghost-windows\n\
|
||||
└──0.00 MB (100.0%) ── a\n\
|
||||
\n\
|
||||
0.30 MB (100.0%) -- other\n\
|
||||
├──0.20 MB (66.67%) ── a\n\
|
||||
└──0.10 MB (33.33%) ── b\n\
|
||||
\n\
|
||||
0.00 MB (100.0%) -- pss\n\
|
||||
└──0.00 MB (100.0%) ── a\n\
|
||||
\n\
|
||||
0.00 MB (100.0%) -- rss\n\
|
||||
└──0.00 MB (100.0%) ── a\n\
|
||||
\n\
|
||||
0.00 MB (100.0%) -- size\n\
|
||||
└──0.00 MB (100.0%) ── a\n\
|
||||
\n\
|
||||
0.00 MB (100.0%) -- swap\n\
|
||||
└──0.00 MB (100.0%) ── a\n\
|
||||
\n\
|
||||
250.00 MB ── heap-allocated\n\
|
||||
\n\
|
||||
End of Main Process (pid NNN)\n\
|
||||
Other-only process\n\
|
||||
Other Measurements\n\
|
||||
\n\
|
||||
0.19 MB (100.0%) -- a\n\
|
||||
├──0.10 MB (50.00%) ── b\n\
|
||||
└──0.10 MB (50.00%) ── c\n\
|
||||
\n\
|
||||
0.48 MB ── heap-allocated\n\
|
||||
\n\
|
||||
End of Other-only process\n\
|
||||
";
|
||||
|
||||
// This is the output for a malformed data file.
|
||||
let expectedBad =
|
||||
"\
|
||||
Error: Invalid memory report(s): missing 'hasMozMallocUsableSize' property";
|
||||
|
||||
let frames = [
|
||||
// This loads a pre-existing file that is valid.
|
||||
{ filename: "memory-reports-good.json", expected: expectedGood },
|
||||
|
||||
// This loads a pre-existing file that is valid.
|
||||
{ filename: "memory-reports-bad.json", expected: expectedBad }
|
||||
];
|
||||
|
||||
SimpleTest.waitForFocus(chain(frames));
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
|
@ -1,167 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
|
||||
<window title="about:memory"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
|
||||
<!-- This file tests the saving and loading of memory reports to/from file in
|
||||
about:memory in the presence of child processes. It is also notable
|
||||
for being an about:memory test that uses the real reporters, rather
|
||||
than fake deterministic ones, and so tends to show up problems in the
|
||||
real reporters (like bogus negative values). -->
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml"></body>
|
||||
|
||||
<iframe id="amFrame" height="400" src="about:memory"></iframe>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
"use strict";
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
let mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
|
||||
getService(Ci.nsIMemoryReporterManager);
|
||||
|
||||
let numRemotes = 3;
|
||||
let numReady = 0;
|
||||
|
||||
// Create some remote processes, and set up message-passing so that
|
||||
// we know when each child is fully initialized.
|
||||
let remotes = [];
|
||||
|
||||
let prefs = [
|
||||
["dom.ipc.processCount", 3], // Allow up to 3 child processes
|
||||
["memory.report_concurrency", 2], // Cover more child handling cases
|
||||
["memory.system_memory_reporter", true] // Test SystemMemoryReporter
|
||||
];
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": prefs}, function() {
|
||||
for (let i = 0; i < numRemotes; i++) {
|
||||
let w = remotes[i] = window.open("remote.xul", "", "chrome");
|
||||
|
||||
w.addEventListener("load", function loadHandler() {
|
||||
w.removeEventListener("load", loadHandler);
|
||||
let remoteBrowser = w.document.getElementById("remote");
|
||||
let mm = remoteBrowser.messageManager;
|
||||
mm.addMessageListener("test:ready", function readyHandler() {
|
||||
mm.removeMessageListener("test:ready", readyHandler);
|
||||
numReady++;
|
||||
if (numReady == numRemotes) {
|
||||
// All the remote processes are ready.
|
||||
SimpleTest.waitForFocus(onFocus);
|
||||
}
|
||||
});
|
||||
mm.loadFrameScript("data:," + encodeURI("sendAsyncMessage('test:ready');"), true);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Load the given file into the frame, then copy+paste the entire frame and
|
||||
// check that the cut text matches what we expect.
|
||||
function onFocus() {
|
||||
let frame = document.getElementById("amFrame");
|
||||
frame.focus();
|
||||
|
||||
function getFilePath(aFilename) {
|
||||
let file = Cc["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Components.interfaces.nsIProperties)
|
||||
.get("CurWorkD", Components.interfaces.nsIFile);
|
||||
file.append("chrome");
|
||||
file.append("toolkit");
|
||||
file.append("components");
|
||||
file.append("aboutmemory");
|
||||
file.append("tests");
|
||||
file.append(aFilename);
|
||||
return file.path;
|
||||
}
|
||||
|
||||
let filePath = getFilePath("memory-reports-dumped.json.gz");
|
||||
|
||||
let e = document.createEvent('Event');
|
||||
e.initEvent('change', true, true);
|
||||
|
||||
let dumper = Cc["@mozilla.org/memory-info-dumper;1"].
|
||||
getService(Ci.nsIMemoryInfoDumper);
|
||||
dumper.dumpMemoryReportsToNamedFile(filePath, loadAndCheck, null,
|
||||
/* anonymize = */ false);
|
||||
|
||||
function loadAndCheck() {
|
||||
// Load the file.
|
||||
let fileInput1 =
|
||||
frame.contentWindow.document.getElementById("fileInput1");
|
||||
fileInput1.value = filePath; // this works because it's a chrome test
|
||||
fileInput1.dispatchEvent(e);
|
||||
|
||||
// Initialize the clipboard contents.
|
||||
SpecialPowers.clipboardCopyString("initial clipboard value");
|
||||
|
||||
let numFailures = 0, maxFailures = 30;
|
||||
|
||||
copyPasteAndCheck();
|
||||
|
||||
// Because the file load is async, we don't know when it will finish and
|
||||
// the output will show up. So we poll.
|
||||
function copyPasteAndCheck() {
|
||||
// Copy and paste frame contents, and filter out non-deterministic
|
||||
// differences.
|
||||
synthesizeKey("A", {accelKey: true});
|
||||
synthesizeKey("C", {accelKey: true});
|
||||
let actual = SpecialPowers.getClipboardData("text/unicode");
|
||||
|
||||
// If we have more than 1000 chars, we've probably successfully
|
||||
// copy+pasted.
|
||||
if (actual.length > 1000) {
|
||||
|
||||
let good = true;
|
||||
|
||||
if (actual.match("End of System")) {
|
||||
let m1 = actual.match("anonymous") &&
|
||||
actual.match("shared-libraries");
|
||||
ok(m1, "system-wide reporter")
|
||||
good = good && !!m1;
|
||||
}
|
||||
|
||||
// Note: Match "vsize" but not "vsize-max-contiguous".
|
||||
let vsizes = actual.match(/vsize[^-]/g);
|
||||
let endOfBrowsers = actual.match(/End of Browser/g);
|
||||
if (endOfBrowsers == null) {
|
||||
endOfBrowsers = actual.match(/End of Web Content/g);
|
||||
}
|
||||
let m2 = (vsizes.length == 4 && endOfBrowsers.length == 3);
|
||||
ok(m2, "three child processes present in loaded data");
|
||||
good = good && !!m2;
|
||||
|
||||
if (!good) {
|
||||
dump("*******ACTUAL*******\n");
|
||||
dump(actual);
|
||||
dump("********************\n");
|
||||
}
|
||||
|
||||
// Close the remote processes.
|
||||
for (let i = 0; i < numRemotes; i++) {
|
||||
remotes[i].close();
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
|
||||
} else {
|
||||
numFailures++;
|
||||
if (numFailures === maxFailures) {
|
||||
ok(false, "not enough chars in pasted output");
|
||||
SimpleTest.finish();
|
||||
} else {
|
||||
setTimeout(copyPasteAndCheck, 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
|
@ -1,88 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
|
||||
<window title="about:memory"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
|
||||
<!-- This file tests the saving of GC and CC logs in both concise and
|
||||
verbose formats. -->
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml"></body>
|
||||
|
||||
<iframe id="amFrame" height="400" src="about:memory"></iframe>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
"use strict";
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
function onFocus() {
|
||||
let frame = document.getElementById("amFrame");
|
||||
frame.focus();
|
||||
|
||||
// Checks that a file exists on the local file system and removes it if it
|
||||
// is present.
|
||||
function checkForFileAndRemove(aFilename) {
|
||||
let localFile = Cc["@mozilla.org/file/local;1"]
|
||||
.createInstance(Ci.nsILocalFile);
|
||||
localFile.initWithPath(aFilename);
|
||||
|
||||
let exists = localFile.exists();
|
||||
if (exists) {
|
||||
localFile.remove(/* recursive = */ false);
|
||||
}
|
||||
|
||||
return exists;
|
||||
}
|
||||
|
||||
// Given a save log button, triggers the action and checks if both CC & GC
|
||||
// logs were written to disk.
|
||||
function saveLogs(aLogButton, aCCLogType)
|
||||
{
|
||||
// trigger the log saving
|
||||
aLogButton.click();
|
||||
|
||||
// mainDiv
|
||||
// |-> section
|
||||
// | -> div gc log path
|
||||
// | -> div cc log path
|
||||
let mainDiv = frame.contentWindow.document.getElementById("mainDiv");
|
||||
let logNodes = mainDiv.childNodes[0];
|
||||
|
||||
// we expect 2 logs listed
|
||||
let numOfLogs = logNodes.childNodes.length;
|
||||
ok(numOfLogs == 2, "two log entries generated")
|
||||
|
||||
// grab the path portion of the text
|
||||
let gcLogPath = logNodes.childNodes[0].textContent
|
||||
.replace("Saved GC log to ", "");
|
||||
let ccLogPath = logNodes.childNodes[1].textContent
|
||||
.replace("Saved " + aCCLogType + " CC log to ", "");
|
||||
|
||||
// check that the files actually exist
|
||||
ok(checkForFileAndRemove(gcLogPath), "GC log file exists");
|
||||
ok(checkForFileAndRemove(ccLogPath), "CC log file exists");
|
||||
}
|
||||
|
||||
// get the log buttons to test
|
||||
let saveConcise = frame.contentWindow.document
|
||||
.getElementById("saveLogsConcise");
|
||||
let saveVerbose = frame.contentWindow.document
|
||||
.getElementById("saveLogsVerbose");
|
||||
|
||||
saveLogs(saveConcise, "concise");
|
||||
saveLogs(saveVerbose, "verbose");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForFocus(onFocus);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
|
@ -1,98 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
<window title="GC/CC logging with child processes"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
</body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript"><![CDATA[
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
let numRemotes = 3;
|
||||
let numReady = 0;
|
||||
|
||||
// Create some remote processes, and set up message-passing so that
|
||||
// we know when each child is fully initialized.
|
||||
let remotes = [];
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.ipc.processCount", numRemotes]]},
|
||||
function() {
|
||||
for (let i = 0; i < numRemotes; i++) {
|
||||
let w = remotes[i] = window.open("remote.xul", "", "chrome");
|
||||
|
||||
w.addEventListener("load", function loadHandler() {
|
||||
w.removeEventListener("load", loadHandler);
|
||||
let remoteBrowser = w.document.getElementById("remote");
|
||||
let mm = remoteBrowser.messageManager;
|
||||
mm.addMessageListener("test:ready", function readyHandler() {
|
||||
mm.removeMessageListener("test:ready", readyHandler);
|
||||
numReady++;
|
||||
if (numReady == numRemotes) {
|
||||
// All the remote processes are ready. Run test.
|
||||
runTest();
|
||||
}
|
||||
});
|
||||
mm.loadFrameScript("data:," + encodeURI("sendAsyncMessage('test:ready');"), true);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let dumper = Cc["@mozilla.org/memory-info-dumper;1"].
|
||||
getService(Ci.nsIMemoryInfoDumper);
|
||||
|
||||
function runTest()
|
||||
{
|
||||
let numParents = 0;
|
||||
let numChildren = 0;
|
||||
dumper.dumpGCAndCCLogsToFile(
|
||||
/* identifier: */ "test." + Date.now(),
|
||||
/* allTraces: */ false,
|
||||
/* childProcesses: */ true,
|
||||
{
|
||||
onDump: function(gcLog, ccLog, isParent) {
|
||||
if (isParent) {
|
||||
numParents++;
|
||||
} else {
|
||||
numChildren++;
|
||||
}
|
||||
checkAndRemoveLog(gcLog);
|
||||
checkAndRemoveLog(ccLog);
|
||||
},
|
||||
onFinish: function() {
|
||||
is(numParents, 1,
|
||||
"GC/CC logs for the parent process");
|
||||
is(numChildren, numRemotes,
|
||||
"GC/CC logs for each child process");
|
||||
cleanUpAndFinish();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function cleanUpAndFinish() {
|
||||
// Close the remote processes.
|
||||
for (let i = 0; i < numRemotes; i++) {
|
||||
remotes[i].close();
|
||||
}
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function checkAndRemoveLog(logFile) {
|
||||
let name = logFile.path;
|
||||
ok(logFile.exists(), "log file "+name+" exists");
|
||||
ok(logFile.isFile(), "log file "+name+" is a regular file");
|
||||
ok(logFile.fileSize > 0, "log file "+name+" is not empty");
|
||||
logFile.remove(/* recursive: */ false);
|
||||
}
|
||||
|
||||
]]></script>
|
||||
</window>
|
|
@ -1,424 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
|
||||
<window title="Memory reporters"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
|
||||
<!-- This file tests (in a rough fashion) whether the memory reporters are
|
||||
producing sensible results. test_aboutmemory.xul tests the
|
||||
presentation of memory reports in about:memory. -->
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<!-- In bug 773533, <marquee> elements crashed the JS memory reporter -->
|
||||
<marquee>Marquee</marquee>
|
||||
</body>
|
||||
|
||||
<!-- some URIs that should be anonymized in anonymous mode -->
|
||||
<iframe id="amFrame" height="200" src="http://example.org:80"></iframe>
|
||||
<iframe id="amFrame" height="200" src="https://example.com:443"></iframe>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
"use strict";
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
|
||||
const NONHEAP = Ci.nsIMemoryReporter.KIND_NONHEAP;
|
||||
const HEAP = Ci.nsIMemoryReporter.KIND_HEAP;
|
||||
const OTHER = Ci.nsIMemoryReporter.KIND_OTHER;
|
||||
|
||||
const BYTES = Ci.nsIMemoryReporter.UNITS_BYTES;
|
||||
const COUNT = Ci.nsIMemoryReporter.UNITS_COUNT;
|
||||
const COUNT_CUMULATIVE = Ci.nsIMemoryReporter.UNITS_COUNT_CUMULATIVE;
|
||||
const PERCENTAGE = Ci.nsIMemoryReporter.UNITS_PERCENTAGE;
|
||||
|
||||
// Use backslashes instead of forward slashes due to memory reporting's hacky
|
||||
// handling of URLs.
|
||||
const XUL_NS =
|
||||
"http:\\\\www.mozilla.org\\keymaster\\gatekeeper\\there.is.only.xul";
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
let vsizeAmounts = [];
|
||||
let residentAmounts = [];
|
||||
let heapAllocatedAmounts = [];
|
||||
let storageSqliteAmounts = [];
|
||||
|
||||
let jsGcHeapUsedGcThingsTotal = 0;
|
||||
let jsGcHeapUsedGcThings = {};
|
||||
|
||||
let present = {}
|
||||
|
||||
// Generate a long, random string. We'll check that this string is
|
||||
// reported in at least one of the memory reporters.
|
||||
let bigString = "";
|
||||
while (bigString.length < 10000) {
|
||||
bigString += Math.random();
|
||||
}
|
||||
let bigStringPrefix = bigString.substring(0, 100);
|
||||
|
||||
// Generate many copies of two distinctive short strings, "!)(*&" and
|
||||
// "@)(*&". We'll check that these strings are reported in at least
|
||||
// one of the memory reporters.
|
||||
let shortStrings = [];
|
||||
for (let i = 0; i < 10000; i++) {
|
||||
let str = (Math.random() > 0.5 ? "!" : "@") + ")(*&";
|
||||
shortStrings.push(str);
|
||||
}
|
||||
|
||||
let mySandbox = Components.utils.Sandbox(document.nodePrincipal,
|
||||
{ sandboxName: "this-is-a-sandbox-name" });
|
||||
|
||||
function handleReportNormal(aProcess, aPath, aKind, aUnits, aAmount,
|
||||
aDescription)
|
||||
{
|
||||
// Record the values of some notable reporters.
|
||||
if (aPath === "vsize") {
|
||||
vsizeAmounts.push(aAmount);
|
||||
} else if (aPath === "resident") {
|
||||
residentAmounts.push(aAmount);
|
||||
} else if (aPath.search(/^js-main-runtime-gc-heap-committed\/used\/gc-things\//) >= 0) {
|
||||
jsGcHeapUsedGcThingsTotal += aAmount;
|
||||
jsGcHeapUsedGcThings[aPath] = (jsGcHeapUsedGcThings[aPath] | 0) + 1;
|
||||
} else if (aPath === "heap-allocated") {
|
||||
heapAllocatedAmounts.push(aAmount);
|
||||
} else if (aPath === "storage-sqlite") {
|
||||
storageSqliteAmounts.push(aAmount);
|
||||
|
||||
// Check the presence of some other notable reporters.
|
||||
} else if (aPath.search(/^explicit\/js-non-window\/.*compartment\(/) >= 0) {
|
||||
present.jsNonWindowCompartments = true;
|
||||
} else if (aPath.search(/^explicit\/window-objects\/top\(.*\/js-compartment\(/) >= 0) {
|
||||
present.windowObjectsJsCompartments = true;
|
||||
} else if (aPath.search(/^explicit\/storage\/sqlite\/places.sqlite/) >= 0) {
|
||||
present.places = true;
|
||||
} else if (aPath.search(/^explicit\/images/) >= 0) {
|
||||
present.images = true;
|
||||
} else if (aPath.search(/^explicit\/xpti-working-set$/) >= 0) {
|
||||
present.xptiWorkingSet = true;
|
||||
} else if (aPath.search(/^explicit\/atom-tables\/main$/) >= 0) {
|
||||
present.atomTablesMain = true;
|
||||
} else if (/\[System Principal\].*this-is-a-sandbox-name/.test(aPath)) {
|
||||
// A system compartment with a location (such as a sandbox) should
|
||||
// show that location.
|
||||
present.sandboxLocation = true;
|
||||
} else if (aPath.includes(bigStringPrefix)) {
|
||||
present.bigString = true;
|
||||
} else if (aPath.includes("!)(*&")) {
|
||||
present.smallString1 = true;
|
||||
} else if (aPath.includes("@)(*&")) {
|
||||
present.smallString2 = true;
|
||||
}
|
||||
|
||||
// Shouldn't get any anonymized paths.
|
||||
if (aPath.includes('<anonymized')) {
|
||||
present.anonymizedWhenUnnecessary = aPath;
|
||||
}
|
||||
}
|
||||
|
||||
function handleReportAnonymized(aProcess, aPath, aKind, aUnits, aAmount,
|
||||
aDescription)
|
||||
{
|
||||
// Path might include an xmlns using http, which is safe to ignore.
|
||||
let reducedPath = aPath.replace(XUL_NS, "");
|
||||
|
||||
// Shouldn't get http: or https: in any paths.
|
||||
if (reducedPath.includes('http:')) {
|
||||
present.httpWhenAnonymized = aPath;
|
||||
}
|
||||
|
||||
// file: URLs should have their path anonymized.
|
||||
if (reducedPath.search('file:..[^<]') !== -1) {
|
||||
present.unanonymizedFilePathWhenAnonymized = aPath;
|
||||
}
|
||||
}
|
||||
|
||||
let mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
|
||||
getService(Ci.nsIMemoryReporterManager);
|
||||
|
||||
let amounts = [
|
||||
"vsize",
|
||||
"vsizeMaxContiguous",
|
||||
"resident",
|
||||
"residentFast",
|
||||
"residentPeak",
|
||||
"residentUnique",
|
||||
"heapAllocated",
|
||||
"heapOverheadFraction",
|
||||
"JSMainRuntimeGCHeap",
|
||||
"JSMainRuntimeTemporaryPeak",
|
||||
"JSMainRuntimeCompartmentsSystem",
|
||||
"JSMainRuntimeCompartmentsUser",
|
||||
"imagesContentUsedUncompressed",
|
||||
"storageSQLite",
|
||||
"lowMemoryEventsVirtual",
|
||||
"lowMemoryEventsPhysical",
|
||||
"ghostWindows",
|
||||
"pageFaultsHard",
|
||||
];
|
||||
for (let i = 0; i < amounts.length; i++) {
|
||||
try {
|
||||
// If mgr[amounts[i]] throws an exception, just move on -- some amounts
|
||||
// aren't available on all platforms. But if the attribute simply
|
||||
// isn't present, that indicates the distinguished amounts have changed
|
||||
// and this file hasn't been updated appropriately.
|
||||
let dummy = mgr[amounts[i]];
|
||||
ok(dummy !== undefined,
|
||||
"accessed an unknown distinguished amount: " + amounts[i]);
|
||||
} catch (ex) {
|
||||
}
|
||||
}
|
||||
|
||||
// Run sizeOfTab() to make sure it doesn't crash. We can't check the result
|
||||
// values because they're non-deterministic.
|
||||
let jsObjectsSize = {};
|
||||
let jsStringsSize = {};
|
||||
let jsOtherSize = {};
|
||||
let domSize = {};
|
||||
let styleSize = {};
|
||||
let otherSize = {};
|
||||
let totalSize = {};
|
||||
let jsMilliseconds = {};
|
||||
let nonJSMilliseconds = {};
|
||||
mgr.sizeOfTab(window, jsObjectsSize, jsStringsSize, jsOtherSize,
|
||||
domSize, styleSize, otherSize, totalSize,
|
||||
jsMilliseconds, nonJSMilliseconds);
|
||||
|
||||
let asyncSteps = [
|
||||
getReportsNormal,
|
||||
getReportsAnonymized,
|
||||
checkResults,
|
||||
test_register_strong,
|
||||
test_register_strong, // Make sure re-registering works
|
||||
test_register_weak,
|
||||
SimpleTest.finish
|
||||
];
|
||||
|
||||
function runNext() {
|
||||
setTimeout(asyncSteps.shift(), 0);
|
||||
}
|
||||
|
||||
function getReportsNormal()
|
||||
{
|
||||
mgr.getReports(handleReportNormal, null,
|
||||
runNext, null,
|
||||
/* anonymize = */ false);
|
||||
}
|
||||
|
||||
function getReportsAnonymized()
|
||||
{
|
||||
mgr.getReports(handleReportAnonymized, null,
|
||||
runNext, null,
|
||||
/* anonymize = */ true);
|
||||
}
|
||||
|
||||
function checkSizeReasonable(aName, aAmount)
|
||||
{
|
||||
// Check the size is reasonable -- i.e. not ridiculously large or small.
|
||||
ok(100 * 1000 <= aAmount && aAmount <= 10 * 1000 * 1000 * 1000,
|
||||
aName + "'s size is reasonable");
|
||||
}
|
||||
|
||||
function checkSpecialReport(aName, aAmounts, aCanBeUnreasonable)
|
||||
{
|
||||
ok(aAmounts.length == 1, aName + " has " + aAmounts.length + " report");
|
||||
let n = aAmounts[0];
|
||||
if (!aCanBeUnreasonable) {
|
||||
checkSizeReasonable(aName, n);
|
||||
}
|
||||
}
|
||||
|
||||
function checkResults()
|
||||
{
|
||||
try {
|
||||
// Nb: mgr.heapAllocated will throw NS_ERROR_NOT_AVAILABLE if this is a
|
||||
// --disable-jemalloc build. Allow for skipping this test on that
|
||||
// exception, but *only* that exception.
|
||||
let dummy = mgr.heapAllocated;
|
||||
checkSpecialReport("heap-allocated", heapAllocatedAmounts);
|
||||
} catch (ex) {
|
||||
is(ex.result, Cr.NS_ERROR_NOT_AVAILABLE, "mgr.heapAllocated exception");
|
||||
}
|
||||
// vsize may be unreasonable if ASAN is enabled
|
||||
checkSpecialReport("vsize", vsizeAmounts, /*canBeUnreasonable*/true);
|
||||
checkSpecialReport("resident", residentAmounts);
|
||||
|
||||
for (var reporter in jsGcHeapUsedGcThings) {
|
||||
ok(jsGcHeapUsedGcThings[reporter] == 1);
|
||||
}
|
||||
checkSizeReasonable("js-main-runtime-gc-heap-committed/used/gc-things",
|
||||
jsGcHeapUsedGcThingsTotal);
|
||||
|
||||
ok(present.jsNonWindowCompartments, "js-non-window compartments are present");
|
||||
ok(present.windowObjectsJsCompartments, "window-objects/.../js compartments are present");
|
||||
ok(present.places, "places is present");
|
||||
ok(present.images, "images is present");
|
||||
ok(present.xptiWorkingSet, "xpti-working-set is present");
|
||||
ok(present.atomTablesMain, "atom-tables/main is present");
|
||||
ok(present.sandboxLocation, "sandbox locations are present");
|
||||
ok(present.bigString, "large string is present");
|
||||
ok(present.smallString1, "small string 1 is present");
|
||||
ok(present.smallString2, "small string 2 is present");
|
||||
|
||||
ok(!present.anonymizedWhenUnnecessary,
|
||||
"anonymized paths are not present when unnecessary. Failed case: " +
|
||||
present.anonymizedWhenUnnecessary);
|
||||
ok(!present.httpWhenAnonymized,
|
||||
"http URLs are anonymized when necessary. Failed case: " +
|
||||
present.httpWhenAnonymized);
|
||||
ok(!present.unanonymizedFilePathWhenAnonymized,
|
||||
"file URLs are anonymized when necessary. Failed case: " +
|
||||
present.unanonymizedFilePathWhenAnonymized);
|
||||
|
||||
runNext();
|
||||
}
|
||||
|
||||
// Reporter registration tests
|
||||
|
||||
// collectReports() calls to the test reporter.
|
||||
let called = 0;
|
||||
|
||||
// The test memory reporter, testing the various report units.
|
||||
// Also acts as a report collector, verifying the reported values match the
|
||||
// expected ones after passing through XPConnect / nsMemoryReporterManager
|
||||
// and back.
|
||||
function MemoryReporterAndCallback() {
|
||||
this.seen = 0;
|
||||
}
|
||||
MemoryReporterAndCallback.prototype = {
|
||||
// The test reports.
|
||||
// Each test key corresponds to the path of the report. |amount| is a
|
||||
// function called when generating the report. |expected| is a function
|
||||
// to be tested when receiving a report during collection. If |expected| is
|
||||
// omitted the |amount| will be checked instead.
|
||||
tests: {
|
||||
"test-memory-reporter-bytes1": {
|
||||
units: BYTES,
|
||||
amount: () => 0
|
||||
},
|
||||
"test-memory-reporter-bytes2": {
|
||||
units: BYTES,
|
||||
amount: () => (1<<30) * 8 // awkward way to say 8G in JS
|
||||
},
|
||||
"test-memory-reporter-counter": {
|
||||
units: COUNT,
|
||||
amount: () => 2
|
||||
},
|
||||
"test-memory-reporter-ccounter": {
|
||||
units: COUNT_CUMULATIVE,
|
||||
amount: () => ++called,
|
||||
expected: () => called
|
||||
},
|
||||
"test-memory-reporter-percentage": {
|
||||
units: PERCENTAGE,
|
||||
amount: () => 9999
|
||||
}
|
||||
},
|
||||
// nsIMemoryReporter
|
||||
collectReports: function(callback, data, anonymize) {
|
||||
for (let path of Object.keys(this.tests)) {
|
||||
try {
|
||||
let test = this.tests[path];
|
||||
callback.callback(
|
||||
"", // Process. Should be "" initially.
|
||||
path,
|
||||
OTHER,
|
||||
test.units,
|
||||
test.amount(),
|
||||
"Test " + path + ".",
|
||||
data);
|
||||
}
|
||||
catch (ex) {
|
||||
ok(false, ex);
|
||||
}
|
||||
}
|
||||
},
|
||||
// nsIMemoryReporterCallback
|
||||
callback: function(process, path, kind, units, amount, data) {
|
||||
if (path in this.tests) {
|
||||
this.seen++;
|
||||
let test = this.tests[path];
|
||||
ok(units === test.units, "Test reporter units match");
|
||||
ok(amount === (test.expected || test.amount)(),
|
||||
"Test reporter values match: " + amount);
|
||||
}
|
||||
},
|
||||
// Checks that the callback has seen the expected number of reports, and
|
||||
// resets the callback counter.
|
||||
// @param expected Optional. Expected number of reports the callback
|
||||
// should have processed.
|
||||
finish: function(expected) {
|
||||
if (expected === undefined) {
|
||||
expected = Object.keys(this.tests).length;
|
||||
}
|
||||
is(expected, this.seen,
|
||||
"Test reporter called the correct number of times: " + expected);
|
||||
this.seen = 0;
|
||||
}
|
||||
};
|
||||
|
||||
// General memory reporter + registerStrongReporter tests.
|
||||
function test_register_strong() {
|
||||
let reporterAndCallback = new MemoryReporterAndCallback();
|
||||
// Registration works.
|
||||
mgr.registerStrongReporter(reporterAndCallback);
|
||||
|
||||
// Check the generated reports.
|
||||
mgr.getReports(reporterAndCallback, null,
|
||||
() => {
|
||||
reporterAndCallback.finish();
|
||||
window.setTimeout(test_unregister_strong, 0, reporterAndCallback);
|
||||
}, null,
|
||||
/* anonymize = */ false);
|
||||
}
|
||||
|
||||
function test_unregister_strong(aReporterAndCallback)
|
||||
{
|
||||
mgr.unregisterStrongReporter(aReporterAndCallback);
|
||||
|
||||
// The reporter was unregistered, hence there shouldn't be any reports from
|
||||
// the test reporter.
|
||||
mgr.getReports(aReporterAndCallback, null,
|
||||
() => {
|
||||
aReporterAndCallback.finish(0);
|
||||
runNext();
|
||||
}, null,
|
||||
/* anonymize = */ false);
|
||||
}
|
||||
|
||||
// Check that you cannot register JS components as weak reporters.
|
||||
function test_register_weak() {
|
||||
let reporterAndCallback = new MemoryReporterAndCallback();
|
||||
try {
|
||||
// Should fail! nsMemoryReporterManager will only hold a raw pointer to
|
||||
// "weak" reporters. When registering a weak reporter, XPConnect will
|
||||
// create a WrappedJS for JS components. This WrappedJS would be
|
||||
// successfully registered with the manager, only to be destroyed
|
||||
// immediately after, which would eventually lead to a crash when
|
||||
// collecting the reports. Therefore nsMemoryReporterManager should
|
||||
// reject WrappedJS reporters, which is what is tested here.
|
||||
// See bug 950391 comment #0.
|
||||
mgr.registerWeakReporter(reporterAndCallback);
|
||||
ok(false, "Shouldn't be allowed to register a JS component (WrappedJS)");
|
||||
}
|
||||
catch (ex) {
|
||||
ok(ex.message.indexOf("NS_ERROR_") >= 0,
|
||||
"WrappedJS reporter got rejected: " + ex);
|
||||
}
|
||||
|
||||
runNext();
|
||||
}
|
||||
|
||||
// Kick-off the async tests.
|
||||
runNext();
|
||||
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
|
@ -1,108 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
<window title="Memory reporters with child processes"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
|
||||
<!-- This file tests (in a rough fashion) whether the memory reporters are
|
||||
producing sensible results in the presence of child processes. -->
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
</body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript"><![CDATA[
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
let numRemotes = 3;
|
||||
let numReady = 0;
|
||||
|
||||
// Create some remote processes, and set up message-passing so that
|
||||
// we know when each child is fully initialized.
|
||||
let remotes = [];
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.ipc.processCount", 3]]}, function() {
|
||||
for (let i = 0; i < numRemotes; i++) {
|
||||
let w = remotes[i] = window.open("remote.xul", "", "chrome");
|
||||
|
||||
w.addEventListener("load", function loadHandler() {
|
||||
w.removeEventListener("load", loadHandler);
|
||||
let remoteBrowser = w.document.getElementById("remote");
|
||||
let mm = remoteBrowser.messageManager;
|
||||
mm.addMessageListener("test:ready", function readyHandler() {
|
||||
mm.removeMessageListener("test:ready", readyHandler);
|
||||
numReady++;
|
||||
if (numReady == numRemotes) {
|
||||
// All the remote processes are ready. Do memory reporting.
|
||||
doReports();
|
||||
}
|
||||
});
|
||||
mm.loadFrameScript("data:," + encodeURI("sendAsyncMessage('test:ready');"), true);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
|
||||
getService(Ci.nsIMemoryReporterManager);
|
||||
|
||||
function doReports()
|
||||
{
|
||||
let residents = {};
|
||||
|
||||
let handleReport = function(aProcess, aPath, aKind, aUnits, aAmount, aDesc) {
|
||||
if (aPath === "resident") {
|
||||
ok(100 * 1000 <= aAmount && aAmount <= 10 * 1000 * 1000 * 1000,
|
||||
"resident is reasonable");
|
||||
residents[aProcess] = aAmount;
|
||||
}
|
||||
}
|
||||
|
||||
let processReports = function() {
|
||||
// First, test a failure case: calling getReports() before the previous
|
||||
// getReports() has finished should silently abort. (And the arguments
|
||||
// won't be used.)
|
||||
mgr.getReports(
|
||||
() => ok(false, "handleReport called for nested getReports() call"),
|
||||
null, null, null, /* anonymize = */ false
|
||||
);
|
||||
|
||||
// Close the remote processes.
|
||||
for (let i = 0; i < numRemotes; i++) {
|
||||
remotes[i].close();
|
||||
}
|
||||
|
||||
// Check the results.
|
||||
|
||||
let processes = Object.keys(residents);
|
||||
ok(processes.length == numRemotes + 1, "correct resident count");
|
||||
|
||||
let numEmptyProcesses = 0, numNonEmptyProcesses = 0;
|
||||
for (let i = 0; i < processes.length; i++) {
|
||||
if (processes[i] == "") {
|
||||
numEmptyProcesses++;
|
||||
} else {
|
||||
ok(processes[i].startsWith("Browser (") || processes[i].startsWith("Web Content ("),
|
||||
"correct non-empty process name prefix: " + processes[i]);
|
||||
numNonEmptyProcesses++;
|
||||
}
|
||||
}
|
||||
ok(numEmptyProcesses == 1, "correct empty process name count");
|
||||
ok(numNonEmptyProcesses == numRemotes,
|
||||
"correct non-empty process name count");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
mgr.getReports(handleReport, null, processReports, null,
|
||||
/* anonymize = */ false);
|
||||
}
|
||||
|
||||
]]></script>
|
||||
</window>
|
|
@ -1,54 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
|
||||
<window title="about:memory"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml"></body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
// Test for bug 708248, where the SQLite memory multi-reporter was
|
||||
// crashing when a DB was closed.
|
||||
|
||||
// Nb: this test is all JS and chould be done with an xpcshell test,
|
||||
// but all the other memory reporter tests are mochitests, so it's easier
|
||||
// if this one is too.
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// Make a fake DB file.
|
||||
let file = Cc["@mozilla.org/file/directory_service;1"].
|
||||
getService(Ci.nsIProperties).
|
||||
get("ProfD", Ci.nsIFile);
|
||||
file.append("test_sqliteMultiReporter-fake-DB-tmp.sqlite");
|
||||
|
||||
// Open and close the DB.
|
||||
let storage = Cc["@mozilla.org/storage/service;1"].
|
||||
getService(Ci.mozIStorageService);
|
||||
let db = storage.openDatabase(file);
|
||||
db.close();
|
||||
|
||||
// Invoke all the reporters. The SQLite multi-reporter is among
|
||||
// them. It shouldn't crash.
|
||||
let mgr = Cc["@mozilla.org/memory-reporter-manager;1"].
|
||||
getService(Ci.nsIMemoryReporterManager);
|
||||
mgr.getReports(function(){}, null,
|
||||
() => {
|
||||
ok(true, "didn't crash");
|
||||
SimpleTest.finish();
|
||||
}, null,
|
||||
/* anonymize = */ false);
|
||||
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
|
@ -5,5 +5,3 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['tests/browser/browser.ini']
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"../../../../../testing/mochitest/browser.eslintrc.js"
|
||||
]
|
||||
};
|
|
@ -1,8 +0,0 @@
|
|||
[DEFAULT]
|
||||
head = head.js
|
||||
support-files =
|
||||
browser_compartments.html
|
||||
browser_compartments_frame.html
|
||||
browser_compartments_script.js
|
||||
|
||||
[browser_aboutperformance.js]
|
|
@ -1,300 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://testing-common/ContentTask.jsm", this);
|
||||
|
||||
const URL = "http://example.com/browser/toolkit/components/aboutperformance/tests/browser/browser_compartments.html?test=" + Math.random();
|
||||
|
||||
// This function is injected as source as a frameScript
|
||||
function frameScript() {
|
||||
"use strict";
|
||||
|
||||
addMessageListener("aboutperformance-test:done", () => {
|
||||
content.postMessage("stop", "*");
|
||||
sendAsyncMessage("aboutperformance-test:done", null);
|
||||
});
|
||||
addMessageListener("aboutperformance-test:setTitle", ({data: title}) => {
|
||||
content.document.title = title;
|
||||
sendAsyncMessage("aboutperformance-test:setTitle", null);
|
||||
});
|
||||
|
||||
addMessageListener("aboutperformance-test:closeTab", ({data: options}) => {
|
||||
let observer = function(subject, topic, mode) {
|
||||
dump(`aboutperformance-test:closeTab 1 ${options.url}\n`);
|
||||
Services.obs.removeObserver(observer, "about:performance-update-complete");
|
||||
|
||||
let exn;
|
||||
let found = false;
|
||||
try {
|
||||
for (let eltContent of content.document.querySelectorAll("li.delta")) {
|
||||
let eltName = eltContent.querySelector("li.name");
|
||||
if (!eltName.textContent.includes(options.url)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
found = true;
|
||||
let [eltCloseTab, eltReloadTab] = eltContent.querySelectorAll("button");
|
||||
let button;
|
||||
if (options.mode == "reload") {
|
||||
button = eltReloadTab;
|
||||
} else if (options.mode == "close") {
|
||||
button = eltCloseTab;
|
||||
} else {
|
||||
throw new TypeError(options.mode);
|
||||
}
|
||||
dump(`aboutperformance-test:closeTab clicking on ${button.textContent}\n`);
|
||||
button.click();
|
||||
return;
|
||||
}
|
||||
} catch (ex) {
|
||||
dump(`aboutperformance-test:closeTab: error ${ex}\n`);
|
||||
exn = ex;
|
||||
} finally {
|
||||
if (exn) {
|
||||
sendAsyncMessage("aboutperformance-test:closeTab", { error: {message: exn.message, lineNumber: exn.lineNumber, fileName: exn.fileName}, found});
|
||||
} else {
|
||||
sendAsyncMessage("aboutperformance-test:closeTab", { ok: true, found });
|
||||
}
|
||||
}
|
||||
}
|
||||
Services.obs.addObserver(observer, "about:performance-update-complete", false);
|
||||
Services.obs.notifyObservers(null, "test-about:performance-test-driver", JSON.stringify(options));
|
||||
});
|
||||
|
||||
addMessageListener("aboutperformance-test:checkSanity", ({data: options}) => {
|
||||
let exn = null;
|
||||
try {
|
||||
let reFullname = /Full name: (.+)/;
|
||||
let reFps = /Impact on framerate: (\d+)\/10( \((\d+) alerts\))?/;
|
||||
let reCpow = /Blocking process calls: (\d+)%( \((\d+) alerts\))?/;
|
||||
|
||||
let getContentOfSelector = function(eltContainer, selector, re) {
|
||||
let elt = eltContainer.querySelector(selector);
|
||||
if (!elt) {
|
||||
throw new Error(`No item ${selector}`);
|
||||
}
|
||||
|
||||
if (!re) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let match = elt.textContent.match(re);
|
||||
if (!match) {
|
||||
throw new Error(`Item ${selector} doesn't match regexp ${re}: ${elt.textContent}`);
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
// Additional sanity check
|
||||
for (let eltContent of content.document.querySelectorAll("delta")) {
|
||||
// Do we have an attribute "impact"? Is it a number between 0 and 10?
|
||||
let impact = eltContent.classList.getAttribute("impact");
|
||||
let value = Number.parseInt(impact);
|
||||
if (isNaN(value) || value < 0 || value > 10) {
|
||||
throw new Error(`Incorrect value ${value}`);
|
||||
}
|
||||
|
||||
// Do we have a button "more"?
|
||||
getContentOfSelector(eltContent, "a.more");
|
||||
|
||||
// Do we have details?
|
||||
getContentOfSelector(eltContent, "ul.details");
|
||||
|
||||
// Do we have a full name? Does it make sense?
|
||||
getContentOfSelector(eltContent, "li.name", reFullname);
|
||||
|
||||
// Do we have an impact on framerate? Does it make sense?
|
||||
let [, jankStr,, alertsStr] = getContentOfSelector(eltDetails, "li.fps", reFps);
|
||||
let jank = Number.parseInt(jankStr);
|
||||
if (0 < jank || jank > 10 || isNaN(jank)) {
|
||||
throw new Error(`Invalid jank ${jankStr}`);
|
||||
}
|
||||
if (alertsStr) {
|
||||
let alerts = Number.parseInt(alertsStr);
|
||||
if (0 < alerts || isNaN(alerts)) {
|
||||
throw new Error(`Invalid alerts ${alertsStr}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Do we have a CPU usage? Does it make sense?
|
||||
let [, cpuStr] = getContentOfSelector(eltDetails, "li.cpu", reCPU);
|
||||
let cpu = Number.parseInt(cpuStr);
|
||||
if (0 < cpu || isNaN(cpu)) { // Note that cpu can be > 100%.
|
||||
throw new Error(`Invalid CPU ${cpuStr}`);
|
||||
}
|
||||
|
||||
// Do we have CPOW? Does it make sense?
|
||||
let [, cpowStr,, alertsStr2] = getContentOfSelector(eltDetails, "li.cpow", reCpow);
|
||||
let cpow = Number.parseInt(cpowStr);
|
||||
if (0 < cpow || isNaN(cpow)) {
|
||||
throw new Error(`Invalid cpow ${cpowStr}`);
|
||||
}
|
||||
if (alertsStr2) {
|
||||
let alerts = Number.parseInt(alertsStr2);
|
||||
if (0 < alerts || isNaN(alerts)) {
|
||||
throw new Error(`Invalid alerts ${alertsStr2}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
dump(`aboutperformance-test:checkSanity: error ${ex}\n`);
|
||||
exn = ex;
|
||||
}
|
||||
if (exn) {
|
||||
sendAsyncMessage("aboutperformance-test:checkSanity", { error: {message: exn.message, lineNumber: exn.lineNumber, fileName: exn.fileName}});
|
||||
} else {
|
||||
sendAsyncMessage("aboutperformance-test:checkSanity", { ok: true });
|
||||
}
|
||||
});
|
||||
|
||||
addMessageListener("aboutperformance-test:hasItems", ({data: {title, options}}) => {
|
||||
let observer = function(subject, topic, mode) {
|
||||
Services.obs.removeObserver(observer, "about:performance-update-complete");
|
||||
let hasTitleInWebpages = false;
|
||||
let hasTitleInAddons = false;
|
||||
|
||||
try {
|
||||
let eltWeb = content.document.getElementById("webpages");
|
||||
let eltAddons = content.document.getElementById("addons");
|
||||
if (!eltWeb || !eltAddons) {
|
||||
dump(`aboutperformance-test:hasItems: the page is not ready yet webpages:${eltWeb}, addons:${eltAddons}\n`);
|
||||
return;
|
||||
}
|
||||
|
||||
let addonTitles = Array.from(eltAddons.querySelectorAll("span.title"), elt => elt.textContent);
|
||||
let webTitles = Array.from(eltWeb.querySelectorAll("span.title"), elt => elt.textContent);
|
||||
|
||||
hasTitleInAddons = addonTitles.includes(title);
|
||||
hasTitleInWebpages = webTitles.includes(title);
|
||||
} catch (ex) {
|
||||
Cu.reportError("Error in content: " + ex);
|
||||
Cu.reportError(ex.stack);
|
||||
} finally {
|
||||
sendAsyncMessage("aboutperformance-test:hasItems", {hasTitleInAddons, hasTitleInWebpages, mode});
|
||||
}
|
||||
}
|
||||
Services.obs.addObserver(observer, "about:performance-update-complete", false);
|
||||
Services.obs.notifyObservers(null, "test-about:performance-test-driver", JSON.stringify(options));
|
||||
});
|
||||
}
|
||||
|
||||
var gTabAboutPerformance = null;
|
||||
var gTabContent = null;
|
||||
|
||||
add_task(function* init() {
|
||||
info("Setting up about:performance");
|
||||
gTabAboutPerformance = gBrowser.selectedTab = gBrowser.addTab("about:performance");
|
||||
yield ContentTask.spawn(gTabAboutPerformance.linkedBrowser, null, frameScript);
|
||||
|
||||
info(`Setting up ${URL}`);
|
||||
gTabContent = gBrowser.addTab(URL);
|
||||
yield ContentTask.spawn(gTabContent.linkedBrowser, null, frameScript);
|
||||
});
|
||||
|
||||
var promiseExpectContent = Task.async(function*(options) {
|
||||
let title = "Testing about:performance " + Math.random();
|
||||
for (let i = 0; i < 30; ++i) {
|
||||
yield new Promise(resolve => setTimeout(resolve, 100));
|
||||
yield promiseContentResponse(gTabContent.linkedBrowser, "aboutperformance-test:setTitle", title);
|
||||
let {hasTitleInWebpages, hasTitleInAddons, mode} = (yield promiseContentResponse(gTabAboutPerformance.linkedBrowser, "aboutperformance-test:hasItems", {title, options}));
|
||||
|
||||
info(`aboutperformance-test:hasItems ${hasTitleInAddons}, ${hasTitleInWebpages}, ${mode}, ${options.displayRecent}`);
|
||||
if (!hasTitleInWebpages) {
|
||||
info(`Title not found in webpages`);
|
||||
continue;
|
||||
}
|
||||
if ((mode == "recent") != options.displayRecent) {
|
||||
info(`Wrong mode`);
|
||||
continue;
|
||||
}
|
||||
Assert.ok(!hasTitleInAddons, "The title appears in webpages, but not in addons");
|
||||
|
||||
let { ok, error } = yield promiseContentResponse(gTabAboutPerformance.linkedBrowser, "aboutperformance-test:checkSanity", {options});
|
||||
if (ok) {
|
||||
info("aboutperformance-test:checkSanity: success");
|
||||
}
|
||||
if (error) {
|
||||
Assert.ok(false, `aboutperformance-test:checkSanity error: ${JSON.stringify(error)}`);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// Test that we can find the title of a webpage in about:performance
|
||||
add_task(function* test_find_title() {
|
||||
for (let displayRecent of [true, false]) {
|
||||
info(`Testing with autoRefresh, in ${displayRecent?"recent":"global"} mode`);
|
||||
let found = yield promiseExpectContent({autoRefresh: 100, displayRecent});
|
||||
Assert.ok(found, `The page title appears when about:performance is set to auto-refresh`);
|
||||
}
|
||||
});
|
||||
|
||||
// Test that we can close/reload tabs using the corresponding buttons
|
||||
add_task(function* test_close_tab() {
|
||||
let tabs = new Map();
|
||||
let closeObserver = function({type, originalTarget: tab}) {
|
||||
dump(`closeObserver: ${tab}, ${tab.constructor.name}, ${tab.tagName}, ${type}\n`);
|
||||
let cb = tabs.get(tab);
|
||||
if (cb) {
|
||||
cb(type);
|
||||
}
|
||||
};
|
||||
let promiseTabClosed = function(tab) {
|
||||
return new Promise(resolve => tabs.set(tab, resolve));
|
||||
}
|
||||
window.gBrowser.tabContainer.addEventListener("TabClose", closeObserver);
|
||||
let promiseTabReloaded = function(tab) {
|
||||
return new Promise(resolve =>
|
||||
tab.linkedBrowser.contentDocument.addEventListener("readystatechange", resolve)
|
||||
);
|
||||
}
|
||||
for (let displayRecent of [true, false]) {
|
||||
for (let mode of ["close", "reload"]) {
|
||||
let URL = `about:about?display-recent=${displayRecent}&mode=${mode}&salt=${Math.random()}`;
|
||||
info(`Setting up ${URL}`);
|
||||
let tab = gBrowser.addTab(URL);
|
||||
yield ContentTask.spawn(tab.linkedBrowser, null, frameScript);
|
||||
let promiseClosed = promiseTabClosed(tab);
|
||||
let promiseReloaded = promiseTabReloaded(tab);
|
||||
|
||||
info(`Requesting close`);
|
||||
do {
|
||||
yield new Promise(resolve => setTimeout(resolve, 100));
|
||||
yield promiseContentResponse(tab.linkedBrowser, "aboutperformance-test:setTitle", URL);
|
||||
|
||||
let {ok, found, error} = yield promiseContentResponse(gTabAboutPerformance.linkedBrowser, "aboutperformance-test:closeTab", {url: URL, autoRefresh: true, mode, displayRecent});
|
||||
Assert.ok(ok, `Message aboutperformance-test:closeTab was handled correctly ${JSON.stringify(error)}`);
|
||||
info(`URL ${URL} ${found?"found":"hasn't been found yet"}`);
|
||||
if (found) {
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
if (mode == "close") {
|
||||
info(`Waiting for close`);
|
||||
yield promiseClosed;
|
||||
} else {
|
||||
info(`Waiting for reload`);
|
||||
yield promiseReloaded;
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* cleanup() {
|
||||
// Cleanup
|
||||
info("Cleaning up");
|
||||
yield promiseContentResponse(gTabAboutPerformance.linkedBrowser, "aboutperformance-test:done", null);
|
||||
|
||||
info("Closing tabs");
|
||||
for (let tab of gBrowser.tabs) {
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
}
|
||||
|
||||
info("Done");
|
||||
gBrowser.selectedTab = null;
|
||||
});
|
|
@ -1,20 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Main frame for test browser_aboutperformance.js
|
||||
</title>
|
||||
</head>
|
||||
<body>
|
||||
Main frame.
|
||||
|
||||
<iframe src="browser_compartments_frame.html?frame=1">
|
||||
Subframe 1
|
||||
</iframe>
|
||||
|
||||
<iframe src="browser_compartments_frame.html?frame=2">
|
||||
Subframe 2.
|
||||
</iframe>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -1,12 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
Subframe for test browser_compartments.html (do not change this title)
|
||||
</title>
|
||||
<script src="browser_compartments_script.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
Subframe loaded.
|
||||
</body>
|
||||
</html>
|
|
@ -1,29 +0,0 @@
|
|||
|
||||
var carryOn = true;
|
||||
|
||||
window.addEventListener("message", e => {
|
||||
console.log("frame content", "message", e);
|
||||
if ("title" in e.data) {
|
||||
document.title = e.data.title;
|
||||
}
|
||||
if ("stop" in e.data) {
|
||||
carryOn = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Use some CPU.
|
||||
var interval = window.setInterval(() => {
|
||||
if (!carryOn) {
|
||||
window.clearInterval(interval);
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute an arbitrary value, print it out to make sure that the JS
|
||||
// engine doesn't discard all our computation.
|
||||
var date = Date.now();
|
||||
var array = [];
|
||||
var i = 0;
|
||||
while (Date.now() - date <= 100) {
|
||||
array[i%2] = i++;
|
||||
}
|
||||
}, 300);
|
|
@ -1,52 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
var { utils: Cu, interfaces: Ci, classes: Cc } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm", this);
|
||||
|
||||
function promiseContentResponse(browser, name, message) {
|
||||
let mm = browser.messageManager;
|
||||
let promise = new Promise(resolve => {
|
||||
function removeListener() {
|
||||
mm.removeMessageListener(name, listener);
|
||||
}
|
||||
|
||||
function listener(msg) {
|
||||
removeListener();
|
||||
resolve(msg.data);
|
||||
}
|
||||
|
||||
mm.addMessageListener(name, listener);
|
||||
registerCleanupFunction(removeListener);
|
||||
});
|
||||
mm.sendAsyncMessage(name, message);
|
||||
return promise;
|
||||
}
|
||||
function promiseContentResponseOrNull(browser, name, message) {
|
||||
if (!browser.messageManager) {
|
||||
return null;
|
||||
}
|
||||
return promiseContentResponse(browser, name, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* `true` if we are running an OS in which the OS performance
|
||||
* clock has a low precision and might unpredictably
|
||||
* never be updated during the execution of the test.
|
||||
*/
|
||||
function hasLowPrecision() {
|
||||
let [sysName, sysVersion] = [Services.sysinfo.getPropertyAsAString("name"), Services.sysinfo.getPropertyAsDouble("version")];
|
||||
info(`Running ${sysName} version ${sysVersion}`);
|
||||
|
||||
if (sysName == "Windows_NT" && sysVersion < 6) {
|
||||
info("Running old Windows, need to deactivate tests due to bad precision.");
|
||||
return true;
|
||||
}
|
||||
if (sysName == "Linux" && sysVersion <= 2.6) {
|
||||
info("Running old Linux, need to deactivate tests due to bad precision.");
|
||||
return true;
|
||||
}
|
||||
info("This platform has good precision.")
|
||||
return false;
|
||||
}
|
|
@ -4,8 +4,6 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
TEST_DIRS += ['tests']
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'addoncompat.manifest',
|
||||
'defaultShims.js',
|
||||
|
|
|
@ -1,653 +0,0 @@
|
|||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
var Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/BrowserUtils.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
const baseURL = "http://mochi.test:8888/browser/" +
|
||||
"toolkit/components/addoncompat/tests/browser/";
|
||||
|
||||
var contentSecManager = Cc["@mozilla.org/contentsecuritymanager;1"]
|
||||
.getService(Ci.nsIContentSecurityManager);
|
||||
|
||||
function forEachWindow(f)
|
||||
{
|
||||
let wins = Services.wm.getEnumerator("navigator:browser");
|
||||
while (wins.hasMoreElements()) {
|
||||
let win = wins.getNext();
|
||||
f(win);
|
||||
}
|
||||
}
|
||||
|
||||
function addLoadListener(target, listener)
|
||||
{
|
||||
target.addEventListener("load", function handler(event) {
|
||||
target.removeEventListener("load", handler, true);
|
||||
return listener(event);
|
||||
}, true);
|
||||
}
|
||||
|
||||
var gWin;
|
||||
var gBrowser;
|
||||
var ok, is, info;
|
||||
|
||||
function removeTab(tab, done)
|
||||
{
|
||||
// Remove the tab in a different turn of the event loop. This way
|
||||
// the nested event loop in removeTab doesn't conflict with the
|
||||
// event listener shims.
|
||||
gWin.setTimeout(() => {
|
||||
gBrowser.removeTab(tab);
|
||||
done();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
// Make sure that the shims for window.content, browser.contentWindow,
|
||||
// and browser.contentDocument are working.
|
||||
function testContentWindow()
|
||||
{
|
||||
return new Promise(function(resolve, reject) {
|
||||
const url = baseURL + "browser_addonShims_testpage.html";
|
||||
let tab = gBrowser.addTab(url);
|
||||
gBrowser.selectedTab = tab;
|
||||
let browser = tab.linkedBrowser;
|
||||
addLoadListener(browser, function handler() {
|
||||
ok(gWin.content, "content is defined on chrome window");
|
||||
ok(browser.contentWindow, "contentWindow is defined");
|
||||
ok(browser.contentDocument, "contentWindow is defined");
|
||||
is(gWin.content, browser.contentWindow, "content === contentWindow");
|
||||
ok(browser.webNavigation.sessionHistory, "sessionHistory is defined");
|
||||
|
||||
ok(browser.contentDocument.getElementById("link"), "link present in document");
|
||||
|
||||
// FIXME: Waiting on bug 1073631.
|
||||
// is(browser.contentWindow.wrappedJSObject.global, 3, "global available on document");
|
||||
|
||||
removeTab(tab, resolve);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Test for bug 1060046 and bug 1072607. We want to make sure that
|
||||
// adding and removing listeners works as expected.
|
||||
function testListeners()
|
||||
{
|
||||
return new Promise(function(resolve, reject) {
|
||||
const url1 = baseURL + "browser_addonShims_testpage.html";
|
||||
const url2 = baseURL + "browser_addonShims_testpage2.html";
|
||||
|
||||
let tab = gBrowser.addTab(url2);
|
||||
let browser = tab.linkedBrowser;
|
||||
addLoadListener(browser, function handler() {
|
||||
function dummyHandler() {}
|
||||
|
||||
// Test that a removed listener stays removed (bug
|
||||
// 1072607). We're looking to make sure that adding and removing
|
||||
// a listener here doesn't cause later listeners to fire more
|
||||
// than once.
|
||||
for (let i = 0; i < 5; i++) {
|
||||
gBrowser.addEventListener("load", dummyHandler, true);
|
||||
gBrowser.removeEventListener("load", dummyHandler, true);
|
||||
}
|
||||
|
||||
// We also want to make sure that this listener doesn't fire
|
||||
// after it's removed.
|
||||
let loadWithRemoveCount = 0;
|
||||
addLoadListener(browser, function handler1(event) {
|
||||
loadWithRemoveCount++;
|
||||
is(event.target.documentURI, url1, "only fire for first url");
|
||||
});
|
||||
|
||||
// Load url1 and then url2. We want to check that:
|
||||
// 1. handler1 only fires for url1.
|
||||
// 2. handler2 only fires once for url1 (so the second time it
|
||||
// fires should be for url2).
|
||||
let loadCount = 0;
|
||||
browser.addEventListener("load", function handler2(event) {
|
||||
loadCount++;
|
||||
if (loadCount == 1) {
|
||||
is(event.target.documentURI, url1, "first load is for first page loaded");
|
||||
browser.loadURI(url2);
|
||||
} else {
|
||||
gBrowser.removeEventListener("load", handler2, true);
|
||||
|
||||
is(event.target.documentURI, url2, "second load is for second page loaded");
|
||||
is(loadWithRemoveCount, 1, "load handler is only called once");
|
||||
|
||||
removeTab(tab, resolve);
|
||||
}
|
||||
}, true);
|
||||
|
||||
browser.loadURI(url1);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Test for bug 1059207. We want to make sure that adding a capturing
|
||||
// listener and a non-capturing listener to the same element works as
|
||||
// expected.
|
||||
function testCapturing()
|
||||
{
|
||||
return new Promise(function(resolve, reject) {
|
||||
let capturingCount = 0;
|
||||
let nonCapturingCount = 0;
|
||||
|
||||
function capturingHandler(event) {
|
||||
is(capturingCount, 0, "capturing handler called once");
|
||||
is(nonCapturingCount, 0, "capturing handler called before bubbling handler");
|
||||
capturingCount++;
|
||||
}
|
||||
|
||||
function nonCapturingHandler(event) {
|
||||
is(capturingCount, 1, "bubbling handler called after capturing handler");
|
||||
is(nonCapturingCount, 0, "bubbling handler called once");
|
||||
nonCapturingCount++;
|
||||
}
|
||||
|
||||
gBrowser.addEventListener("mousedown", capturingHandler, true);
|
||||
gBrowser.addEventListener("mousedown", nonCapturingHandler, false);
|
||||
|
||||
const url = baseURL + "browser_addonShims_testpage.html";
|
||||
let tab = gBrowser.addTab(url);
|
||||
let browser = tab.linkedBrowser;
|
||||
addLoadListener(browser, function handler() {
|
||||
let win = browser.contentWindow;
|
||||
let event = win.document.createEvent("MouseEvents");
|
||||
event.initMouseEvent("mousedown", true, false, win, 1,
|
||||
1, 0, 0, 0, // screenX, screenY, clientX, clientY
|
||||
false, false, false, false, // ctrlKey, altKey, shiftKey, metaKey
|
||||
0, null); // buttonCode, relatedTarget
|
||||
|
||||
let element = win.document.getElementById("output");
|
||||
element.dispatchEvent(event);
|
||||
|
||||
is(capturingCount, 1, "capturing handler fired");
|
||||
is(nonCapturingCount, 1, "bubbling handler fired");
|
||||
|
||||
gBrowser.removeEventListener("mousedown", capturingHandler, true);
|
||||
gBrowser.removeEventListener("mousedown", nonCapturingHandler, false);
|
||||
|
||||
removeTab(tab, resolve);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Make sure we get observer notifications that normally fire in the
|
||||
// child.
|
||||
function testObserver()
|
||||
{
|
||||
return new Promise(function(resolve, reject) {
|
||||
let observerFired = 0;
|
||||
|
||||
function observer(subject, topic, data) {
|
||||
Services.obs.removeObserver(observer, "document-element-inserted");
|
||||
observerFired++;
|
||||
}
|
||||
Services.obs.addObserver(observer, "document-element-inserted", false);
|
||||
|
||||
let count = 0;
|
||||
const url = baseURL + "browser_addonShims_testpage.html";
|
||||
let tab = gBrowser.addTab(url);
|
||||
let browser = tab.linkedBrowser;
|
||||
browser.addEventListener("load", function handler() {
|
||||
count++;
|
||||
if (count == 1) {
|
||||
browser.reload();
|
||||
} else {
|
||||
browser.removeEventListener("load", handler);
|
||||
|
||||
is(observerFired, 1, "got observer notification");
|
||||
|
||||
removeTab(tab, resolve);
|
||||
}
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
||||
// Test for bug 1072472. Make sure that creating a sandbox to run code
|
||||
// in the content window works. This is essentially a test for
|
||||
// Greasemonkey.
|
||||
function testSandbox()
|
||||
{
|
||||
return new Promise(function(resolve, reject) {
|
||||
const url = baseURL + "browser_addonShims_testpage.html";
|
||||
let tab = gBrowser.addTab(url);
|
||||
let browser = tab.linkedBrowser;
|
||||
browser.addEventListener("load", function handler() {
|
||||
browser.removeEventListener("load", handler);
|
||||
|
||||
let sandbox = Cu.Sandbox(browser.contentWindow,
|
||||
{sandboxPrototype: browser.contentWindow,
|
||||
wantXrays: false});
|
||||
Cu.evalInSandbox("const unsafeWindow = window;", sandbox);
|
||||
Cu.evalInSandbox("document.getElementById('output').innerHTML = 'hello';", sandbox);
|
||||
|
||||
is(browser.contentDocument.getElementById("output").innerHTML, "hello",
|
||||
"sandbox code ran successfully");
|
||||
|
||||
// Now try a sandbox with expanded principals.
|
||||
sandbox = Cu.Sandbox([browser.contentWindow],
|
||||
{sandboxPrototype: browser.contentWindow,
|
||||
wantXrays: false});
|
||||
Cu.evalInSandbox("const unsafeWindow = window;", sandbox);
|
||||
Cu.evalInSandbox("document.getElementById('output').innerHTML = 'hello2';", sandbox);
|
||||
|
||||
is(browser.contentDocument.getElementById("output").innerHTML, "hello2",
|
||||
"EP sandbox code ran successfully");
|
||||
|
||||
removeTab(tab, resolve);
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
||||
// Test for bug 1095305. We just want to make sure that loading some
|
||||
// unprivileged content from an add-on package doesn't crash.
|
||||
function testAddonContent()
|
||||
{
|
||||
let chromeRegistry = Components.classes["@mozilla.org/chrome/chrome-registry;1"]
|
||||
.getService(Components.interfaces.nsIChromeRegistry);
|
||||
let base = chromeRegistry.convertChromeURL(BrowserUtils.makeURI("chrome://addonshim1/content/"));
|
||||
|
||||
let res = Services.io.getProtocolHandler("resource")
|
||||
.QueryInterface(Ci.nsIResProtocolHandler);
|
||||
res.setSubstitution("addonshim1", base);
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
const url = "resource://addonshim1/page.html";
|
||||
let tab = gBrowser.addTab(url);
|
||||
let browser = tab.linkedBrowser;
|
||||
addLoadListener(browser, function handler() {
|
||||
res.setSubstitution("addonshim1", null);
|
||||
removeTab(tab, resolve);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Test for bug 1102410. We check that multiple nsIAboutModule's can be
|
||||
// registered in the parent, and that the child can browse to each of
|
||||
// the registered about: pages.
|
||||
function testAboutModuleRegistration()
|
||||
{
|
||||
let Registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
|
||||
let modulesToUnregister = new Map();
|
||||
|
||||
function TestChannel(uri, aLoadInfo, aboutName) {
|
||||
this.aboutName = aboutName;
|
||||
this.loadInfo = aLoadInfo;
|
||||
this.URI = this.originalURI = uri;
|
||||
}
|
||||
|
||||
TestChannel.prototype = {
|
||||
asyncOpen: function(listener, context) {
|
||||
let stream = this.open();
|
||||
let runnable = {
|
||||
run: () => {
|
||||
try {
|
||||
listener.onStartRequest(this, context);
|
||||
} catch (e) {}
|
||||
try {
|
||||
listener.onDataAvailable(this, context, stream, 0, stream.available());
|
||||
} catch (e) {}
|
||||
try {
|
||||
listener.onStopRequest(this, context, Cr.NS_OK);
|
||||
} catch (e) {}
|
||||
}
|
||||
};
|
||||
Services.tm.currentThread.dispatch(runnable, Ci.nsIEventTarget.DISPATCH_NORMAL);
|
||||
},
|
||||
|
||||
asyncOpen2: function(listener) {
|
||||
// throws an error if security checks fail
|
||||
var outListener = contentSecManager.performSecurityCheck(this, listener);
|
||||
return this.asyncOpen(outListener, null);
|
||||
},
|
||||
|
||||
open: function() {
|
||||
function getWindow(channel) {
|
||||
try
|
||||
{
|
||||
if (channel.notificationCallbacks)
|
||||
return channel.notificationCallbacks.getInterface(Ci.nsILoadContext).associatedWindow;
|
||||
} catch (e) {}
|
||||
|
||||
try
|
||||
{
|
||||
if (channel.loadGroup && channel.loadGroup.notificationCallbacks)
|
||||
return channel.loadGroup.notificationCallbacks.getInterface(Ci.nsILoadContext).associatedWindow;
|
||||
} catch (e) {}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
let data = `<html><h1>${this.aboutName}</h1></html>`;
|
||||
let wnd = getWindow(this);
|
||||
if (!wnd)
|
||||
throw Cr.NS_ERROR_UNEXPECTED;
|
||||
|
||||
let stream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
|
||||
stream.setData(data, data.length);
|
||||
return stream;
|
||||
},
|
||||
|
||||
open2: function() {
|
||||
// throws an error if security checks fail
|
||||
contentSecManager.performSecurityCheck(this, null);
|
||||
return this.open();
|
||||
},
|
||||
|
||||
isPending: function() {
|
||||
return false;
|
||||
},
|
||||
cancel: function() {
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
suspend: function() {
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
resume: function() {
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIChannel, Ci.nsIRequest])
|
||||
};
|
||||
|
||||
/**
|
||||
* This function creates a new nsIAboutModule and registers it. Callers
|
||||
* should also call unregisterModules after using this function to clean
|
||||
* up the nsIAboutModules at the end of this test.
|
||||
*
|
||||
* @param aboutName
|
||||
* This will be the string after about: used to refer to this module.
|
||||
* For example, if aboutName is foo, you can refer to this module by
|
||||
* browsing to about:foo.
|
||||
*
|
||||
* @param uuid
|
||||
* A unique identifer string for this module. For example,
|
||||
* "5f3a921b-250f-4ac5-a61c-8f79372e6063"
|
||||
*/
|
||||
let createAndRegisterAboutModule = function(aboutName, uuid) {
|
||||
|
||||
let AboutModule = function() {};
|
||||
|
||||
AboutModule.prototype = {
|
||||
classID: Components.ID(uuid),
|
||||
classDescription: `Testing About Module for about:${aboutName}`,
|
||||
contractID: `@mozilla.org/network/protocol/about;1?what=${aboutName}`,
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]),
|
||||
|
||||
newChannel: (aURI, aLoadInfo) => {
|
||||
return new TestChannel(aURI, aLoadInfo, aboutName);
|
||||
},
|
||||
|
||||
getURIFlags: (aURI) => {
|
||||
return Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
||||
Ci.nsIAboutModule.ALLOW_SCRIPT;
|
||||
},
|
||||
};
|
||||
|
||||
let factory = {
|
||||
createInstance: function(outer, iid) {
|
||||
if (outer) {
|
||||
throw Cr.NS_ERROR_NO_AGGREGATION;
|
||||
}
|
||||
return new AboutModule();
|
||||
},
|
||||
};
|
||||
|
||||
Registrar.registerFactory(AboutModule.prototype.classID,
|
||||
AboutModule.prototype.classDescription,
|
||||
AboutModule.prototype.contractID,
|
||||
factory);
|
||||
|
||||
modulesToUnregister.set(AboutModule.prototype.classID,
|
||||
factory);
|
||||
};
|
||||
|
||||
/**
|
||||
* Unregisters any nsIAboutModules registered with
|
||||
* createAndRegisterAboutModule.
|
||||
*/
|
||||
let unregisterModules = () => {
|
||||
for (let [classID, factory] of modulesToUnregister) {
|
||||
Registrar.unregisterFactory(classID, factory);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Takes a browser, and sends it a framescript to attempt to
|
||||
* load some about: pages. The frame script will send a test:result
|
||||
* message on completion, passing back a data object with:
|
||||
*
|
||||
* {
|
||||
* pass: true
|
||||
* }
|
||||
*
|
||||
* on success, and:
|
||||
*
|
||||
* {
|
||||
* pass: false,
|
||||
* errorMsg: message,
|
||||
* }
|
||||
*
|
||||
* on failure.
|
||||
*
|
||||
* @param browser
|
||||
* The browser to send the framescript to.
|
||||
*/
|
||||
let testAboutModulesWork = (browser) => {
|
||||
let testConnection = () => {
|
||||
let request = new content.XMLHttpRequest();
|
||||
try {
|
||||
request.open("GET", "about:test1", false);
|
||||
request.send(null);
|
||||
if (request.status != 200) {
|
||||
throw (`about:test1 response had status ${request.status} - expected 200`);
|
||||
}
|
||||
if (request.responseText.indexOf("test1") == -1) {
|
||||
throw (`about:test1 response had result ${request.responseText}`);
|
||||
}
|
||||
|
||||
request = new content.XMLHttpRequest();
|
||||
request.open("GET", "about:test2", false);
|
||||
request.send(null);
|
||||
|
||||
if (request.status != 200) {
|
||||
throw (`about:test2 response had status ${request.status} - expected 200`);
|
||||
}
|
||||
if (request.responseText.indexOf("test2") == -1) {
|
||||
throw (`about:test2 response had result ${request.responseText}`);
|
||||
}
|
||||
|
||||
sendAsyncMessage("test:result", {
|
||||
pass: true,
|
||||
});
|
||||
} catch (e) {
|
||||
sendAsyncMessage("test:result", {
|
||||
pass: false,
|
||||
errorMsg: e.toString(),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let mm = browser.messageManager;
|
||||
mm.addMessageListener("test:result", function onTestResult(message) {
|
||||
mm.removeMessageListener("test:result", onTestResult);
|
||||
if (message.data.pass) {
|
||||
ok(true, "Connections to about: pages were successful");
|
||||
} else {
|
||||
ok(false, message.data.errorMsg);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
mm.loadFrameScript("data:,(" + testConnection.toString() + ")();", false);
|
||||
});
|
||||
}
|
||||
|
||||
// Here's where the actual test is performed.
|
||||
return new Promise((resolve, reject) => {
|
||||
createAndRegisterAboutModule("test1", "5f3a921b-250f-4ac5-a61c-8f79372e6063");
|
||||
createAndRegisterAboutModule("test2", "d7ec0389-1d49-40fa-b55c-a1fc3a6dbf6f");
|
||||
|
||||
// This needs to be a chrome-privileged page that loads in the
|
||||
// content process. It needs chrome privs because otherwise the
|
||||
// XHRs for about:test[12] will fail with a privilege error
|
||||
// despite the presence of URI_SAFE_FOR_UNTRUSTED_CONTENT.
|
||||
let newTab = gBrowser.addTab("chrome://addonshim1/content/page.html");
|
||||
gBrowser.selectedTab = newTab;
|
||||
let browser = newTab.linkedBrowser;
|
||||
|
||||
addLoadListener(browser, function() {
|
||||
testAboutModulesWork(browser).then(() => {
|
||||
unregisterModules();
|
||||
removeTab(newTab, resolve);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testProgressListener()
|
||||
{
|
||||
const url = baseURL + "browser_addonShims_testpage.html";
|
||||
|
||||
let sawGlobalLocChange = false;
|
||||
let sawTabsLocChange = false;
|
||||
|
||||
let globalListener = {
|
||||
onLocationChange: function(webProgress, request, uri) {
|
||||
if (uri.spec == url) {
|
||||
sawGlobalLocChange = true;
|
||||
ok(request instanceof Ci.nsIHttpChannel, "Global listener channel is an HTTP channel");
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
let tabsListener = {
|
||||
onLocationChange: function(browser, webProgress, request, uri) {
|
||||
if (uri.spec == url) {
|
||||
sawTabsLocChange = true;
|
||||
ok(request instanceof Ci.nsIHttpChannel, "Tab listener channel is an HTTP channel");
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
gBrowser.addProgressListener(globalListener);
|
||||
gBrowser.addTabsProgressListener(tabsListener);
|
||||
info("Added progress listeners");
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
let tab = gBrowser.addTab(url);
|
||||
gBrowser.selectedTab = tab;
|
||||
addLoadListener(tab.linkedBrowser, function handler() {
|
||||
ok(sawGlobalLocChange, "Saw global onLocationChange");
|
||||
ok(sawTabsLocChange, "Saw tabs onLocationChange");
|
||||
|
||||
gBrowser.removeProgressListener(globalListener);
|
||||
gBrowser.removeTabsProgressListener(tabsListener);
|
||||
removeTab(tab, resolve);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testRootTreeItem()
|
||||
{
|
||||
return new Promise(function(resolve, reject) {
|
||||
const url = baseURL + "browser_addonShims_testpage.html";
|
||||
let tab = gBrowser.addTab(url);
|
||||
gBrowser.selectedTab = tab;
|
||||
let browser = tab.linkedBrowser;
|
||||
addLoadListener(browser, function handler() {
|
||||
let win = browser.contentWindow;
|
||||
|
||||
// Add-ons love this crap.
|
||||
let root = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||
.getInterface(Components.interfaces.nsIWebNavigation)
|
||||
.QueryInterface(Components.interfaces.nsIDocShellTreeItem)
|
||||
.rootTreeItem
|
||||
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||
.getInterface(Components.interfaces.nsIDOMWindow);
|
||||
is(root, gWin, "got correct chrome window");
|
||||
|
||||
removeTab(tab, resolve);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testImportNode()
|
||||
{
|
||||
return new Promise(function(resolve, reject) {
|
||||
const url = baseURL + "browser_addonShims_testpage.html";
|
||||
let tab = gBrowser.addTab(url);
|
||||
gBrowser.selectedTab = tab;
|
||||
let browser = tab.linkedBrowser;
|
||||
addLoadListener(browser, function handler() {
|
||||
let node = gWin.document.createElement("div");
|
||||
let doc = browser.contentDocument;
|
||||
let result;
|
||||
try {
|
||||
result = doc.importNode(node, false);
|
||||
} catch (e) {
|
||||
ok(false, "importing threw an exception");
|
||||
}
|
||||
if (browser.isRemoteBrowser) {
|
||||
is(result, node, "got expected import result");
|
||||
}
|
||||
|
||||
removeTab(tab, resolve);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function runTests(win, funcs)
|
||||
{
|
||||
ok = funcs.ok;
|
||||
is = funcs.is;
|
||||
info = funcs.info;
|
||||
|
||||
gWin = win;
|
||||
gBrowser = win.gBrowser;
|
||||
|
||||
return testContentWindow().
|
||||
then(testListeners).
|
||||
then(testCapturing).
|
||||
then(testObserver).
|
||||
then(testSandbox).
|
||||
then(testAddonContent).
|
||||
then(testAboutModuleRegistration).
|
||||
then(testProgressListener).
|
||||
then(testRootTreeItem).
|
||||
then(testImportNode).
|
||||
then(Promise.resolve());
|
||||
}
|
||||
|
||||
/*
|
||||
bootstrap.js API
|
||||
*/
|
||||
|
||||
function startup(aData, aReason)
|
||||
{
|
||||
forEachWindow(win => {
|
||||
win.runAddonShimTests = (funcs) => runTests(win, funcs);
|
||||
});
|
||||
}
|
||||
|
||||
function shutdown(aData, aReason)
|
||||
{
|
||||
forEachWindow(win => {
|
||||
delete win.runAddonShimTests;
|
||||
});
|
||||
}
|
||||
|
||||
function install(aData, aReason)
|
||||
{
|
||||
}
|
||||
|
||||
function uninstall(aData, aReason)
|
||||
{
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
content addonshim1 content/
|
|
@ -1,2 +0,0 @@
|
|||
<html>
|
||||
</html>
|
|
@ -1,37 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>test-addon-shim-1@tests.mozilla.org</em:id>
|
||||
<em:version>1</em:version>
|
||||
<em:type>2</em:type>
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
|
||||
<!-- Front End MetaData -->
|
||||
<em:name>Test addon shim 1</em:name>
|
||||
<em:description>Test an add-on that needs multiprocess shims.</em:description>
|
||||
<em:multiprocessCompatible>false</em:multiprocessCompatible>
|
||||
|
||||
<em:iconURL>chrome://foo/skin/icon.png</em:iconURL>
|
||||
<em:aboutURL>chrome://foo/content/about.xul</em:aboutURL>
|
||||
<em:optionsURL>chrome://foo/content/options.xul</em:optionsURL>
|
||||
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
|
||||
<em:minVersion>0.3</em:minVersion>
|
||||
<em:maxVersion>*</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>toolkit@mozilla.org</em:id>
|
||||
<em:minVersion>10.0</em:minVersion>
|
||||
<em:maxVersion>*</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
</Description>
|
||||
</RDF>
|
|
@ -1,7 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"../../../../../testing/mochitest/browser.eslintrc.js"
|
||||
]
|
||||
};
|
Binary file not shown.
|
@ -1,9 +0,0 @@
|
|||
[DEFAULT]
|
||||
tags = addons
|
||||
support-files =
|
||||
addon.xpi
|
||||
browser_addonShims_testpage.html
|
||||
browser_addonShims_testpage2.html
|
||||
compat-addon.xpi
|
||||
|
||||
[browser_addonShims.js]
|
|
@ -1,67 +0,0 @@
|
|||
var {AddonManager} = Cu.import("resource://gre/modules/AddonManager.jsm", {});
|
||||
var {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
|
||||
const ADDON_URL = "http://example.com/browser/toolkit/components/addoncompat/tests/browser/addon.xpi";
|
||||
const COMPAT_ADDON_URL = "http://example.com/browser/toolkit/components/addoncompat/tests/browser/compat-addon.xpi";
|
||||
|
||||
// Install a test add-on that will exercise e10s shims.
|
||||
// url: Location of the add-on.
|
||||
function addAddon(url)
|
||||
{
|
||||
info("Installing add-on: " + url);
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
AddonManager.getInstallForURL(url, installer => {
|
||||
installer.install();
|
||||
let listener = {
|
||||
onInstallEnded: function(addon, addonInstall) {
|
||||
installer.removeListener(listener);
|
||||
|
||||
// Wait for add-on's startup scripts to execute. See bug 997408
|
||||
executeSoon(function() {
|
||||
resolve(addonInstall);
|
||||
});
|
||||
}
|
||||
};
|
||||
installer.addListener(listener);
|
||||
}, "application/x-xpinstall");
|
||||
});
|
||||
}
|
||||
|
||||
// Uninstall a test add-on.
|
||||
// addon: The addon reference returned from addAddon.
|
||||
function removeAddon(addon)
|
||||
{
|
||||
info("Removing addon.");
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
let listener = {
|
||||
onUninstalled: function(uninstalledAddon) {
|
||||
if (uninstalledAddon != addon) {
|
||||
return;
|
||||
}
|
||||
AddonManager.removeAddonListener(listener);
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
AddonManager.addAddonListener(listener);
|
||||
addon.uninstall();
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function* test_addon_shims() {
|
||||
yield new Promise(resolve => {
|
||||
SpecialPowers.pushPrefEnv({set: [["dom.ipc.shims.enabledWarnings", true]]},
|
||||
resolve);
|
||||
});
|
||||
|
||||
let addon = yield addAddon(ADDON_URL);
|
||||
yield window.runAddonShimTests({ok: ok, is: is, info: info});
|
||||
yield removeAddon(addon);
|
||||
|
||||
if (Services.appinfo.browserTabsRemoteAutostart) {
|
||||
addon = yield addAddon(COMPAT_ADDON_URL);
|
||||
yield window.runAddonTests({ok: ok, is: is, info: info});
|
||||
yield removeAddon(addon);
|
||||
}
|
||||
});
|
|
@ -1,17 +0,0 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>shim test</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
Hello!
|
||||
|
||||
<a href="browser_addonShims_testpage2.html" id="link">Link</a>
|
||||
<div id="output"></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var global = 3;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,16 +0,0 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>shim test</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
Hello!
|
||||
|
||||
<a href="browser_addonShims_testpage.html" id="link">Link</a>
|
||||
|
||||
<script type="text/javascript">
|
||||
var global = 5;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Binary file not shown.
|
@ -1,99 +0,0 @@
|
|||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
var Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/BrowserUtils.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
const baseURL = "http://mochi.test:8888/browser/" +
|
||||
"toolkit/components/addoncompat/tests/browser/";
|
||||
|
||||
function forEachWindow(f)
|
||||
{
|
||||
let wins = Services.wm.getEnumerator("navigator:browser");
|
||||
while (wins.hasMoreElements()) {
|
||||
let win = wins.getNext();
|
||||
f(win);
|
||||
}
|
||||
}
|
||||
|
||||
function addLoadListener(target, listener)
|
||||
{
|
||||
function frameScript() {
|
||||
addEventListener("load", function handler(event) {
|
||||
removeEventListener("load", handler, true);
|
||||
sendAsyncMessage("compat-test:loaded");
|
||||
}, true);
|
||||
}
|
||||
target.messageManager.loadFrameScript("data:,(" + frameScript.toString() + ")()", false);
|
||||
target.messageManager.addMessageListener("compat-test:loaded", function handler() {
|
||||
target.messageManager.removeMessageListener("compat-test:loaded", handler);
|
||||
listener();
|
||||
});
|
||||
}
|
||||
|
||||
var gWin;
|
||||
var gBrowser;
|
||||
var ok, is, info;
|
||||
|
||||
// Make sure that the shims for window.content, browser.contentWindow,
|
||||
// and browser.contentDocument are working.
|
||||
function testContentWindow()
|
||||
{
|
||||
return new Promise(function(resolve, reject) {
|
||||
const url = baseURL + "browser_addonShims_testpage.html";
|
||||
let tab = gBrowser.addTab("about:blank");
|
||||
gBrowser.selectedTab = tab;
|
||||
let browser = tab.linkedBrowser;
|
||||
addLoadListener(browser, function handler() {
|
||||
ok(!gWin.content, "content is defined on chrome window");
|
||||
ok(!browser.contentWindow, "contentWindow is defined");
|
||||
ok(!browser.contentDocument, "contentWindow is defined");
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
resolve();
|
||||
});
|
||||
browser.loadURI(url);
|
||||
});
|
||||
}
|
||||
|
||||
function runTests(win, funcs)
|
||||
{
|
||||
ok = funcs.ok;
|
||||
is = funcs.is;
|
||||
info = funcs.info;
|
||||
|
||||
gWin = win;
|
||||
gBrowser = win.gBrowser;
|
||||
|
||||
return testContentWindow();
|
||||
}
|
||||
|
||||
/*
|
||||
bootstrap.js API
|
||||
*/
|
||||
|
||||
function startup(aData, aReason)
|
||||
{
|
||||
forEachWindow(win => {
|
||||
win.runAddonTests = (funcs) => runTests(win, funcs);
|
||||
});
|
||||
}
|
||||
|
||||
function shutdown(aData, aReason)
|
||||
{
|
||||
forEachWindow(win => {
|
||||
delete win.runAddonTests;
|
||||
});
|
||||
}
|
||||
|
||||
function install(aData, aReason)
|
||||
{
|
||||
}
|
||||
|
||||
function uninstall(aData, aReason)
|
||||
{
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
|
||||
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>test-addon-shim-2@tests.mozilla.org</em:id>
|
||||
<em:version>1</em:version>
|
||||
<em:type>2</em:type>
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
|
||||
<!-- Front End MetaData -->
|
||||
<em:name>Test addon shims 2</em:name>
|
||||
<em:description>Test an add-on that doesn't need multiprocess shims.</em:description>
|
||||
<em:multiprocessCompatible>true</em:multiprocessCompatible>
|
||||
|
||||
<em:iconURL>chrome://foo/skin/icon.png</em:iconURL>
|
||||
<em:aboutURL>chrome://foo/content/about.xul</em:aboutURL>
|
||||
<em:optionsURL>chrome://foo/content/options.xul</em:optionsURL>
|
||||
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
|
||||
<em:minVersion>0.3</em:minVersion>
|
||||
<em:maxVersion>*</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>toolkit@mozilla.org</em:id>
|
||||
<em:minVersion>10.0</em:minVersion>
|
||||
<em:maxVersion>*</em:maxVersion>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
</Description>
|
||||
</RDF>
|
|
@ -1,7 +0,0 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['browser/browser.ini']
|
|
@ -4,17 +4,13 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
MOCHITEST_MANIFESTS += ['test/mochitest.ini']
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIAlertsService.idl',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'alerts'
|
||||
|
||||
EXPORTS += [
|
||||
'nsAlertsUtils.h',
|
||||
]
|
||||
EXPORTS += ['nsAlertsUtils.h']
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'AlertNotification.h',
|
||||
|
@ -33,6 +29,3 @@ include('/ipc/chromium/chromium-config.mozbuild')
|
|||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
||||
with Files('**'):
|
||||
BUG_COMPONENT = ('Toolkit', 'Notifications and Alerts')
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"../../../../testing/mochitest/mochitest.eslintrc.js"
|
||||
]
|
||||
};
|
Binary file not shown.
Before Width: | Height: | Size: 60 KiB |
Binary file not shown.
Before Width: | Height: | Size: 2.5 KiB |
|
@ -1,82 +0,0 @@
|
|||
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr, Constructor: CC } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Timer.jsm");
|
||||
|
||||
const LocalFile = CC("@mozilla.org/file/local;1", "nsILocalFile",
|
||||
"initWithPath");
|
||||
|
||||
const FileInputStream = CC("@mozilla.org/network/file-input-stream;1",
|
||||
"nsIFileInputStream", "init");
|
||||
|
||||
const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
|
||||
"nsIBinaryInputStream", "setInputStream");
|
||||
|
||||
function handleRequest(request, response) {
|
||||
let params = parseQueryString(request.queryString);
|
||||
|
||||
response.setStatusLine(request.httpVersion, 200, "OK");
|
||||
|
||||
// Compare and increment a cookie for this request. This is used to test
|
||||
// private browsing mode; the cookie should not be set if the image is
|
||||
// loaded anonymously.
|
||||
if (params.has("c")) {
|
||||
let expectedValue = parseInt(params.get("c"), 10);
|
||||
let actualValue = !request.hasHeader("Cookie") ? 0 :
|
||||
parseInt(request.getHeader("Cookie")
|
||||
.replace(/^counter=(\d+)/, "$1"), 10);
|
||||
if (actualValue != expectedValue) {
|
||||
response.setStatusLine(request.httpVersion, 400, "Wrong counter value");
|
||||
return;
|
||||
}
|
||||
response.setHeader("Set-Cookie", `counter=${expectedValue + 1}`, false);
|
||||
}
|
||||
|
||||
// Wait to send the image if a timeout is given.
|
||||
let timeout = parseInt(params.get("t"), 10);
|
||||
if (timeout > 0) {
|
||||
response.processAsync();
|
||||
setTimeout(() => {
|
||||
respond(params, request, response);
|
||||
response.finish();
|
||||
}, timeout * 1000);
|
||||
return;
|
||||
}
|
||||
|
||||
respond(params, request, response);
|
||||
}
|
||||
|
||||
function parseQueryString(queryString) {
|
||||
return queryString.split("&").reduce((params, param) => {
|
||||
let [key, value] = param.split("=", 2);
|
||||
params.set(key, value);
|
||||
return params;
|
||||
}, new Map());
|
||||
}
|
||||
|
||||
function respond(params, request, response) {
|
||||
if (params.has("s")) {
|
||||
let statusCode = parseInt(params.get("s"), 10);
|
||||
response.setStatusLine(request.httpVersion, statusCode, "Custom status");
|
||||
return;
|
||||
}
|
||||
var filename = params.get("f");
|
||||
writeFile(filename, response);
|
||||
}
|
||||
|
||||
function writeFile(name, response) {
|
||||
var file = new LocalFile(getState("__LOCATION__")).parent;
|
||||
file.append(name);
|
||||
|
||||
let mimeType = Cc["@mozilla.org/uriloader/external-helper-app-service;1"]
|
||||
.getService(Ci.nsIMIMEService)
|
||||
.getTypeFromFile(file);
|
||||
|
||||
let fileStream = new FileInputStream(file, 1, 0, false);
|
||||
let binaryStream = new BinaryInputStream(fileStream);
|
||||
|
||||
response.setHeader("Content-Type", mimeType, false);
|
||||
response.bodyOutputStream.writeFrom(binaryStream, binaryStream.available());
|
||||
|
||||
binaryStream.close();
|
||||
fileStream.close();
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
image.gif
|
||||
image.png
|
||||
image_server.sjs
|
||||
|
||||
# Synchronous tests like test_alerts.html must come before
|
||||
# asynchronous tests like test_alerts_noobserve.html!
|
||||
[test_alerts.html]
|
||||
skip-if = toolkit == 'android'
|
||||
[test_alerts_noobserve.html]
|
||||
[test_alerts_requireinteraction.html]
|
||||
[test_image.html]
|
||||
[test_multiple_alerts.html]
|
||||
[test_principal.html]
|
||||
skip-if = toolkit == 'android'
|
|
@ -1,89 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Alerts Service</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
|
||||
<br>Alerts service, with observer "synchronous" case.
|
||||
<br>
|
||||
<br>Did a notification appear anywhere?
|
||||
<br>If so, the test will finish once the notification disappears.
|
||||
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
var observer = {
|
||||
alertShow: false,
|
||||
observe: function (aSubject, aTopic, aData) {
|
||||
is(aData, "foobarcookie", "Checking whether the alert cookie was passed correctly");
|
||||
if (aTopic == "alertclickcallback") {
|
||||
todo(false, "Did someone click the notification while running mochitests? (Please don't.)");
|
||||
} else if (aTopic == "alertshow") {
|
||||
ok(!this.alertShow, "Alert should not be shown more than once");
|
||||
this.alertShow = true;
|
||||
} else {
|
||||
is(aTopic, "alertfinished", "Checking the topic for a finished notification");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function runTest() {
|
||||
const Cc = SpecialPowers.Cc;
|
||||
const Ci = SpecialPowers.Ci;
|
||||
|
||||
if (!("@mozilla.org/alerts-service;1" in Cc)) {
|
||||
todo(false, "Alerts service does not exist in this application");
|
||||
return;
|
||||
}
|
||||
|
||||
ok(true, "Alerts service exists in this application");
|
||||
|
||||
var notifier;
|
||||
try {
|
||||
notifier = Cc["@mozilla.org/alerts-service;1"].
|
||||
getService(Ci.nsIAlertsService);
|
||||
ok(true, "Alerts service is available");
|
||||
} catch (ex) {
|
||||
todo(false,
|
||||
"Alerts service is not available.", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var alertName = "fiorello";
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
notifier.showAlertNotification(null, "Notification test",
|
||||
"Surprise! I'm here to test notifications!",
|
||||
false, "foobarcookie", observer, alertName);
|
||||
ok(true, "showAlertNotification() succeeded. Waiting for notification...");
|
||||
|
||||
if ("@mozilla.org/system-alerts-service;1" in Cc) {
|
||||
// Notifications are native on OS X 10.8 and later, as well as GNOME
|
||||
// Shell with libnotify (bug 1236036). These notifications persist in the
|
||||
// Notification Center, and only fire the `alertfinished` event when
|
||||
// closed. For platforms where native notifications may be used, we need
|
||||
// to close explicitly to avoid a hang. This also works for XUL
|
||||
// notifications when running this test on OS X < 10.8, or a window
|
||||
// manager like Ubuntu Unity with incomplete libnotify support.
|
||||
notifier.closeAlert(alertName);
|
||||
}
|
||||
} catch (ex) {
|
||||
todo(false, "showAlertNotification() failed.", ex);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
runTest();
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,96 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Alerts Service</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
|
||||
<br>Alerts service, without observer "asynchronous" case.
|
||||
<br>
|
||||
<br>A notification should soon appear somewhere.
|
||||
<br>If there has been no crash when the notification (later) disappears, assume all is good.
|
||||
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
const Cc = SpecialPowers.Cc;
|
||||
const Ci = SpecialPowers.Ci;
|
||||
|
||||
const chromeScript = SpecialPowers.loadChromeScript(_ => {
|
||||
const { utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Timer.jsm");
|
||||
|
||||
function anyXULAlertsVisible() {
|
||||
var windows = Services.wm.getEnumerator("alert:alert");
|
||||
return windows.hasMoreElements();
|
||||
}
|
||||
|
||||
addMessageListener("anyXULAlertsVisible", anyXULAlertsVisible);
|
||||
|
||||
addMessageListener("waitForAlerts", function waitForAlerts() {
|
||||
if (anyXULAlertsVisible()) {
|
||||
setTimeout(waitForAlerts, 1000);
|
||||
} else {
|
||||
sendAsyncMessage("waitedForAlerts");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function waitForAlertsThenFinish() {
|
||||
chromeScript.addMessageListener("waitedForAlerts", function waitedForAlerts() {
|
||||
chromeScript.removeMessageListener("waitedForAlerts", waitedForAlerts);
|
||||
ok(true, "Alert disappeared.");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
chromeScript.sendAsyncMessage("waitForAlerts");
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
if (!("@mozilla.org/alerts-service;1" in Cc)) {
|
||||
todo(false, "Alerts service does not exist in this application");
|
||||
} else {
|
||||
ok(true, "Alerts service exists in this application");
|
||||
|
||||
var notifier;
|
||||
try {
|
||||
notifier = Cc["@mozilla.org/alerts-service;1"].
|
||||
getService(Ci.nsIAlertsService);
|
||||
ok(true, "Alerts service is available");
|
||||
} catch (ex) {
|
||||
todo(false, "Alerts service is not available.", ex);
|
||||
}
|
||||
|
||||
if (notifier) {
|
||||
try {
|
||||
notifier.showAlertNotification(null, "Notification test",
|
||||
"This notification has no observer");
|
||||
ok(true, "showAlertNotification() succeeded");
|
||||
} catch (ex) {
|
||||
todo(false, "showAlertNotification() failed.", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.requestFlakyTimeout("untriaged");
|
||||
|
||||
// sendSyncMessage returns an array of arrays: the outer array is from the
|
||||
// message manager, and the inner array is from the chrome script's listeners.
|
||||
// See the comment in test_SpecialPowersLoadChromeScript.html.
|
||||
var [[alertsVisible]] = chromeScript.sendSyncMessage("anyXULAlertsVisible");
|
||||
ok(!alertsVisible, "Alerts should not be present at the start of the test.");
|
||||
runTest();
|
||||
setTimeout(waitForAlertsThenFinish, 1000);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,168 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for alerts with requireInteraction</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
const Cc = SpecialPowers.Cc;
|
||||
const Ci = SpecialPowers.Ci;
|
||||
|
||||
const chromeScript = SpecialPowers.loadChromeScript(_ => {
|
||||
const { utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Timer.jsm");
|
||||
|
||||
addMessageListener("waitForXULAlert", function() {
|
||||
var timer = setTimeout(function() {
|
||||
Services.ww.unregisterNotification(windowObserver);
|
||||
sendAsyncMessage("waitForXULAlert", false);
|
||||
}, 2000);
|
||||
|
||||
var windowObserver = function(aSubject, aTopic, aData) {
|
||||
if (aTopic != "domwindowopened") {
|
||||
return;
|
||||
}
|
||||
|
||||
var win = aSubject.QueryInterface(Components.interfaces.nsIDOMWindow);
|
||||
win.addEventListener("load", function onLoad() {
|
||||
win.removeEventListener("load", onLoad);
|
||||
let windowType = win.document.documentElement.getAttribute("windowtype");
|
||||
if (windowType == "alert:alert") {
|
||||
clearTimeout(timer);
|
||||
Services.ww.unregisterNotification(windowObserver);
|
||||
|
||||
sendAsyncMessage("waitForXULAlert", true);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Services.ww.registerNotification(windowObserver);
|
||||
});
|
||||
});
|
||||
|
||||
var cookie = 0;
|
||||
function promiseCreateXULAlert(alertService, listener, name) {
|
||||
return new Promise(resolve => {
|
||||
chromeScript.addMessageListener("waitForXULAlert", function waitedForAlert(result) {
|
||||
chromeScript.removeMessageListener("waitForXULAlert", waitedForAlert);
|
||||
resolve(result);
|
||||
});
|
||||
|
||||
chromeScript.sendAsyncMessage("waitForXULAlert");
|
||||
alertService.showAlertNotification(null, "title", "body",
|
||||
true, cookie++, listener, name, null, null, null,
|
||||
null, false, true);
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function* test_require_interaction() {
|
||||
if (!("@mozilla.org/alerts-service;1" in Cc)) {
|
||||
todo(false, "Alerts service does not exist in this application.");
|
||||
return;
|
||||
}
|
||||
|
||||
ok(true, "Alerts service exists in this application.");
|
||||
|
||||
var alertService;
|
||||
try {
|
||||
alertService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
|
||||
ok(true, "Alerts service is available.");
|
||||
} catch (ex) {
|
||||
todo(false, "Alerts service is not available.");
|
||||
return;
|
||||
}
|
||||
|
||||
yield SpecialPowers.pushPrefEnv({"set": [
|
||||
[ "dom.webnotifications.requireinteraction.enabled", true ],
|
||||
[ "dom.webnotifications.requireinteraction.count", 2 ]
|
||||
]});
|
||||
|
||||
var expectedSequence = [
|
||||
"first show",
|
||||
"second show",
|
||||
"second finished",
|
||||
"second replacement show",
|
||||
"third finished",
|
||||
"first finished",
|
||||
"third replacement show",
|
||||
"second replacement finished",
|
||||
"third replacement finished"
|
||||
];
|
||||
|
||||
var actualSequence = [];
|
||||
|
||||
function createAlertListener(name, showCallback, finishCallback) {
|
||||
return (subject, topic, data) => {
|
||||
if (topic == "alertshow") {
|
||||
actualSequence.push(name + " show");
|
||||
if (showCallback) {
|
||||
showCallback();
|
||||
}
|
||||
} else if (topic == "alertfinished") {
|
||||
actualSequence.push(name + " finished");
|
||||
if (finishCallback) {
|
||||
finishCallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var xulAlertCreated = yield promiseCreateXULAlert(alertService,
|
||||
createAlertListener("first"), "first");
|
||||
if (!xulAlertCreated) {
|
||||
ok(true, "Platform does not use XUL alerts.");
|
||||
alertService.closeAlert("first");
|
||||
return;
|
||||
}
|
||||
|
||||
xulAlertCreated = yield promiseCreateXULAlert(alertService,
|
||||
createAlertListener("second"), "second");
|
||||
ok(xulAlertCreated, "Create XUL alert");
|
||||
|
||||
// Replace second alert
|
||||
xulAlertCreated = yield promiseCreateXULAlert(alertService,
|
||||
createAlertListener("second replacement"), "second");
|
||||
ok(xulAlertCreated, "Create XUL alert");
|
||||
|
||||
var testFinishResolve;
|
||||
var testFinishPromise = new Promise((resolve) => { testFinishResolve = resolve; });
|
||||
|
||||
xulAlertCreated = yield promiseCreateXULAlert(alertService,
|
||||
createAlertListener("third"), "third"),
|
||||
ok(!xulAlertCreated, "XUL alert should not be visible");
|
||||
|
||||
// Replace the not-yet-visible third alert.
|
||||
xulAlertCreated = yield promiseCreateXULAlert(alertService,
|
||||
createAlertListener("third replacement",
|
||||
function showCallback() {
|
||||
alertService.closeAlert("second");
|
||||
alertService.closeAlert("third");
|
||||
},
|
||||
function finishCallback() {
|
||||
// Check actual sequence of alert events compared to expected sequence.
|
||||
for (var i = 0; i < actualSequence.length; i++) {
|
||||
is(actualSequence[i], expectedSequence[i],
|
||||
"Alert callback at index " + i + " should be in expected order.");
|
||||
}
|
||||
|
||||
testFinishResolve();
|
||||
}), "third");
|
||||
|
||||
ok(!xulAlertCreated, "XUL alert should not be visible");
|
||||
|
||||
alertService.closeAlert("first");
|
||||
|
||||
yield testFinishPromise;
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,118 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Bug 1233086</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
const Cc = SpecialPowers.Cc;
|
||||
const Ci = SpecialPowers.Ci;
|
||||
const Services = SpecialPowers.Services;
|
||||
|
||||
const imageServerURL = "http://mochi.test:8888/tests/toolkit/components/alerts/test/image_server.sjs";
|
||||
|
||||
function makeAlert(...params) {
|
||||
var alert = Cc["@mozilla.org/alert-notification;1"]
|
||||
.createInstance(Ci.nsIAlertNotification);
|
||||
alert.init(...params);
|
||||
return alert;
|
||||
}
|
||||
|
||||
function promiseImage(alert, timeout = 0, userData = null) {
|
||||
return new Promise(resolve => {
|
||||
var isDone = false;
|
||||
function done(value) {
|
||||
ok(!isDone, "Should call the image listener once");
|
||||
isDone = true;
|
||||
resolve(value);
|
||||
}
|
||||
alert.loadImage(timeout, SpecialPowers.wrapCallbackObject({
|
||||
onImageReady(aUserData, aRequest) {
|
||||
done([true, aRequest, aUserData]);
|
||||
},
|
||||
onImageMissing(aUserData) {
|
||||
done([false, aUserData]);
|
||||
},
|
||||
}), SpecialPowers.wrap(userData));
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function* testContext() {
|
||||
var inUserData = Cc["@mozilla.org/supports-PRInt64;1"]
|
||||
.createInstance(Ci.nsISupportsPRInt64);
|
||||
inUserData.data = 123;
|
||||
|
||||
var alert = makeAlert(null, imageServerURL + "?f=image.png");
|
||||
var [ready, , userData] = yield promiseImage(alert, 0, inUserData);
|
||||
ok(ready, "Should load requested image");
|
||||
is(userData.QueryInterface(Ci.nsISupportsPRInt64).data, 123,
|
||||
"Should pass user data for loaded image");
|
||||
|
||||
alert = makeAlert(null, imageServerURL + "?s=404");
|
||||
[ready, userData] = yield promiseImage(alert, 0, inUserData);
|
||||
ok(!ready, "Should not load missing image");
|
||||
is(userData.QueryInterface(Ci.nsISupportsPRInt64).data, 123,
|
||||
"Should pass user data for missing image");
|
||||
});
|
||||
|
||||
add_task(function* testTimeout() {
|
||||
var alert = makeAlert(null, imageServerURL + "?f=image.png&t=3");
|
||||
var [ready] = yield promiseImage(alert, 1000);
|
||||
ok(!ready, "Should cancel request if timeout fires");
|
||||
|
||||
[ready, request] = yield promiseImage(alert, 45000);
|
||||
ok(ready, "Should load image if request finishes before timeout");
|
||||
});
|
||||
|
||||
add_task(function* testAnimatedGIF() {
|
||||
var alert = makeAlert(null, imageServerURL + "?f=image.gif");
|
||||
var [ready, request] = yield promiseImage(alert);
|
||||
ok(ready, "Should load first animated GIF frame");
|
||||
is(request.mimeType, "image/gif", "Should report correct GIF MIME type");
|
||||
is(request.image.width, 256, "GIF width should be 256px");
|
||||
is(request.image.height, 256, "GIF height should be 256px");
|
||||
});
|
||||
|
||||
add_task(function* testCancel() {
|
||||
var alert = makeAlert(null, imageServerURL + "?f=image.gif&t=180");
|
||||
yield new Promise((resolve, reject) => {
|
||||
var request = alert.loadImage(0, SpecialPowers.wrapCallbackObject({
|
||||
onImageReady() {
|
||||
reject(new Error("Should not load cancelled request"));
|
||||
},
|
||||
onImageMissing() {
|
||||
resolve();
|
||||
},
|
||||
}), null);
|
||||
request.cancel(SpecialPowers.Cr.NS_BINDING_ABORTED);
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* testMixedContent() {
|
||||
// Loading principal is HTTPS; image URL is HTTP.
|
||||
var origin = "https://mochi.test:8888";
|
||||
var principal = Services.scriptSecurityManager
|
||||
.createCodebasePrincipalFromOrigin(origin);
|
||||
|
||||
var alert = makeAlert(null, imageServerURL + "?f=image.png",
|
||||
null, null, false, null, null, null,
|
||||
null, principal);
|
||||
var [ready, request] = yield promiseImage(alert);
|
||||
ok(ready, "Should load cross-protocol image");
|
||||
is(request.mimeType, "image/png", "Should report correct MIME type");
|
||||
is(request.image.width, 32, "Width should be 32px");
|
||||
is(request.image.height, 32, "Height should be 32px");
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,103 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for multiple alerts</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
const Cc = SpecialPowers.Cc;
|
||||
const Ci = SpecialPowers.Ci;
|
||||
|
||||
const chromeScript = SpecialPowers.loadChromeScript(_ => {
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource://gre/modules/Timer.jsm");
|
||||
|
||||
const alertService = Components.classes["@mozilla.org/alerts-service;1"]
|
||||
.getService(Components.interfaces.nsIAlertsService);
|
||||
|
||||
addMessageListener("waitForPosition", function() {
|
||||
var timer = setTimeout(function() {
|
||||
Services.ww.unregisterNotification(windowObserver);
|
||||
sendAsyncMessage("waitedForPosition", null);
|
||||
}, 2000);
|
||||
|
||||
var windowObserver = function(aSubject, aTopic, aData) {
|
||||
if (aTopic != "domwindowopened") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Alerts are implemented using XUL.
|
||||
clearTimeout(timer);
|
||||
|
||||
Services.ww.unregisterNotification(windowObserver);
|
||||
|
||||
var win = aSubject.QueryInterface(Components.interfaces.nsIDOMWindow);
|
||||
win.addEventListener("pageshow", function onPageShow() {
|
||||
win.removeEventListener("pageshow", onPageShow, false);
|
||||
|
||||
var x = win.screenX;
|
||||
var y = win.screenY;
|
||||
|
||||
win.addEventListener("pagehide", function onPageHide() {
|
||||
win.removeEventListener("pagehide", onPageHide, false);
|
||||
sendAsyncMessage("waitedForPosition", { x, y });
|
||||
}, false);
|
||||
|
||||
alertService.closeAlert();
|
||||
}, false);
|
||||
};
|
||||
|
||||
Services.ww.registerNotification(windowObserver);
|
||||
});
|
||||
});
|
||||
|
||||
function promiseAlertPosition(alertService) {
|
||||
return new Promise(resolve => {
|
||||
chromeScript.addMessageListener("waitedForPosition", function waitedForPosition(result) {
|
||||
chromeScript.removeMessageListener("waitedForPosition", waitedForPosition);
|
||||
resolve(result);
|
||||
});
|
||||
chromeScript.sendAsyncMessage("waitForPosition");
|
||||
|
||||
alertService.showAlertNotification(null, "title", "body");
|
||||
ok(true, "Alert shown.");
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function* test_multiple_alerts() {
|
||||
if (!("@mozilla.org/alerts-service;1" in Cc)) {
|
||||
todo(false, "Alerts service does not exist in this application.");
|
||||
return;
|
||||
}
|
||||
|
||||
ok(true, "Alerts service exists in this application.");
|
||||
|
||||
var alertService;
|
||||
try {
|
||||
alertService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
|
||||
ok(true, "Alerts service is available.");
|
||||
} catch (ex) {
|
||||
todo(false, "Alerts service is not available.");
|
||||
return;
|
||||
}
|
||||
|
||||
var firstAlertPosition = yield promiseAlertPosition(alertService);
|
||||
if (!firstAlertPosition) {
|
||||
ok(true, "Platform does not use XUL alerts.");
|
||||
return;
|
||||
}
|
||||
|
||||
var secondAlertPosition = yield promiseAlertPosition(alertService);
|
||||
is(secondAlertPosition.x, firstAlertPosition.x, "Second alert should be opened in the same position.");
|
||||
is(secondAlertPosition.y, firstAlertPosition.y, "Second alert should be opened in the same position.");
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,122 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Bug 1202933</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
const Cc = SpecialPowers.Cc;
|
||||
const Ci = SpecialPowers.Ci;
|
||||
const Services = SpecialPowers.Services;
|
||||
|
||||
const notifier = Cc["@mozilla.org/alerts-service;1"]
|
||||
.getService(Ci.nsIAlertsService);
|
||||
|
||||
const chromeScript = SpecialPowers.loadChromeScript(_ => {
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
addMessageListener("anyXULAlertsVisible", function() {
|
||||
var windows = Services.wm.getEnumerator("alert:alert");
|
||||
return windows.hasMoreElements();
|
||||
});
|
||||
|
||||
addMessageListener("getAlertSource", function() {
|
||||
var alertWindows = Services.wm.getEnumerator("alert:alert");
|
||||
if (!alertWindows) {
|
||||
return null;
|
||||
}
|
||||
var alertWindow = alertWindows.getNext();
|
||||
return alertWindow.document.getElementById("alertSourceLabel").getAttribute("value");
|
||||
});
|
||||
});
|
||||
|
||||
function notify(alertName, principal) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var source;
|
||||
function observe(subject, topic, data) {
|
||||
if (topic == "alertclickcallback") {
|
||||
reject(new Error("Alerts should not be clicked during test"));
|
||||
} else if (topic == "alertshow") {
|
||||
source = chromeScript.sendSyncMessage("getAlertSource")[0][0];
|
||||
notifier.closeAlert(alertName);
|
||||
} else {
|
||||
is(topic, "alertfinished", "Should hide alert");
|
||||
resolve(source);
|
||||
}
|
||||
}
|
||||
notifier.showAlertNotification(null, "Notification test",
|
||||
"Surprise! I'm here to test notifications!",
|
||||
false, alertName, observe, alertName,
|
||||
null, null, null, principal);
|
||||
if (SpecialPowers.Services.appinfo.OS == "Darwin") {
|
||||
notifier.closeAlert(alertName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function* testNoPrincipal() {
|
||||
var source = yield notify("noPrincipal", null);
|
||||
ok(!source, "Should omit source without principal");
|
||||
}
|
||||
|
||||
function* testSystemPrincipal() {
|
||||
var principal = Services.scriptSecurityManager.getSystemPrincipal();
|
||||
var source = yield notify("systemPrincipal", principal);
|
||||
ok(!source, "Should omit source for system principal");
|
||||
}
|
||||
|
||||
function* testNullPrincipal() {
|
||||
var principal = Services.scriptSecurityManager.createNullPrincipal({});
|
||||
var source = yield notify("nullPrincipal", principal);
|
||||
ok(!source, "Should omit source for null principal");
|
||||
}
|
||||
|
||||
function* testNodePrincipal() {
|
||||
var principal = SpecialPowers.wrap(document).nodePrincipal;
|
||||
var source = yield notify("nodePrincipal", principal);
|
||||
|
||||
var stringBundle = Services.strings.createBundle(
|
||||
"chrome://alerts/locale/alert.properties"
|
||||
);
|
||||
var localizedSource = stringBundle.formatStringFromName(
|
||||
"source.label", [principal.URI.hostPort], 1);
|
||||
is(source, localizedSource, "Should include source for node principal");
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
if (!("@mozilla.org/alerts-service;1" in Cc)) {
|
||||
todo(false, "Alerts service does not exist in this application");
|
||||
return;
|
||||
}
|
||||
|
||||
if ("@mozilla.org/system-alerts-service;1" in Cc) {
|
||||
todo(false, "Native alerts service exists in this application");
|
||||
return;
|
||||
}
|
||||
|
||||
ok(true, "Alerts service exists in this application");
|
||||
|
||||
// sendSyncMessage returns an array of arrays. See the comments in
|
||||
// test_alerts_noobserve.html and test_SpecialPowersLoadChromeScript.html.
|
||||
var [[alertsVisible]] = chromeScript.sendSyncMessage("anyXULAlertsVisible");
|
||||
ok(!alertsVisible, "Alerts should not be present at the start of the test.");
|
||||
|
||||
add_task(testNoPrincipal);
|
||||
add_task(testSystemPrincipal);
|
||||
add_task(testNullPrincipal);
|
||||
add_task(testNodePrincipal);
|
||||
}
|
||||
|
||||
runTest();
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -4,22 +4,12 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini']
|
||||
|
||||
XPIDL_MODULE = 'toolkit_asyncshutdown'
|
||||
XPIDL_SOURCES += ['nsIAsyncShutdown.idl']
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIAsyncShutdown.idl',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'AsyncShutdown.jsm',
|
||||
]
|
||||
EXTRA_JS_MODULES += ['AsyncShutdown.jsm']
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'nsAsyncShutdown.js',
|
||||
'nsAsyncShutdown.manifest',
|
||||
]
|
||||
|
||||
with Files('**'):
|
||||
BUG_COMPONENT = ('Toolkit', 'Async Tooling')
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"../../../../../testing/xpcshell/xpcshell.eslintrc.js"
|
||||
]
|
||||
};
|
|
@ -1,174 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
var Cu = Components.utils;
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/AsyncShutdown.jsm");
|
||||
|
||||
var asyncShutdownService = Cc["@mozilla.org/async-shutdown-service;1"].
|
||||
getService(Ci.nsIAsyncShutdownService);
|
||||
|
||||
|
||||
Services.prefs.setBoolPref("toolkit.asyncshutdown.testing", true);
|
||||
|
||||
/**
|
||||
* Utility function used to provide the same API for various sources
|
||||
* of async shutdown barriers.
|
||||
*
|
||||
* @param {string} kind One of
|
||||
* - "phase" to test an AsyncShutdown phase;
|
||||
* - "barrier" to test an instance of AsyncShutdown.Barrier;
|
||||
* - "xpcom-barrier" to test an instance of nsIAsyncShutdownBarrier;
|
||||
* - "xpcom-barrier-unwrapped" to test the field `jsclient` of a nsIAsyncShutdownClient.
|
||||
*
|
||||
* @return An object with the following methods:
|
||||
* - addBlocker() - the same method as AsyncShutdown phases and barrier clients
|
||||
* - wait() - trigger the resolution of the lock
|
||||
*/
|
||||
function makeLock(kind) {
|
||||
if (kind == "phase") {
|
||||
let topic = "test-Phase-" + ++makeLock.counter;
|
||||
let phase = AsyncShutdown._getPhase(topic);
|
||||
return {
|
||||
addBlocker: function(...args) {
|
||||
return phase.addBlocker(...args);
|
||||
},
|
||||
removeBlocker: function(blocker) {
|
||||
return phase.removeBlocker(blocker);
|
||||
},
|
||||
wait: function() {
|
||||
Services.obs.notifyObservers(null, topic, null);
|
||||
return Promise.resolve();
|
||||
}
|
||||
};
|
||||
} else if (kind == "barrier") {
|
||||
let name = "test-Barrier-" + ++makeLock.counter;
|
||||
let barrier = new AsyncShutdown.Barrier(name);
|
||||
return {
|
||||
addBlocker: barrier.client.addBlocker,
|
||||
removeBlocker: barrier.client.removeBlocker,
|
||||
wait: function() {
|
||||
return barrier.wait();
|
||||
}
|
||||
};
|
||||
} else if (kind == "xpcom-barrier") {
|
||||
let name = "test-xpcom-Barrier-" + ++makeLock.counter;
|
||||
let barrier = asyncShutdownService.makeBarrier(name);
|
||||
return {
|
||||
addBlocker: function(blockerName, condition, state) {
|
||||
if (condition == null) {
|
||||
// Slight trick as `null` or `undefined` cannot be used as keys
|
||||
// for `xpcomMap`. Note that this has no incidence on the result
|
||||
// of the test as the XPCOM interface imposes that the condition
|
||||
// is a method, so it cannot be `null`/`undefined`.
|
||||
condition = "<this case can't happen with the xpcom interface>";
|
||||
}
|
||||
let blocker = makeLock.xpcomMap.get(condition);
|
||||
if (!blocker) {
|
||||
blocker = {
|
||||
name: blockerName,
|
||||
state: state,
|
||||
blockShutdown: function(aBarrierClient) {
|
||||
return Task.spawn(function*() {
|
||||
try {
|
||||
if (typeof condition == "function") {
|
||||
yield Promise.resolve(condition());
|
||||
} else {
|
||||
yield Promise.resolve(condition);
|
||||
}
|
||||
} finally {
|
||||
aBarrierClient.removeBlocker(blocker);
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
makeLock.xpcomMap.set(condition, blocker);
|
||||
}
|
||||
let {fileName, lineNumber, stack} = (new Error());
|
||||
return barrier.client.addBlocker(blocker, fileName, lineNumber, stack);
|
||||
},
|
||||
removeBlocker: function(condition) {
|
||||
let blocker = makeLock.xpcomMap.get(condition);
|
||||
if (!blocker) {
|
||||
return;
|
||||
}
|
||||
barrier.client.removeBlocker(blocker);
|
||||
},
|
||||
wait: function() {
|
||||
return new Promise(resolve => {
|
||||
barrier.wait(resolve);
|
||||
});
|
||||
}
|
||||
};
|
||||
} else if ("unwrapped-xpcom-barrier") {
|
||||
let name = "unwrapped-xpcom-barrier-" + ++makeLock.counter;
|
||||
let barrier = asyncShutdownService.makeBarrier(name);
|
||||
let client = barrier.client.jsclient;
|
||||
return {
|
||||
addBlocker: client.addBlocker,
|
||||
removeBlocker: client.removeBlocker,
|
||||
wait: function() {
|
||||
return new Promise(resolve => {
|
||||
barrier.wait(resolve);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
throw new TypeError("Unknown kind " + kind);
|
||||
}
|
||||
makeLock.counter = 0;
|
||||
makeLock.xpcomMap = new Map(); // Note: Not a WeakMap as we wish to handle non-gc-able keys (e.g. strings)
|
||||
|
||||
/**
|
||||
* An asynchronous task that takes several ticks to complete.
|
||||
*
|
||||
* @param {*=} resolution The value with which the resulting promise will be
|
||||
* resolved once the task is complete. This may be a rejected promise,
|
||||
* in which case the resulting promise will itself be rejected.
|
||||
* @param {object=} outResult An object modified by side-effect during the task.
|
||||
* Initially, its field |isFinished| is set to |false|. Once the task is
|
||||
* complete, its field |isFinished| is set to |true|.
|
||||
*
|
||||
* @return {promise} A promise fulfilled once the task is complete
|
||||
*/
|
||||
function longRunningAsyncTask(resolution = undefined, outResult = {}) {
|
||||
outResult.isFinished = false;
|
||||
if (!("countFinished" in outResult)) {
|
||||
outResult.countFinished = 0;
|
||||
}
|
||||
let deferred = Promise.defer();
|
||||
do_timeout(100, function() {
|
||||
++outResult.countFinished;
|
||||
outResult.isFinished = true;
|
||||
deferred.resolve(resolution);
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function get_exn(f) {
|
||||
try {
|
||||
f();
|
||||
return null;
|
||||
} catch (ex) {
|
||||
return ex;
|
||||
}
|
||||
}
|
||||
|
||||
function do_check_exn(exn, constructor) {
|
||||
do_check_neq(exn, null);
|
||||
if (exn.name == constructor) {
|
||||
do_check_eq(exn.constructor.name, constructor);
|
||||
return;
|
||||
}
|
||||
do_print("Wrong error constructor");
|
||||
do_print(exn.constructor.name);
|
||||
do_print(exn.stack);
|
||||
do_check_true(false);
|
||||
}
|
|
@ -1,194 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://gre/modules/PromiseUtils.jsm", this);
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_no_condition() {
|
||||
for (let kind of ["phase", "barrier", "xpcom-barrier", "xpcom-barrier-unwrapped"]) {
|
||||
do_print("Testing a barrier with no condition (" + kind + ")");
|
||||
let lock = makeLock(kind);
|
||||
yield lock.wait();
|
||||
do_print("Barrier with no condition didn't lock");
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* test_phase_various_failures() {
|
||||
for (let kind of ["phase", "barrier", "xpcom-barrier", "xpcom-barrier-unwrapped"]) {
|
||||
do_print("Kind: " + kind);
|
||||
// Testing with wrong arguments
|
||||
let lock = makeLock(kind);
|
||||
|
||||
Assert.throws(() => lock.addBlocker(), /TypeError|NS_ERROR_XPC_JAVASCRIPT_ERROR_WITH_DETAILS/);
|
||||
Assert.throws(() => lock.addBlocker(null, true), /TypeError|NS_ERROR_XPC_JAVASCRIPT_ERROR_WITH_DETAILS/);
|
||||
|
||||
if (kind != "xpcom-barrier") {
|
||||
// xpcom-barrier actually expects a string in that position
|
||||
Assert.throws(() => lock.addBlocker("Test 2", () => true, "not a function"), /TypeError/);
|
||||
}
|
||||
|
||||
// Attempting to add a blocker after we are done waiting
|
||||
yield lock.wait();
|
||||
Assert.throws(() => lock.addBlocker("Test 3", () => true), /is finished/);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* test_reentrant() {
|
||||
do_print("Ensure that we can call addBlocker from within a blocker");
|
||||
|
||||
for (let kind of ["phase", "barrier", "xpcom-barrier", "xpcom-barrier-unwrapped"]) {
|
||||
do_print("Kind: " + kind);
|
||||
let lock = makeLock(kind);
|
||||
|
||||
let deferredOuter = PromiseUtils.defer();
|
||||
let deferredInner = PromiseUtils.defer();
|
||||
let deferredBlockInner = PromiseUtils.defer();
|
||||
|
||||
lock.addBlocker("Outer blocker", () => {
|
||||
do_print("Entering outer blocker");
|
||||
deferredOuter.resolve();
|
||||
lock.addBlocker("Inner blocker", () => {
|
||||
do_print("Entering inner blocker");
|
||||
deferredInner.resolve();
|
||||
return deferredBlockInner.promise;
|
||||
});
|
||||
});
|
||||
|
||||
// Note that phase-style locks spin the event loop and do not return from
|
||||
// `lock.wait()` until after all blockers have been resolved. Therefore,
|
||||
// to be able to test them, we need to dispatch the following steps to the
|
||||
// event loop before calling `lock.wait()`, which we do by forcing
|
||||
// a Promise.resolve().
|
||||
//
|
||||
let promiseSteps = Task.spawn(function* () {
|
||||
yield Promise.resolve();
|
||||
|
||||
do_print("Waiting until we have entered the outer blocker");
|
||||
yield deferredOuter.promise;
|
||||
|
||||
do_print("Waiting until we have entered the inner blocker");
|
||||
yield deferredInner.promise;
|
||||
|
||||
do_print("Allowing the lock to resolve")
|
||||
deferredBlockInner.resolve();
|
||||
});
|
||||
|
||||
do_print("Starting wait");
|
||||
yield lock.wait();
|
||||
|
||||
do_print("Waiting until all steps have been walked");
|
||||
yield promiseSteps;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_phase_removeBlocker() {
|
||||
do_print("Testing that we can call removeBlocker before, during and after the call to wait()");
|
||||
|
||||
for (let kind of ["phase", "barrier", "xpcom-barrier", "xpcom-barrier-unwrapped"]) {
|
||||
|
||||
do_print("Switching to kind " + kind);
|
||||
do_print("Attempt to add then remove a blocker before wait()");
|
||||
let lock = makeLock(kind);
|
||||
let blocker = () => {
|
||||
do_print("This promise will never be resolved");
|
||||
return Promise.defer().promise;
|
||||
};
|
||||
|
||||
lock.addBlocker("Wait forever", blocker);
|
||||
let do_remove_blocker = function(aLock, aBlocker, aShouldRemove) {
|
||||
do_print("Attempting to remove blocker " + aBlocker + ", expecting result " + aShouldRemove);
|
||||
if (kind == "xpcom-barrier") {
|
||||
// The xpcom variant always returns `undefined`, so we can't
|
||||
// check its result.
|
||||
aLock.removeBlocker(aBlocker);
|
||||
return;
|
||||
}
|
||||
do_check_eq(aLock.removeBlocker(aBlocker), aShouldRemove);
|
||||
};
|
||||
do_remove_blocker(lock, blocker, true);
|
||||
do_remove_blocker(lock, blocker, false);
|
||||
do_print("Attempt to remove non-registered blockers before wait()");
|
||||
do_remove_blocker(lock, "foo", false);
|
||||
do_remove_blocker(lock, null, false);
|
||||
do_print("Waiting (should lift immediately)");
|
||||
yield lock.wait();
|
||||
|
||||
do_print("Attempt to add a blocker then remove it during wait()");
|
||||
lock = makeLock(kind);
|
||||
let blockers = [
|
||||
() => {
|
||||
do_print("This blocker will self-destruct");
|
||||
do_remove_blocker(lock, blockers[0], true);
|
||||
return Promise.defer().promise;
|
||||
},
|
||||
() => {
|
||||
do_print("This blocker will self-destruct twice");
|
||||
do_remove_blocker(lock, blockers[1], true);
|
||||
do_remove_blocker(lock, blockers[1], false);
|
||||
return Promise.defer().promise;
|
||||
},
|
||||
() => {
|
||||
do_print("Attempt to remove non-registered blockers during wait()");
|
||||
do_remove_blocker(lock, "foo", false);
|
||||
do_remove_blocker(lock, null, false);
|
||||
}
|
||||
];
|
||||
for (let i in blockers) {
|
||||
lock.addBlocker("Wait forever again: " + i, blockers[i]);
|
||||
}
|
||||
do_print("Waiting (should lift very quickly)");
|
||||
yield lock.wait();
|
||||
do_remove_blocker(lock, blockers[0], false);
|
||||
|
||||
|
||||
do_print("Attempt to remove a blocker after wait");
|
||||
lock = makeLock(kind);
|
||||
blocker = Promise.resolve.bind(Promise);
|
||||
yield lock.wait();
|
||||
do_remove_blocker(lock, blocker, false);
|
||||
|
||||
do_print("Attempt to remove non-registered blocker after wait()");
|
||||
do_remove_blocker(lock, "foo", false);
|
||||
do_remove_blocker(lock, null, false);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
add_task(function* test_state() {
|
||||
do_print("Testing information contained in `state`");
|
||||
|
||||
let BLOCKER_NAME = "test_state blocker " + Math.random();
|
||||
|
||||
// Set up the barrier. Note that we cannot test `barrier.state`
|
||||
// immediately, as it initially contains "Not started"
|
||||
let barrier = new AsyncShutdown.Barrier("test_filename");
|
||||
let deferred = Promise.defer();
|
||||
let {filename, lineNumber} = Components.stack;
|
||||
barrier.client.addBlocker(BLOCKER_NAME,
|
||||
function() {
|
||||
return deferred.promise;
|
||||
});
|
||||
|
||||
let promiseDone = barrier.wait();
|
||||
|
||||
// Now that we have called `wait()`, the state contains interesting things
|
||||
let state = barrier.state[0];
|
||||
do_print("State: " + JSON.stringify(barrier.state, null, "\t"));
|
||||
Assert.equal(state.filename, filename);
|
||||
Assert.equal(state.lineNumber, lineNumber + 1);
|
||||
Assert.equal(state.name, BLOCKER_NAME);
|
||||
Assert.ok(state.stack.some(x => x.includes("test_state")), "The stack contains the caller function's name");
|
||||
Assert.ok(state.stack.some(x => x.includes(filename)), "The stack contains the calling file's name");
|
||||
|
||||
deferred.resolve();
|
||||
yield promiseDone;
|
||||
});
|
||||
|
||||
add_task(function*() {
|
||||
Services.prefs.clearUserPref("toolkit.asyncshutdown.testing");
|
||||
});
|
|
@ -1,96 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
//
|
||||
// This file contains tests that need to leave uncaught asynchronous
|
||||
// errors. If your test catches all its asynchronous errors, please
|
||||
// put it in another file.
|
||||
//
|
||||
|
||||
Promise.Debugging.clearUncaughtErrorObservers();
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_phase_simple_async() {
|
||||
do_print("Testing various combinations of a phase with a single condition");
|
||||
for (let kind of ["phase", "barrier", "xpcom-barrier", "xpcom-barrier-unwrapped"]) {
|
||||
for (let arg of [undefined, null, "foo", 100, new Error("BOOM")]) {
|
||||
for (let resolution of [arg, Promise.reject(arg)]) {
|
||||
for (let success of [false, true]) {
|
||||
for (let state of [[null],
|
||||
[],
|
||||
[() => "some state"],
|
||||
[function() {
|
||||
throw new Error("State BOOM"); }],
|
||||
[function() {
|
||||
return {
|
||||
toJSON: function() {
|
||||
throw new Error("State.toJSON BOOM");
|
||||
}
|
||||
};
|
||||
}]]) {
|
||||
// Asynchronous phase
|
||||
do_print("Asynchronous test with " + arg + ", " + resolution + ", " + kind);
|
||||
let lock = makeLock(kind);
|
||||
let outParam = { isFinished: false };
|
||||
lock.addBlocker(
|
||||
"Async test",
|
||||
function() {
|
||||
if (success) {
|
||||
return longRunningAsyncTask(resolution, outParam);
|
||||
}
|
||||
throw resolution;
|
||||
},
|
||||
...state
|
||||
);
|
||||
do_check_false(outParam.isFinished);
|
||||
yield lock.wait();
|
||||
do_check_eq(outParam.isFinished, success);
|
||||
}
|
||||
}
|
||||
|
||||
// Synchronous phase - just test that we don't throw/freeze
|
||||
do_print("Synchronous test with " + arg + ", " + resolution + ", " + kind);
|
||||
let lock = makeLock(kind);
|
||||
lock.addBlocker(
|
||||
"Sync test",
|
||||
resolution
|
||||
);
|
||||
yield lock.wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* test_phase_many() {
|
||||
do_print("Testing various combinations of a phase with many conditions");
|
||||
for (let kind of ["phase", "barrier", "xpcom-barrier", "xpcom-barrier-unwrapped"]) {
|
||||
let lock = makeLock(kind);
|
||||
let outParams = [];
|
||||
for (let arg of [undefined, null, "foo", 100, new Error("BOOM")]) {
|
||||
for (let resolve of [true, false]) {
|
||||
do_print("Testing with " + kind + ", " + arg + ", " + resolve);
|
||||
let resolution = resolve ? arg : Promise.reject(arg);
|
||||
let outParam = { isFinished: false };
|
||||
lock.addBlocker(
|
||||
"Test " + Math.random(),
|
||||
() => longRunningAsyncTask(resolution, outParam)
|
||||
);
|
||||
}
|
||||
}
|
||||
do_check_true(outParams.every((x) => !x.isFinished));
|
||||
yield lock.wait();
|
||||
do_check_true(outParams.every((x) => x.isFinished));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
add_task(function*() {
|
||||
Services.prefs.clearUserPref("toolkit.asyncshutdown.testing");
|
||||
});
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Test conversion between nsIPropertyBag and JS values.
|
||||
*/
|
||||
|
||||
var PropertyBagConverter = asyncShutdownService.wrappedJSObject._propertyBagConverter;
|
||||
|
||||
function run_test() {
|
||||
test_conversions();
|
||||
}
|
||||
|
||||
function normalize(obj) {
|
||||
if (obj == null || typeof obj != "object") {
|
||||
return obj;
|
||||
}
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map(normalize);
|
||||
}
|
||||
let result = {};
|
||||
for (let k of Object.keys(obj).sort()) {
|
||||
result[k] = normalize(obj[k]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function test_conversions() {
|
||||
const SAMPLES = [
|
||||
// Simple values
|
||||
1,
|
||||
true,
|
||||
"string",
|
||||
null,
|
||||
|
||||
// Objects
|
||||
{
|
||||
a: 1,
|
||||
b: true,
|
||||
c: "string",
|
||||
d:.5,
|
||||
e: [2, false, "another string", .3],
|
||||
f: [],
|
||||
g: {
|
||||
a2: 1,
|
||||
b2: true,
|
||||
c2: "string",
|
||||
d2:.5,
|
||||
e2: [2, false, "another string", .3],
|
||||
f2: [],
|
||||
g2: [{
|
||||
a3: 1,
|
||||
b3: true,
|
||||
c3: "string",
|
||||
d3:.5,
|
||||
e3: [2, false, "another string", .3],
|
||||
f3: [],
|
||||
g3: {}
|
||||
}]
|
||||
}
|
||||
}];
|
||||
|
||||
for (let sample of SAMPLES) {
|
||||
let stringified = JSON.stringify(normalize(sample), null, "\t");
|
||||
do_print("Testing conversions of " + stringified);
|
||||
let rewrites = [sample];
|
||||
for (let i = 1; i < 3; ++i) {
|
||||
let source = rewrites[i - 1];
|
||||
let bag = PropertyBagConverter.fromValue(source);
|
||||
do_print(" => " + bag);
|
||||
if (source == null) {
|
||||
Assert.ok(bag == null, "The bag is null");
|
||||
} else if (typeof source == "object") {
|
||||
Assert.ok(bag instanceof Ci.nsIPropertyBag, "The bag is a property bag");
|
||||
} else {
|
||||
Assert.ok(typeof bag != "object", "The bag is not an object");
|
||||
}
|
||||
let dest = PropertyBagConverter.toValue(bag);
|
||||
let restringified = JSON.stringify(normalize(dest), null, "\t");
|
||||
do_print("Comparing");
|
||||
do_print(stringified);
|
||||
do_print(restringified);
|
||||
Assert.deepEqual(sample, dest, "Testing after " + i + " conversions");
|
||||
rewrites.push(dest);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
[DEFAULT]
|
||||
head=head.js
|
||||
tail=
|
||||
skip-if = toolkit == 'android'
|
||||
|
||||
[test_AsyncShutdown.js]
|
||||
[test_AsyncShutdown_leave_uncaught.js]
|
||||
[test_converters.js]
|
|
@ -4,8 +4,6 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIAutoCompleteController.idl',
|
||||
'nsIAutoCompleteInput.idl',
|
||||
|
@ -23,6 +21,3 @@ UNIFIED_SOURCES += [
|
|||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
with Files('**'):
|
||||
BUG_COMPONENT = ('Toolkit', 'Autocomplete')
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"../../../../../testing/xpcshell/xpcshell.eslintrc.js"
|
||||
]
|
||||
};
|
|
@ -1,211 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
|
||||
/**
|
||||
* Dummy nsIAutoCompleteInput source that returns
|
||||
* the given list of AutoCompleteSearch names.
|
||||
*
|
||||
* Implements only the methods needed for this test.
|
||||
*/
|
||||
function AutoCompleteInputBase(aSearches) {
|
||||
this.searches = aSearches;
|
||||
}
|
||||
AutoCompleteInputBase.prototype = {
|
||||
|
||||
// Array of AutoCompleteSearch names
|
||||
searches: null,
|
||||
|
||||
minResultsForPopup: 0,
|
||||
timeout: 10,
|
||||
searchParam: "",
|
||||
textValue: "",
|
||||
disableAutoComplete: false,
|
||||
completeDefaultIndex: false,
|
||||
|
||||
// Text selection range
|
||||
_selStart: 0,
|
||||
_selEnd: 0,
|
||||
get selectionStart() {
|
||||
return this._selStart;
|
||||
},
|
||||
get selectionEnd() {
|
||||
return this._selEnd;
|
||||
},
|
||||
selectTextRange: function(aStart, aEnd) {
|
||||
this._selStart = aStart;
|
||||
this._selEnd = aEnd;
|
||||
},
|
||||
|
||||
get searchCount() {
|
||||
return this.searches.length;
|
||||
},
|
||||
|
||||
getSearchAt: function(aIndex) {
|
||||
return this.searches[aIndex];
|
||||
},
|
||||
|
||||
onSearchBegin: function() {},
|
||||
onSearchComplete: function() {},
|
||||
|
||||
popupOpen: false,
|
||||
|
||||
get popup() {
|
||||
if (!this._popup) {
|
||||
this._popup = new AutocompletePopupBase(this);
|
||||
}
|
||||
return this._popup;
|
||||
},
|
||||
|
||||
// nsISupports implementation
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompleteInput])
|
||||
}
|
||||
|
||||
/**
|
||||
* nsIAutoCompleteResult implementation
|
||||
*/
|
||||
function AutoCompleteResultBase(aValues) {
|
||||
this._values = aValues;
|
||||
}
|
||||
AutoCompleteResultBase.prototype = {
|
||||
|
||||
// Arrays
|
||||
_values: null,
|
||||
_comments: [],
|
||||
_styles: [],
|
||||
_finalCompleteValues: [],
|
||||
|
||||
searchString: "",
|
||||
searchResult: null,
|
||||
|
||||
defaultIndex: -1,
|
||||
|
||||
_typeAheadResult: false,
|
||||
get typeAheadResult() {
|
||||
return this._typeAheadResult;
|
||||
},
|
||||
|
||||
get matchCount() {
|
||||
return this._values.length;
|
||||
},
|
||||
|
||||
getValueAt: function(aIndex) {
|
||||
return this._values[aIndex];
|
||||
},
|
||||
|
||||
getLabelAt: function(aIndex) {
|
||||
return this.getValueAt(aIndex);
|
||||
},
|
||||
|
||||
getCommentAt: function(aIndex) {
|
||||
return this._comments[aIndex];
|
||||
},
|
||||
|
||||
getStyleAt: function(aIndex) {
|
||||
return this._styles[aIndex];
|
||||
},
|
||||
|
||||
getImageAt: function(aIndex) {
|
||||
return "";
|
||||
},
|
||||
|
||||
getFinalCompleteValueAt: function(aIndex) {
|
||||
return this._finalCompleteValues[aIndex] || this._values[aIndex];
|
||||
},
|
||||
|
||||
removeValueAt: function (aRowIndex, aRemoveFromDb) {},
|
||||
|
||||
// nsISupports implementation
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompleteResult])
|
||||
}
|
||||
|
||||
/**
|
||||
* nsIAutoCompleteSearch implementation that always returns
|
||||
* the same result set.
|
||||
*/
|
||||
function AutoCompleteSearchBase(aName, aResult) {
|
||||
this.name = aName;
|
||||
this._result = aResult;
|
||||
}
|
||||
AutoCompleteSearchBase.prototype = {
|
||||
|
||||
// Search name. Used by AutoCompleteController
|
||||
name: null,
|
||||
|
||||
// AutoCompleteResult
|
||||
_result: null,
|
||||
|
||||
startSearch: function(aSearchString,
|
||||
aSearchParam,
|
||||
aPreviousResult,
|
||||
aListener) {
|
||||
var result = this._result;
|
||||
|
||||
result.searchResult = Ci.nsIAutoCompleteResult.RESULT_SUCCESS;
|
||||
aListener.onSearchResult(this, result);
|
||||
},
|
||||
|
||||
stopSearch: function() {},
|
||||
|
||||
// nsISupports implementation
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory,
|
||||
Ci.nsIAutoCompleteSearch]),
|
||||
|
||||
// nsIFactory implementation
|
||||
createInstance: function(outer, iid) {
|
||||
return this.QueryInterface(iid);
|
||||
}
|
||||
}
|
||||
|
||||
function AutocompletePopupBase(input) {
|
||||
this.input = input;
|
||||
}
|
||||
AutocompletePopupBase.prototype = {
|
||||
selectedIndex: 0,
|
||||
invalidate() {},
|
||||
selectBy(reverse, page) {
|
||||
let numRows = this.input.controller.matchCount;
|
||||
if (numRows > 0) {
|
||||
let delta = reverse ? -1 : 1;
|
||||
this.selectedIndex = (this.selectedIndex + delta) % numRows;
|
||||
if (this.selectedIndex < 0) {
|
||||
this.selectedIndex = numRows - 1;
|
||||
}
|
||||
}
|
||||
},
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompletePopup]),
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper to register an AutoCompleteSearch with the given name.
|
||||
* Allows the AutoCompleteController to find the search.
|
||||
*/
|
||||
function registerAutoCompleteSearch(aSearch) {
|
||||
var name = "@mozilla.org/autocomplete/search;1?name=" + aSearch.name;
|
||||
var cid = Cc["@mozilla.org/uuid-generator;1"].
|
||||
getService(Ci.nsIUUIDGenerator).
|
||||
generateUUID();
|
||||
|
||||
var desc = "Test AutoCompleteSearch";
|
||||
var componentManager = Components.manager
|
||||
.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
componentManager.registerFactory(cid, desc, name, aSearch);
|
||||
|
||||
// Keep the id on the object so we can unregister later
|
||||
aSearch.cid = cid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to unregister an AutoCompleteSearch.
|
||||
*/
|
||||
function unregisterAutoCompleteSearch(aSearch) {
|
||||
var componentManager = Components.manager
|
||||
.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
componentManager.unregisterFactory(aSearch.cid, aSearch);
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
var gResultListener = {
|
||||
_lastResult: null,
|
||||
_lastValue: "",
|
||||
_lastRemoveFromDb: false,
|
||||
|
||||
onValueRemoved: function(aResult, aValue, aRemoveFromDb) {
|
||||
this._lastResult = aResult;
|
||||
this._lastValue = aValue;
|
||||
this._lastRemoveFromDb = aRemoveFromDb;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// main
|
||||
function run_test() {
|
||||
var result = Cc["@mozilla.org/autocomplete/simple-result;1"].
|
||||
createInstance(Ci.nsIAutoCompleteSimpleResult);
|
||||
result.appendMatch("a", "");
|
||||
result.appendMatch("b", "");
|
||||
result.appendMatch("c", "");
|
||||
result.setListener(gResultListener);
|
||||
do_check_eq(result.matchCount, 3);
|
||||
result.removeValueAt(0, true);
|
||||
do_check_eq(result.matchCount, 2);
|
||||
do_check_eq(gResultListener._lastResult, result);
|
||||
do_check_eq(gResultListener._lastValue, "a");
|
||||
do_check_eq(gResultListener._lastRemoveFromDb, true);
|
||||
|
||||
result.removeValueAt(0, false);
|
||||
do_check_eq(result.matchCount, 1);
|
||||
do_check_eq(gResultListener._lastValue, "b");
|
||||
do_check_eq(gResultListener._lastRemoveFromDb, false);
|
||||
|
||||
// check that we don't get notified if the listener is unset
|
||||
result.setListener(null);
|
||||
result.removeValueAt(0, true); // "c"
|
||||
do_check_eq(result.matchCount, 0);
|
||||
do_check_eq(gResultListener._lastValue, "b");
|
||||
}
|
|
@ -1,285 +0,0 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Unit test for Bug 378079 - AutoComplete returns invalid rows when
|
||||
* more than one AutoCompleteSearch is used.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Dummy nsIAutoCompleteInput source that returns
|
||||
* the given list of AutoCompleteSearch names.
|
||||
*
|
||||
* Implements only the methods needed for this test.
|
||||
*/
|
||||
function AutoCompleteInput(aSearches) {
|
||||
this.searches = aSearches;
|
||||
}
|
||||
AutoCompleteInput.prototype = {
|
||||
constructor: AutoCompleteInput,
|
||||
|
||||
// Array of AutoCompleteSearch names
|
||||
searches: null,
|
||||
|
||||
minResultsForPopup: 0,
|
||||
timeout: 10,
|
||||
searchParam: "",
|
||||
textValue: "",
|
||||
disableAutoComplete: false,
|
||||
completeDefaultIndex: false,
|
||||
|
||||
get searchCount() {
|
||||
return this.searches.length;
|
||||
},
|
||||
|
||||
getSearchAt: function(aIndex) {
|
||||
return this.searches[aIndex];
|
||||
},
|
||||
|
||||
onSearchBegin: function() {},
|
||||
onSearchComplete: function() {},
|
||||
|
||||
popupOpen: false,
|
||||
|
||||
popup: {
|
||||
setSelectedIndex: function(aIndex) {},
|
||||
invalidate: function() {},
|
||||
|
||||
// nsISupports implementation
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsISupports) ||
|
||||
iid.equals(Ci.nsIAutoCompletePopup))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
},
|
||||
|
||||
// nsISupports implementation
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsISupports) ||
|
||||
iid.equals(Ci.nsIAutoCompleteInput))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* nsIAutoCompleteResult implementation
|
||||
*/
|
||||
function AutoCompleteResult(aValues, aComments, aStyles) {
|
||||
this._values = aValues;
|
||||
this._comments = aComments;
|
||||
this._styles = aStyles;
|
||||
|
||||
if (this._values.length > 0) {
|
||||
this.searchResult = Ci.nsIAutoCompleteResult.RESULT_SUCCESS;
|
||||
} else {
|
||||
this.searchResult = Ci.nsIAutoCompleteResult.NOMATCH;
|
||||
}
|
||||
}
|
||||
AutoCompleteResult.prototype = {
|
||||
constructor: AutoCompleteResult,
|
||||
|
||||
// Arrays
|
||||
_values: null,
|
||||
_comments: null,
|
||||
_styles: null,
|
||||
|
||||
searchString: "",
|
||||
searchResult: null,
|
||||
|
||||
defaultIndex: 0,
|
||||
|
||||
get matchCount() {
|
||||
return this._values.length;
|
||||
},
|
||||
|
||||
getValueAt: function(aIndex) {
|
||||
return this._values[aIndex];
|
||||
},
|
||||
|
||||
getLabelAt: function(aIndex) {
|
||||
return this.getValueAt(aIndex);
|
||||
},
|
||||
|
||||
getCommentAt: function(aIndex) {
|
||||
return this._comments[aIndex];
|
||||
},
|
||||
|
||||
getStyleAt: function(aIndex) {
|
||||
return this._styles[aIndex];
|
||||
},
|
||||
|
||||
getImageAt: function(aIndex) {
|
||||
return "";
|
||||
},
|
||||
|
||||
getFinalCompleteValueAt: function(aIndex) {
|
||||
return this.getValueAt(aIndex);
|
||||
},
|
||||
|
||||
removeValueAt: function (aRowIndex, aRemoveFromDb) {},
|
||||
|
||||
// nsISupports implementation
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsISupports) ||
|
||||
iid.equals(Ci.nsIAutoCompleteResult))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* nsIAutoCompleteSearch implementation that always returns
|
||||
* the same result set.
|
||||
*/
|
||||
function AutoCompleteSearch(aName, aResult) {
|
||||
this.name = aName;
|
||||
this._result = aResult;
|
||||
}
|
||||
AutoCompleteSearch.prototype = {
|
||||
constructor: AutoCompleteSearch,
|
||||
|
||||
// Search name. Used by AutoCompleteController
|
||||
name: null,
|
||||
|
||||
// AutoCompleteResult
|
||||
_result:null,
|
||||
|
||||
|
||||
/**
|
||||
* Return the same result set for every search
|
||||
*/
|
||||
startSearch: function(aSearchString,
|
||||
aSearchParam,
|
||||
aPreviousResult,
|
||||
aListener)
|
||||
{
|
||||
aListener.onSearchResult(this, this._result);
|
||||
},
|
||||
|
||||
stopSearch: function() {},
|
||||
|
||||
// nsISupports implementation
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsISupports) ||
|
||||
iid.equals(Ci.nsIFactory) ||
|
||||
iid.equals(Ci.nsIAutoCompleteSearch))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
|
||||
// nsIFactory implementation
|
||||
createInstance: function(outer, iid) {
|
||||
return this.QueryInterface(iid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Helper to register an AutoCompleteSearch with the given name.
|
||||
* Allows the AutoCompleteController to find the search.
|
||||
*/
|
||||
function registerAutoCompleteSearch(aSearch) {
|
||||
var name = "@mozilla.org/autocomplete/search;1?name=" + aSearch.name;
|
||||
|
||||
var uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].
|
||||
getService(Ci.nsIUUIDGenerator);
|
||||
var cid = uuidGenerator.generateUUID();
|
||||
|
||||
var desc = "Test AutoCompleteSearch";
|
||||
|
||||
var componentManager = Components.manager
|
||||
.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
componentManager.registerFactory(cid, desc, name, aSearch);
|
||||
|
||||
// Keep the id on the object so we can unregister later
|
||||
aSearch.cid = cid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Helper to unregister an AutoCompleteSearch.
|
||||
*/
|
||||
function unregisterAutoCompleteSearch(aSearch) {
|
||||
var componentManager = Components.manager
|
||||
.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
componentManager.unregisterFactory(aSearch.cid, aSearch);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test AutoComplete with multiple AutoCompleteSearch sources.
|
||||
*/
|
||||
function run_test() {
|
||||
|
||||
// Make an AutoCompleteSearch that always returns nothing
|
||||
var emptySearch = new AutoCompleteSearch("test-empty-search",
|
||||
new AutoCompleteResult([], [], []));
|
||||
|
||||
// Make an AutoCompleteSearch that returns two values
|
||||
var expectedValues = ["test1", "test2"];
|
||||
var regularSearch = new AutoCompleteSearch("test-regular-search",
|
||||
new AutoCompleteResult(expectedValues, [], []));
|
||||
|
||||
// Register searches so AutoCompleteController can find them
|
||||
registerAutoCompleteSearch(emptySearch);
|
||||
registerAutoCompleteSearch(regularSearch);
|
||||
|
||||
var controller = Components.classes["@mozilla.org/autocomplete/controller;1"].
|
||||
getService(Components.interfaces.nsIAutoCompleteController);
|
||||
|
||||
// Make an AutoCompleteInput that uses our searches
|
||||
// and confirms results on search complete
|
||||
var input = new AutoCompleteInput([emptySearch.name, regularSearch.name]);
|
||||
var numSearchesStarted = 0;
|
||||
|
||||
input.onSearchBegin = function() {
|
||||
numSearchesStarted++;
|
||||
do_check_eq(numSearchesStarted, 1);
|
||||
};
|
||||
|
||||
input.onSearchComplete = function() {
|
||||
|
||||
do_check_eq(numSearchesStarted, 1);
|
||||
|
||||
do_check_eq(controller.searchStatus,
|
||||
Ci.nsIAutoCompleteController.STATUS_COMPLETE_MATCH);
|
||||
do_check_eq(controller.matchCount, 2);
|
||||
|
||||
// Confirm expected result values
|
||||
for (var i = 0; i < expectedValues.length; i++) {
|
||||
do_check_eq(expectedValues[i], controller.getValueAt(i));
|
||||
}
|
||||
|
||||
// Unregister searches
|
||||
unregisterAutoCompleteSearch(emptySearch);
|
||||
unregisterAutoCompleteSearch(regularSearch);
|
||||
|
||||
do_test_finished();
|
||||
};
|
||||
|
||||
controller.input = input;
|
||||
|
||||
// Search is asynchronous, so don't let the test finish immediately
|
||||
do_test_pending();
|
||||
|
||||
controller.startSearch("test");
|
||||
}
|
||||
|
|
@ -1,272 +0,0 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Unit test for Bug 393191 - AutoComplete crashes if result is null
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Dummy nsIAutoCompleteInput source that returns
|
||||
* the given list of AutoCompleteSearch names.
|
||||
*
|
||||
* Implements only the methods needed for this test.
|
||||
*/
|
||||
function AutoCompleteInput(aSearches) {
|
||||
this.searches = aSearches;
|
||||
}
|
||||
AutoCompleteInput.prototype = {
|
||||
constructor: AutoCompleteInput,
|
||||
|
||||
// Array of AutoCompleteSearch names
|
||||
searches: null,
|
||||
|
||||
minResultsForPopup: 0,
|
||||
timeout: 10,
|
||||
searchParam: "",
|
||||
textValue: "",
|
||||
disableAutoComplete: false,
|
||||
completeDefaultIndex: false,
|
||||
|
||||
get searchCount() {
|
||||
return this.searches.length;
|
||||
},
|
||||
|
||||
getSearchAt: function(aIndex) {
|
||||
return this.searches[aIndex];
|
||||
},
|
||||
|
||||
onSearchBegin: function() {},
|
||||
onSearchComplete: function() {},
|
||||
|
||||
popupOpen: false,
|
||||
|
||||
popup: {
|
||||
setSelectedIndex: function(aIndex) {},
|
||||
invalidate: function() {},
|
||||
|
||||
// nsISupports implementation
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsISupports) ||
|
||||
iid.equals(Ci.nsIAutoCompletePopup))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
},
|
||||
|
||||
// nsISupports implementation
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsISupports) ||
|
||||
iid.equals(Ci.nsIAutoCompleteInput))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* nsIAutoCompleteResult implementation
|
||||
*/
|
||||
function AutoCompleteResult(aValues, aComments, aStyles) {
|
||||
this._values = aValues;
|
||||
this._comments = aComments;
|
||||
this._styles = aStyles;
|
||||
|
||||
if (this._values.length > 0) {
|
||||
this.searchResult = Ci.nsIAutoCompleteResult.RESULT_SUCCESS;
|
||||
} else {
|
||||
this.searchResult = Ci.nsIAutoCompleteResult.NOMATCH;
|
||||
}
|
||||
}
|
||||
AutoCompleteResult.prototype = {
|
||||
constructor: AutoCompleteResult,
|
||||
|
||||
// Arrays
|
||||
_values: null,
|
||||
_comments: null,
|
||||
_styles: null,
|
||||
|
||||
searchString: "",
|
||||
searchResult: null,
|
||||
|
||||
defaultIndex: 0,
|
||||
|
||||
get matchCount() {
|
||||
return this._values.length;
|
||||
},
|
||||
|
||||
getValueAt: function(aIndex) {
|
||||
return this._values[aIndex];
|
||||
},
|
||||
|
||||
getLabelAt: function(aIndex) {
|
||||
return this.getValueAt(aIndex);
|
||||
},
|
||||
|
||||
getCommentAt: function(aIndex) {
|
||||
return this._comments[aIndex];
|
||||
},
|
||||
|
||||
getStyleAt: function(aIndex) {
|
||||
return this._styles[aIndex];
|
||||
},
|
||||
|
||||
getImageAt: function(aIndex) {
|
||||
return "";
|
||||
},
|
||||
|
||||
getFinalCompleteValueAt: function(aIndex) {
|
||||
return this.getValueAt(aIndex);
|
||||
},
|
||||
|
||||
removeValueAt: function (aRowIndex, aRemoveFromDb) {},
|
||||
|
||||
// nsISupports implementation
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsISupports) ||
|
||||
iid.equals(Ci.nsIAutoCompleteResult))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* nsIAutoCompleteSearch implementation that always returns
|
||||
* the same result set.
|
||||
*/
|
||||
function AutoCompleteSearch(aName, aResult) {
|
||||
this.name = aName;
|
||||
this._result = aResult;
|
||||
}
|
||||
AutoCompleteSearch.prototype = {
|
||||
constructor: AutoCompleteSearch,
|
||||
|
||||
// Search name. Used by AutoCompleteController
|
||||
name: null,
|
||||
|
||||
// AutoCompleteResult
|
||||
_result: null,
|
||||
|
||||
|
||||
/**
|
||||
* Return the same result set for every search
|
||||
*/
|
||||
startSearch: function(aSearchString,
|
||||
aSearchParam,
|
||||
aPreviousResult,
|
||||
aListener)
|
||||
{
|
||||
aListener.onSearchResult(this, this._result);
|
||||
},
|
||||
|
||||
stopSearch: function() {},
|
||||
|
||||
// nsISupports implementation
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsISupports) ||
|
||||
iid.equals(Ci.nsIFactory) ||
|
||||
iid.equals(Ci.nsIAutoCompleteSearch))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
|
||||
// nsIFactory implementation
|
||||
createInstance: function(outer, iid) {
|
||||
return this.QueryInterface(iid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Helper to register an AutoCompleteSearch with the given name.
|
||||
* Allows the AutoCompleteController to find the search.
|
||||
*/
|
||||
function registerAutoCompleteSearch(aSearch) {
|
||||
var name = "@mozilla.org/autocomplete/search;1?name=" + aSearch.name;
|
||||
|
||||
var uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].
|
||||
getService(Ci.nsIUUIDGenerator);
|
||||
var cid = uuidGenerator.generateUUID();
|
||||
|
||||
var desc = "Test AutoCompleteSearch";
|
||||
|
||||
var componentManager = Components.manager
|
||||
.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
componentManager.registerFactory(cid, desc, name, aSearch);
|
||||
|
||||
// Keep the id on the object so we can unregister later
|
||||
aSearch.cid = cid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Helper to unregister an AutoCompleteSearch.
|
||||
*/
|
||||
function unregisterAutoCompleteSearch(aSearch) {
|
||||
var componentManager = Components.manager
|
||||
.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
componentManager.unregisterFactory(aSearch.cid, aSearch);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test AutoComplete with a search that returns a null result
|
||||
*/
|
||||
function run_test() {
|
||||
|
||||
// Make an AutoCompleteSearch that always returns nothing
|
||||
var emptySearch = new AutoCompleteSearch("test-empty-search",
|
||||
new AutoCompleteResult([], [], []));
|
||||
|
||||
// Register search so AutoCompleteController can find them
|
||||
registerAutoCompleteSearch(emptySearch);
|
||||
|
||||
var controller = Components.classes["@mozilla.org/autocomplete/controller;1"].
|
||||
getService(Components.interfaces.nsIAutoCompleteController);
|
||||
|
||||
// Make an AutoCompleteInput that uses our search
|
||||
// and confirms results on search complete
|
||||
var input = new AutoCompleteInput([emptySearch.name]);
|
||||
var numSearchesStarted = 0;
|
||||
|
||||
input.onSearchBegin = function() {
|
||||
numSearchesStarted++;
|
||||
do_check_eq(numSearchesStarted, 1);
|
||||
};
|
||||
|
||||
input.onSearchComplete = function() {
|
||||
|
||||
do_check_eq(numSearchesStarted, 1);
|
||||
|
||||
do_check_eq(controller.searchStatus,
|
||||
Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH);
|
||||
do_check_eq(controller.matchCount, 0);
|
||||
|
||||
// Unregister searches
|
||||
unregisterAutoCompleteSearch(emptySearch);
|
||||
|
||||
do_test_finished();
|
||||
};
|
||||
|
||||
controller.input = input;
|
||||
|
||||
// Search is asynchronous, so don't let the test finish immediately
|
||||
do_test_pending();
|
||||
|
||||
controller.startSearch("test");
|
||||
}
|
||||
|
|
@ -1,285 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Unit test for Bug 440866 - First AutoCompleteSearch that returns
|
||||
* RESULT_NOMATCH cancels all other searches when popup is open
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Dummy nsIAutoCompleteInput source that returns
|
||||
* the given list of AutoCompleteSearch names.
|
||||
*
|
||||
* Implements only the methods needed for this test.
|
||||
*/
|
||||
function AutoCompleteInput(aSearches) {
|
||||
this.searches = aSearches;
|
||||
}
|
||||
AutoCompleteInput.prototype = {
|
||||
constructor: AutoCompleteInput,
|
||||
|
||||
// Array of AutoCompleteSearch names
|
||||
searches: null,
|
||||
|
||||
minResultsForPopup: 0,
|
||||
timeout: 10,
|
||||
searchParam: "",
|
||||
textValue: "",
|
||||
disableAutoComplete: false,
|
||||
completeDefaultIndex: false,
|
||||
|
||||
get searchCount() {
|
||||
return this.searches.length;
|
||||
},
|
||||
|
||||
getSearchAt: function(aIndex) {
|
||||
return this.searches[aIndex];
|
||||
},
|
||||
|
||||
onSearchBegin: function() {},
|
||||
onSearchComplete: function() {},
|
||||
|
||||
popupOpen: false,
|
||||
|
||||
popup: {
|
||||
setSelectedIndex: function(aIndex) {},
|
||||
invalidate: function() {},
|
||||
|
||||
// nsISupports implementation
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsISupports) ||
|
||||
iid.equals(Ci.nsIAutoCompletePopup))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
},
|
||||
|
||||
// nsISupports implementation
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsISupports) ||
|
||||
iid.equals(Ci.nsIAutoCompleteInput))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* nsIAutoCompleteResult implementation
|
||||
*/
|
||||
function AutoCompleteResult(aValues, aComments, aStyles) {
|
||||
this._values = aValues;
|
||||
this._comments = aComments;
|
||||
this._styles = aStyles;
|
||||
|
||||
if (this._values.length > 0) {
|
||||
this.searchResult = Ci.nsIAutoCompleteResult.RESULT_SUCCESS;
|
||||
} else {
|
||||
this.searchResult = Ci.nsIAutoCompleteResult.NOMATCH;
|
||||
}
|
||||
}
|
||||
AutoCompleteResult.prototype = {
|
||||
constructor: AutoCompleteResult,
|
||||
|
||||
// Arrays
|
||||
_values: null,
|
||||
_comments: null,
|
||||
_styles: null,
|
||||
|
||||
searchString: "",
|
||||
searchResult: null,
|
||||
|
||||
defaultIndex: 0,
|
||||
|
||||
get matchCount() {
|
||||
return this._values.length;
|
||||
},
|
||||
|
||||
getValueAt: function(aIndex) {
|
||||
return this._values[aIndex];
|
||||
},
|
||||
|
||||
getLabelAt: function(aIndex) {
|
||||
return this.getValueAt(aIndex);
|
||||
},
|
||||
|
||||
getCommentAt: function(aIndex) {
|
||||
return this._comments[aIndex];
|
||||
},
|
||||
|
||||
getStyleAt: function(aIndex) {
|
||||
return this._styles[aIndex];
|
||||
},
|
||||
|
||||
getImageAt: function(aIndex) {
|
||||
return "";
|
||||
},
|
||||
|
||||
getFinalCompleteValueAt: function(aIndex) {
|
||||
return this.getValueAt(aIndex);
|
||||
},
|
||||
|
||||
removeValueAt: function (aRowIndex, aRemoveFromDb) {},
|
||||
|
||||
// nsISupports implementation
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsISupports) ||
|
||||
iid.equals(Ci.nsIAutoCompleteResult))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* nsIAutoCompleteSearch implementation that always returns
|
||||
* the same result set.
|
||||
*/
|
||||
function AutoCompleteSearch(aName, aResult) {
|
||||
this.name = aName;
|
||||
this._result = aResult;
|
||||
}
|
||||
AutoCompleteSearch.prototype = {
|
||||
constructor: AutoCompleteSearch,
|
||||
|
||||
// Search name. Used by AutoCompleteController
|
||||
name: null,
|
||||
|
||||
// AutoCompleteResult
|
||||
_result:null,
|
||||
|
||||
|
||||
/**
|
||||
* Return the same result set for every search
|
||||
*/
|
||||
startSearch: function(aSearchString,
|
||||
aSearchParam,
|
||||
aPreviousResult,
|
||||
aListener)
|
||||
{
|
||||
aListener.onSearchResult(this, this._result);
|
||||
},
|
||||
|
||||
stopSearch: function() {},
|
||||
|
||||
// nsISupports implementation
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsISupports) ||
|
||||
iid.equals(Ci.nsIFactory) ||
|
||||
iid.equals(Ci.nsIAutoCompleteSearch))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
|
||||
// nsIFactory implementation
|
||||
createInstance: function(outer, iid) {
|
||||
return this.QueryInterface(iid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Helper to register an AutoCompleteSearch with the given name.
|
||||
* Allows the AutoCompleteController to find the search.
|
||||
*/
|
||||
function registerAutoCompleteSearch(aSearch) {
|
||||
var name = "@mozilla.org/autocomplete/search;1?name=" + aSearch.name;
|
||||
|
||||
var uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].
|
||||
getService(Ci.nsIUUIDGenerator);
|
||||
var cid = uuidGenerator.generateUUID();
|
||||
|
||||
var desc = "Test AutoCompleteSearch";
|
||||
|
||||
var componentManager = Components.manager
|
||||
.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
componentManager.registerFactory(cid, desc, name, aSearch);
|
||||
|
||||
// Keep the id on the object so we can unregister later
|
||||
aSearch.cid = cid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Helper to unregister an AutoCompleteSearch.
|
||||
*/
|
||||
function unregisterAutoCompleteSearch(aSearch) {
|
||||
var componentManager = Components.manager
|
||||
.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
componentManager.unregisterFactory(aSearch.cid, aSearch);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test AutoComplete with multiple AutoCompleteSearch sources.
|
||||
*/
|
||||
function run_test() {
|
||||
|
||||
// Make an AutoCompleteSearch that always returns nothing
|
||||
var emptySearch = new AutoCompleteSearch("test-empty-search",
|
||||
new AutoCompleteResult([], [], []));
|
||||
|
||||
// Make an AutoCompleteSearch that returns two values
|
||||
var expectedValues = ["test1", "test2"];
|
||||
var regularSearch = new AutoCompleteSearch("test-regular-search",
|
||||
new AutoCompleteResult(expectedValues, [], []));
|
||||
|
||||
// Register searches so AutoCompleteController can find them
|
||||
registerAutoCompleteSearch(emptySearch);
|
||||
registerAutoCompleteSearch(regularSearch);
|
||||
|
||||
var controller = Components.classes["@mozilla.org/autocomplete/controller;1"].
|
||||
getService(Components.interfaces.nsIAutoCompleteController);
|
||||
|
||||
// Make an AutoCompleteInput that uses our searches
|
||||
// and confirms results on search complete
|
||||
var input = new AutoCompleteInput([emptySearch.name, regularSearch.name]);
|
||||
var numSearchesStarted = 0;
|
||||
|
||||
input.onSearchBegin = function() {
|
||||
numSearchesStarted++;
|
||||
do_check_eq(numSearchesStarted, 1);
|
||||
do_check_eq(input.searchCount, 2);
|
||||
};
|
||||
|
||||
input.onSearchComplete = function() {
|
||||
do_check_eq(numSearchesStarted, 1);
|
||||
|
||||
do_check_eq(controller.searchStatus,
|
||||
Ci.nsIAutoCompleteController.STATUS_COMPLETE_MATCH);
|
||||
do_check_eq(controller.matchCount, 2);
|
||||
|
||||
// Confirm expected result values
|
||||
for (var i = 0; i < expectedValues.length; i++) {
|
||||
do_check_eq(expectedValues[i], controller.getValueAt(i));
|
||||
}
|
||||
|
||||
do_check_true(input.popupOpen);
|
||||
|
||||
// Unregister searches
|
||||
unregisterAutoCompleteSearch(emptySearch);
|
||||
unregisterAutoCompleteSearch(regularSearch);
|
||||
|
||||
do_test_finished();
|
||||
};
|
||||
|
||||
controller.input = input;
|
||||
|
||||
// Search is asynchronous, so don't let the test finish immediately
|
||||
do_test_pending();
|
||||
|
||||
controller.startSearch("test");
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// main
|
||||
function run_test() {
|
||||
var result = Cc["@mozilla.org/autocomplete/controller;1"].
|
||||
createInstance(Ci.nsIAutoCompleteController);
|
||||
do_check_eq(result.searchStatus, Ci.nsIAutoCompleteController.STATUS_NONE);
|
||||
}
|
|
@ -1,101 +0,0 @@
|
|||
/**
|
||||
* Search object that returns results at different times.
|
||||
* First, the search that returns results asynchronously.
|
||||
*/
|
||||
function AutoCompleteAsyncSearch(aName, aResult) {
|
||||
this.name = aName;
|
||||
this._result = aResult;
|
||||
}
|
||||
AutoCompleteAsyncSearch.prototype = Object.create(AutoCompleteSearchBase.prototype);
|
||||
AutoCompleteAsyncSearch.prototype.startSearch = function(aSearchString,
|
||||
aSearchParam,
|
||||
aPreviousResult,
|
||||
aListener) {
|
||||
this._result.searchResult = Ci.nsIAutoCompleteResult.RESULT_NOMATCH_ONGOING;
|
||||
aListener.onSearchResult(this, this._result);
|
||||
|
||||
do_timeout(500, () => {
|
||||
this._returnResults(aListener);
|
||||
});
|
||||
};
|
||||
|
||||
AutoCompleteAsyncSearch.prototype._returnResults = function(aListener) {
|
||||
var result = this._result;
|
||||
|
||||
result.searchResult = Ci.nsIAutoCompleteResult.RESULT_SUCCESS;
|
||||
aListener.onSearchResult(this, result);
|
||||
};
|
||||
|
||||
/**
|
||||
* The synchronous version
|
||||
*/
|
||||
function AutoCompleteSyncSearch(aName, aResult) {
|
||||
this.name = aName;
|
||||
this._result = aResult;
|
||||
}
|
||||
AutoCompleteSyncSearch.prototype = Object.create(AutoCompleteAsyncSearch.prototype);
|
||||
AutoCompleteSyncSearch.prototype.startSearch = function(aSearchString,
|
||||
aSearchParam,
|
||||
aPreviousResult,
|
||||
aListener) {
|
||||
this._returnResults(aListener);
|
||||
};
|
||||
|
||||
/**
|
||||
* Results object
|
||||
*/
|
||||
function AutoCompleteResult(aValues, aDefaultIndex) {
|
||||
this._values = aValues;
|
||||
this.defaultIndex = aDefaultIndex;
|
||||
}
|
||||
AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype);
|
||||
|
||||
|
||||
/**
|
||||
* Test AutoComplete with multiple AutoCompleteSearch sources, with one of them
|
||||
* (index != 0) returning before the rest.
|
||||
*/
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
|
||||
var results = ["mozillaTest"];
|
||||
var inputStr = "moz";
|
||||
|
||||
// Async search
|
||||
var asyncSearch = new AutoCompleteAsyncSearch("Async",
|
||||
new AutoCompleteResult(results, -1));
|
||||
// Sync search
|
||||
var syncSearch = new AutoCompleteSyncSearch("Sync",
|
||||
new AutoCompleteResult(results, 0));
|
||||
|
||||
// Register searches so AutoCompleteController can find them
|
||||
registerAutoCompleteSearch(asyncSearch);
|
||||
registerAutoCompleteSearch(syncSearch);
|
||||
|
||||
var controller = Cc["@mozilla.org/autocomplete/controller;1"].
|
||||
getService(Ci.nsIAutoCompleteController);
|
||||
|
||||
// Make an AutoCompleteInput that uses our searches
|
||||
// and confirms results on search complete.
|
||||
// Async search MUST be FIRST to trigger the bug this tests.
|
||||
var input = new AutoCompleteInputBase([asyncSearch.name, syncSearch.name]);
|
||||
input.completeDefaultIndex = true;
|
||||
input.textValue = inputStr;
|
||||
|
||||
// Caret must be at the end. Autofill doesn't happen unless you're typing
|
||||
// characters at the end.
|
||||
var strLen = inputStr.length;
|
||||
input.selectTextRange(strLen, strLen);
|
||||
|
||||
controller.input = input;
|
||||
controller.startSearch(inputStr);
|
||||
|
||||
input.onSearchComplete = function() {
|
||||
do_check_eq(input.textValue, results[0]);
|
||||
|
||||
// Unregister searches
|
||||
unregisterAutoCompleteSearch(asyncSearch);
|
||||
unregisterAutoCompleteSearch(syncSearch);
|
||||
do_test_finished();
|
||||
};
|
||||
}
|
|
@ -1,276 +0,0 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Dummy nsIAutoCompleteInput source that returns
|
||||
* the given list of AutoCompleteSearch names.
|
||||
*
|
||||
* Implements only the methods needed for this test.
|
||||
*/
|
||||
function AutoCompleteInput(aSearches) {
|
||||
this.searches = aSearches;
|
||||
}
|
||||
AutoCompleteInput.prototype = {
|
||||
constructor: AutoCompleteInput,
|
||||
|
||||
// Array of AutoCompleteSearch names
|
||||
searches: null,
|
||||
|
||||
minResultsForPopup: 0,
|
||||
timeout: 10,
|
||||
searchParam: "",
|
||||
textValue: "",
|
||||
disableAutoComplete: false,
|
||||
completeDefaultIndex: false,
|
||||
|
||||
get searchCount() {
|
||||
return this.searches.length;
|
||||
},
|
||||
|
||||
getSearchAt: function(aIndex) {
|
||||
return this.searches[aIndex];
|
||||
},
|
||||
|
||||
onSearchBegin: function() {},
|
||||
onSearchComplete: function() {},
|
||||
|
||||
popupOpen: false,
|
||||
|
||||
popup: {
|
||||
setSelectedIndex: function(aIndex) {},
|
||||
invalidate: function() {},
|
||||
|
||||
// nsISupports implementation
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsISupports) ||
|
||||
iid.equals(Ci.nsIAutoCompletePopup))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
},
|
||||
|
||||
// nsISupports implementation
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsISupports) ||
|
||||
iid.equals(Ci.nsIAutoCompleteInput))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* nsIAutoCompleteResult implementation
|
||||
*/
|
||||
function AutoCompleteResult(aValues, aComments, aStyles) {
|
||||
this._values = aValues;
|
||||
this._comments = aComments;
|
||||
this._styles = aStyles;
|
||||
}
|
||||
AutoCompleteResult.prototype = {
|
||||
constructor: AutoCompleteResult,
|
||||
|
||||
// Arrays
|
||||
_values: null,
|
||||
_comments: null,
|
||||
_styles: null,
|
||||
|
||||
searchString: "",
|
||||
searchResult: null,
|
||||
|
||||
defaultIndex: 0,
|
||||
|
||||
get matchCount() {
|
||||
return this._values.length;
|
||||
},
|
||||
|
||||
getValueAt: function(aIndex) {
|
||||
return this._values[aIndex];
|
||||
},
|
||||
|
||||
getLabelAt: function(aIndex) {
|
||||
return this.getValueAt(aIndex);
|
||||
},
|
||||
|
||||
getCommentAt: function(aIndex) {
|
||||
return this._comments[aIndex];
|
||||
},
|
||||
|
||||
getStyleAt: function(aIndex) {
|
||||
return this._styles[aIndex];
|
||||
},
|
||||
|
||||
getImageAt: function(aIndex) {
|
||||
return "";
|
||||
},
|
||||
|
||||
getFinalCompleteValueAt: function(aIndex) {
|
||||
return this.getValueAt(aIndex);
|
||||
},
|
||||
|
||||
removeValueAt: function (aRowIndex, aRemoveFromDb) {},
|
||||
|
||||
// nsISupports implementation
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsISupports) ||
|
||||
iid.equals(Ci.nsIAutoCompleteResult))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* nsIAutoCompleteSearch implementation that always returns
|
||||
* the same result set.
|
||||
*/
|
||||
function AutoCompleteSearch(aName, aResult) {
|
||||
this.name = aName;
|
||||
this._result = aResult;
|
||||
}
|
||||
AutoCompleteSearch.prototype = {
|
||||
constructor: AutoCompleteSearch,
|
||||
|
||||
// Search name. Used by AutoCompleteController
|
||||
name: null,
|
||||
|
||||
// AutoCompleteResult
|
||||
_result:null,
|
||||
|
||||
|
||||
/**
|
||||
* Return the same result set for every search
|
||||
*/
|
||||
startSearch: function(aSearchString,
|
||||
aSearchParam,
|
||||
aPreviousResult,
|
||||
aListener)
|
||||
{
|
||||
var result = this._result;
|
||||
if (result._values.length > 0) {
|
||||
result.searchResult = Ci.nsIAutoCompleteResult.RESULT_SUCCESS_ONGOING;
|
||||
} else {
|
||||
result.searchResult = Ci.nsIAutoCompleteResult.RESULT_NOMATCH_ONGOING;
|
||||
}
|
||||
aListener.onSearchResult(this, result);
|
||||
|
||||
if (result._values.length > 0) {
|
||||
result.searchResult = Ci.nsIAutoCompleteResult.RESULT_SUCCESS;
|
||||
} else {
|
||||
result.searchResult = Ci.nsIAutoCompleteResult.RESULT_NOMATCH;
|
||||
}
|
||||
aListener.onSearchResult(this, result);
|
||||
},
|
||||
|
||||
stopSearch: function() {},
|
||||
|
||||
// nsISupports implementation
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsISupports) ||
|
||||
iid.equals(Ci.nsIFactory) ||
|
||||
iid.equals(Ci.nsIAutoCompleteSearch))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
|
||||
// nsIFactory implementation
|
||||
createInstance: function(outer, iid) {
|
||||
return this.QueryInterface(iid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Helper to register an AutoCompleteSearch with the given name.
|
||||
* Allows the AutoCompleteController to find the search.
|
||||
*/
|
||||
function registerAutoCompleteSearch(aSearch) {
|
||||
var name = "@mozilla.org/autocomplete/search;1?name=" + aSearch.name;
|
||||
|
||||
var uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].
|
||||
getService(Ci.nsIUUIDGenerator);
|
||||
var cid = uuidGenerator.generateUUID();
|
||||
|
||||
var desc = "Test AutoCompleteSearch";
|
||||
|
||||
var componentManager = Components.manager
|
||||
.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
componentManager.registerFactory(cid, desc, name, aSearch);
|
||||
|
||||
// Keep the id on the object so we can unregister later
|
||||
aSearch.cid = cid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Helper to unregister an AutoCompleteSearch.
|
||||
*/
|
||||
function unregisterAutoCompleteSearch(aSearch) {
|
||||
var componentManager = Components.manager
|
||||
.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
componentManager.unregisterFactory(aSearch.cid, aSearch);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test AutoComplete with multiple AutoCompleteSearch sources.
|
||||
*/
|
||||
function run_test() {
|
||||
var expected1 = ["1", "2", "3"];
|
||||
var expected2 = ["a", "b", "c"];
|
||||
var search1 = new AutoCompleteSearch("search1",
|
||||
new AutoCompleteResult(expected1, [], []));
|
||||
var search2 = new AutoCompleteSearch("search2",
|
||||
new AutoCompleteResult(expected2, [], []));
|
||||
|
||||
// Register searches so AutoCompleteController can find them
|
||||
registerAutoCompleteSearch(search1);
|
||||
registerAutoCompleteSearch(search2);
|
||||
|
||||
var controller = Components.classes["@mozilla.org/autocomplete/controller;1"].
|
||||
getService(Components.interfaces.nsIAutoCompleteController);
|
||||
|
||||
// Make an AutoCompleteInput that uses our searches
|
||||
// and confirms results on search complete
|
||||
var input = new AutoCompleteInput([search1.name, search2.name]);
|
||||
var numSearchesStarted = 0;
|
||||
|
||||
input.onSearchBegin = function() {
|
||||
numSearchesStarted++;
|
||||
do_check_eq(numSearchesStarted, 1);
|
||||
};
|
||||
|
||||
input.onSearchComplete = function() {
|
||||
|
||||
do_check_eq(numSearchesStarted, 1);
|
||||
|
||||
do_check_eq(controller.searchStatus,
|
||||
Ci.nsIAutoCompleteController.STATUS_COMPLETE_MATCH);
|
||||
do_check_eq(controller.matchCount, expected1.length + expected2.length);
|
||||
|
||||
// Unregister searches
|
||||
unregisterAutoCompleteSearch(search1);
|
||||
unregisterAutoCompleteSearch(search2);
|
||||
|
||||
do_test_finished();
|
||||
};
|
||||
|
||||
controller.input = input;
|
||||
|
||||
// Search is asynchronous, so don't let the test finish immediately
|
||||
do_test_pending();
|
||||
|
||||
controller.startSearch("test");
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
|
||||
function AutoCompleteInput(aSearches, aUserContextId) {
|
||||
this.searches = aSearches;
|
||||
this.userContextId = aUserContextId;
|
||||
this.popup.selectedIndex = -1;
|
||||
}
|
||||
AutoCompleteInput.prototype = Object.create(AutoCompleteInputBase.prototype);
|
||||
|
||||
function AutoCompleteSearch(aName) {
|
||||
this.name = aName;
|
||||
}
|
||||
AutoCompleteSearch.prototype = Object.create(AutoCompleteSearchBase.prototype);
|
||||
|
||||
add_task(function *test_userContextId() {
|
||||
let searchParam = yield doSearch("test", 1);
|
||||
Assert.equal(searchParam, " user-context-id:1");
|
||||
});
|
||||
|
||||
function doSearch(aString, aUserContextId) {
|
||||
let deferred = Promise.defer();
|
||||
let search = new AutoCompleteSearch("test");
|
||||
|
||||
search.startSearch = function (aSearchString,
|
||||
aSearchParam,
|
||||
aPreviousResult,
|
||||
aListener) {
|
||||
unregisterAutoCompleteSearch(search);
|
||||
deferred.resolve(aSearchParam);
|
||||
};
|
||||
|
||||
registerAutoCompleteSearch(search);
|
||||
|
||||
let controller = Cc["@mozilla.org/autocomplete/controller;1"].
|
||||
getService(Ci.nsIAutoCompleteController);
|
||||
|
||||
let input = new AutoCompleteInput([ search.name ], aUserContextId);
|
||||
controller.input = input;
|
||||
controller.startSearch(aString);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
add_task(function* sameCaseAsMatch() {
|
||||
yield runTest("moz");
|
||||
});
|
||||
|
||||
add_task(function* differentCaseFromMatch() {
|
||||
yield runTest("MOZ");
|
||||
});
|
||||
|
||||
function* runTest(searchStr) {
|
||||
let matches = [
|
||||
"mozilla.org",
|
||||
"example.com",
|
||||
];
|
||||
let result = new AutoCompleteResultBase(matches);
|
||||
result.defaultIndex = 0;
|
||||
|
||||
let search = new AutoCompleteSearchBase("search", result);
|
||||
registerAutoCompleteSearch(search);
|
||||
|
||||
let input = new AutoCompleteInputBase([search.name]);
|
||||
input.completeSelectedIndex = true;
|
||||
input.completeDefaultIndex = true;
|
||||
|
||||
// Start off with the search string in the input. The selection must be
|
||||
// collapsed and the caret must be at the end to trigger autofill below.
|
||||
input.textValue = searchStr;
|
||||
input.selectTextRange(searchStr.length, searchStr.length);
|
||||
Assert.equal(input.selectionStart, searchStr.length,
|
||||
"Selection should start at the end of the input");
|
||||
Assert.equal(input.selectionEnd, searchStr.length,
|
||||
"Selection should end at the end of the input");
|
||||
|
||||
let controller = Cc["@mozilla.org/autocomplete/controller;1"].
|
||||
createInstance(Ci.nsIAutoCompleteController);
|
||||
controller.input = input;
|
||||
input.controller = controller;
|
||||
|
||||
// Start a search.
|
||||
yield new Promise(resolve => {
|
||||
controller.startSearch(searchStr);
|
||||
input.onSearchComplete = () => {
|
||||
// The first match should have autofilled, but the case of the search
|
||||
// string should be preserved.
|
||||
let expectedValue = searchStr + matches[0].substr(searchStr.length);
|
||||
Assert.equal(input.textValue, expectedValue,
|
||||
"Should have autofilled");
|
||||
Assert.equal(input.selectionStart, searchStr.length,
|
||||
"Selection should start after search string");
|
||||
Assert.equal(input.selectionEnd, expectedValue.length,
|
||||
"Selection should end at the end of the input");
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
|
||||
// Key down to select the second match in the popup.
|
||||
controller.handleKeyNavigation(Ci.nsIDOMKeyEvent.DOM_VK_DOWN);
|
||||
let expectedValue = matches[1];
|
||||
Assert.equal(input.textValue, expectedValue,
|
||||
"Should have filled second match");
|
||||
Assert.equal(input.selectionStart, expectedValue.length,
|
||||
"Selection should start at the end of the input");
|
||||
Assert.equal(input.selectionEnd, expectedValue.length,
|
||||
"Selection should end at the end of the input");
|
||||
|
||||
// Key up to select the first match again. The input should be restored
|
||||
// exactly as it was when the first match was autofilled above: the search
|
||||
// string's case should be preserved, and the selection should be preserved.
|
||||
controller.handleKeyNavigation(Ci.nsIDOMKeyEvent.DOM_VK_UP);
|
||||
expectedValue = searchStr + matches[0].substr(searchStr.length);
|
||||
Assert.equal(input.textValue, expectedValue,
|
||||
"Should have filled first match again");
|
||||
Assert.equal(input.selectionStart, searchStr.length,
|
||||
"Selection should start after search string again");
|
||||
Assert.equal(input.selectionEnd, expectedValue.length,
|
||||
"Selection should end at the end of the input again");
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* A results that wants to defaultComplete to 0, but it has no matches,
|
||||
* though it notifies SUCCESS to the controller.
|
||||
*/
|
||||
function AutoCompleteNoMatchResult() {
|
||||
this.defaultIndex = 0;
|
||||
}
|
||||
AutoCompleteNoMatchResult.prototype = Object.create(AutoCompleteResultBase.prototype);
|
||||
|
||||
/**
|
||||
* A results that wants to defaultComplete to an index greater than the number
|
||||
* of matches.
|
||||
*/
|
||||
function AutoCompleteBadIndexResult(aValues, aDefaultIndex) {
|
||||
do_check_true(aValues.length <= aDefaultIndex);
|
||||
this._values = aValues;
|
||||
this.defaultIndex = aDefaultIndex;
|
||||
}
|
||||
AutoCompleteBadIndexResult.prototype = Object.create(AutoCompleteResultBase.prototype);
|
||||
|
||||
add_test(function autocomplete_noMatch_success() {
|
||||
const INPUT_STR = "moz";
|
||||
|
||||
let searchNoMatch =
|
||||
new AutoCompleteSearchBase("searchNoMatch",
|
||||
new AutoCompleteNoMatchResult());
|
||||
registerAutoCompleteSearch(searchNoMatch);
|
||||
|
||||
// Make an AutoCompleteInput that uses our search and confirms results.
|
||||
let input = new AutoCompleteInputBase([searchNoMatch.name]);
|
||||
input.completeDefaultIndex = true;
|
||||
input.textValue = INPUT_STR;
|
||||
|
||||
// Caret must be at the end for autoFill to happen.
|
||||
let strLen = INPUT_STR.length;
|
||||
input.selectTextRange(strLen, strLen);
|
||||
do_check_eq(input.selectionStart, strLen);
|
||||
do_check_eq(input.selectionEnd, strLen);
|
||||
|
||||
let controller = Cc["@mozilla.org/autocomplete/controller;1"].
|
||||
getService(Ci.nsIAutoCompleteController);
|
||||
controller.input = input;
|
||||
controller.startSearch(INPUT_STR);
|
||||
|
||||
input.onSearchComplete = function () {
|
||||
// Should not try to autoFill to an empty value.
|
||||
do_check_eq(input.textValue, "moz");
|
||||
|
||||
// Clean up.
|
||||
unregisterAutoCompleteSearch(searchNoMatch);
|
||||
run_next_test();
|
||||
};
|
||||
});
|
||||
|
||||
add_test(function autocomplete_defaultIndex_exceeds_matchCount() {
|
||||
const INPUT_STR = "moz";
|
||||
|
||||
// Result returning matches, but a bad defaultIndex.
|
||||
let searchBadIndex =
|
||||
new AutoCompleteSearchBase("searchBadIndex",
|
||||
new AutoCompleteBadIndexResult(["mozillaTest"], 1));
|
||||
registerAutoCompleteSearch(searchBadIndex);
|
||||
|
||||
// Make an AutoCompleteInput that uses our search and confirms results.
|
||||
let input = new AutoCompleteInputBase([searchBadIndex.name]);
|
||||
input.completeDefaultIndex = true;
|
||||
input.textValue = INPUT_STR;
|
||||
|
||||
// Caret must be at the end for autoFill to happen.
|
||||
let strLen = INPUT_STR.length;
|
||||
input.selectTextRange(strLen, strLen);
|
||||
do_check_eq(input.selectionStart, strLen);
|
||||
do_check_eq(input.selectionEnd, strLen);
|
||||
|
||||
let controller = Cc["@mozilla.org/autocomplete/controller;1"].
|
||||
getService(Ci.nsIAutoCompleteController);
|
||||
controller.input = input;
|
||||
controller.startSearch(INPUT_STR);
|
||||
|
||||
input.onSearchComplete = function () {
|
||||
// Should not try to autoFill to an empty value.
|
||||
do_check_eq(input.textValue, "moz");
|
||||
|
||||
// Clean up.
|
||||
unregisterAutoCompleteSearch(searchBadIndex);
|
||||
run_next_test();
|
||||
};
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function AutoCompleteResult(aValues) {
|
||||
this._values = aValues;
|
||||
this.defaultIndex = 0;
|
||||
}
|
||||
AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype);
|
||||
|
||||
function AutoCompleteInput(aSearches) {
|
||||
this.searches = aSearches;
|
||||
this.popup.selectedIndex = -1;
|
||||
this.completeDefaultIndex = true;
|
||||
}
|
||||
AutoCompleteInput.prototype = Object.create(AutoCompleteInputBase.prototype);
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_test(function test_keyNavigation() {
|
||||
doSearch("MOZ", "mozilla", function(aController) {
|
||||
do_check_eq(aController.input.textValue, "MOZilla");
|
||||
aController.handleKeyNavigation(Ci.nsIDOMKeyEvent.DOM_VK_RIGHT);
|
||||
do_check_eq(aController.input.textValue, "mozilla");
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_handleEnter() {
|
||||
doSearch("MOZ", "mozilla", function(aController) {
|
||||
do_check_eq(aController.input.textValue, "MOZilla");
|
||||
aController.handleEnter(false);
|
||||
do_check_eq(aController.input.textValue, "mozilla");
|
||||
});
|
||||
});
|
||||
|
||||
function doSearch(aSearchString, aResultValue, aOnCompleteCallback) {
|
||||
let search = new AutoCompleteSearchBase("search",
|
||||
new AutoCompleteResult([ "mozilla", "toolkit" ], 0));
|
||||
registerAutoCompleteSearch(search);
|
||||
|
||||
let controller = Cc["@mozilla.org/autocomplete/controller;1"].
|
||||
getService(Ci.nsIAutoCompleteController);
|
||||
|
||||
// Make an AutoCompleteInput that uses our searches and confirms results.
|
||||
let input = new AutoCompleteInput([ search.name ]);
|
||||
input.textValue = aSearchString;
|
||||
|
||||
// Caret must be at the end for autofill to happen.
|
||||
let strLen = aSearchString.length;
|
||||
input.selectTextRange(strLen, strLen);
|
||||
controller.input = input;
|
||||
controller.startSearch(aSearchString);
|
||||
|
||||
input.onSearchComplete = function onSearchComplete() {
|
||||
aOnCompleteCallback(controller);
|
||||
|
||||
// Clean up.
|
||||
unregisterAutoCompleteSearch(search);
|
||||
run_next_test();
|
||||
};
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
function AutoCompleteResult(aValues, aFinalCompleteValues) {
|
||||
this._values = aValues;
|
||||
this._finalCompleteValues = aFinalCompleteValues;
|
||||
}
|
||||
AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype);
|
||||
|
||||
function AutoCompleteInput(aSearches) {
|
||||
this.searches = aSearches;
|
||||
this.popup.selectedIndex = 0;
|
||||
}
|
||||
AutoCompleteInput.prototype = Object.create(AutoCompleteInputBase.prototype);
|
||||
|
||||
add_test(function test_handleEnter_mouse() {
|
||||
doSearch("moz", "mozilla.com", "http://www.mozilla.com", function(aController) {
|
||||
do_check_eq(aController.input.textValue, "moz");
|
||||
do_check_eq(aController.getFinalCompleteValueAt(0), "http://www.mozilla.com");
|
||||
// Keyboard interaction is tested by test_finalCompleteValueSelectedIndex.js
|
||||
// so here just test popup selection.
|
||||
aController.handleEnter(true);
|
||||
do_check_eq(aController.input.textValue, "http://www.mozilla.com");
|
||||
});
|
||||
});
|
||||
|
||||
function doSearch(aSearchString, aResultValue, aFinalCompleteValue, aOnCompleteCallback) {
|
||||
let search = new AutoCompleteSearchBase(
|
||||
"search",
|
||||
new AutoCompleteResult([ aResultValue ], [ aFinalCompleteValue ])
|
||||
);
|
||||
registerAutoCompleteSearch(search);
|
||||
|
||||
let controller = Cc["@mozilla.org/autocomplete/controller;1"].
|
||||
getService(Ci.nsIAutoCompleteController);
|
||||
|
||||
// Make an AutoCompleteInput that uses our searches and confirms results.
|
||||
let input = new AutoCompleteInput([ search.name ]);
|
||||
input.textValue = aSearchString;
|
||||
|
||||
controller.input = input;
|
||||
controller.startSearch(aSearchString);
|
||||
|
||||
input.onSearchComplete = function onSearchComplete() {
|
||||
aOnCompleteCallback(controller);
|
||||
|
||||
// Clean up.
|
||||
unregisterAutoCompleteSearch(search);
|
||||
run_next_test();
|
||||
};
|
||||
}
|
|
@ -1,119 +0,0 @@
|
|||
function AutoCompleteResult(aResultValues) {
|
||||
this._values = aResultValues.map(x => x[0]);
|
||||
this._finalCompleteValues = aResultValues.map(x => x[1]);
|
||||
}
|
||||
AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype);
|
||||
|
||||
var selectByWasCalled = false;
|
||||
function AutoCompleteInput(aSearches) {
|
||||
this.searches = aSearches;
|
||||
this.popup.selectedIndex = 0;
|
||||
this.popup.selectBy = function(reverse, page) {
|
||||
Assert.equal(selectByWasCalled, false);
|
||||
selectByWasCalled = true;
|
||||
Assert.equal(reverse, false);
|
||||
Assert.equal(page, false);
|
||||
this.selectedIndex += (reverse ? -1 : 1) * (page ? 100 : 1);
|
||||
};
|
||||
this.completeSelectedIndex = true;
|
||||
}
|
||||
AutoCompleteInput.prototype = Object.create(AutoCompleteInputBase.prototype);
|
||||
|
||||
add_test(function test_handleEnter_key() {
|
||||
let results = [
|
||||
["mozilla.com", "http://www.mozilla.com"],
|
||||
["mozilla.org", "http://www.mozilla.org"],
|
||||
];
|
||||
// First check the case where we do select a value with the keyboard:
|
||||
doSearch("moz", results, function(aController) {
|
||||
Assert.equal(aController.input.textValue, "moz");
|
||||
Assert.equal(aController.getFinalCompleteValueAt(0), "http://www.mozilla.com");
|
||||
Assert.equal(aController.getFinalCompleteValueAt(1), "http://www.mozilla.org");
|
||||
|
||||
Assert.equal(aController.input.popup.selectedIndex, 0);
|
||||
aController.handleKeyNavigation(Ci.nsIDOMKeyEvent.DOM_VK_DOWN);
|
||||
Assert.equal(aController.input.popup.selectedIndex, 1);
|
||||
// Simulate mouse interaction changing selectedIndex
|
||||
// ie NOT keyboard interaction:
|
||||
aController.input.popup.selectedIndex = 0;
|
||||
|
||||
aController.handleEnter(false);
|
||||
// Verify that the keyboard-selected thing got inserted,
|
||||
// and not the mouse selection:
|
||||
Assert.equal(aController.input.textValue, "http://www.mozilla.org");
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_handleEnter_mouse() {
|
||||
let results = [
|
||||
["mozilla.com", "http://www.mozilla.com"],
|
||||
["mozilla.org", "http://www.mozilla.org"],
|
||||
];
|
||||
// Then the case where we do not:
|
||||
doSearch("moz", results, function(aController) {
|
||||
Assert.equal(aController.input.textValue, "moz");
|
||||
Assert.equal(aController.getFinalCompleteValueAt(0), "http://www.mozilla.com");
|
||||
Assert.equal(aController.getFinalCompleteValueAt(1), "http://www.mozilla.org");
|
||||
|
||||
Assert.equal(aController.input.popup.selectedIndex, 0);
|
||||
aController.input.popupOpen = true;
|
||||
// Simulate mouse interaction changing selectedIndex
|
||||
// ie NOT keyboard interaction:
|
||||
aController.input.popup.selectedIndex = 1;
|
||||
Assert.equal(selectByWasCalled, false);
|
||||
Assert.equal(aController.input.popup.selectedIndex, 1);
|
||||
|
||||
aController.handleEnter(false);
|
||||
// Verify that the input stayed the same, because no selection was made
|
||||
// with the keyboard:
|
||||
Assert.equal(aController.input.textValue, "moz");
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_handleEnter_preselected() {
|
||||
let results = [
|
||||
["mozilla.com", "http://www.mozilla.com"],
|
||||
["mozilla.org", "http://www.mozilla.org"],
|
||||
];
|
||||
// Then test a preselection.
|
||||
doSearch("moz", results, function(aController) {
|
||||
Assert.equal(aController.input.textValue, "moz");
|
||||
Assert.equal(aController.getFinalCompleteValueAt(0), "http://www.mozilla.com");
|
||||
Assert.equal(aController.getFinalCompleteValueAt(1), "http://www.mozilla.org");
|
||||
|
||||
aController.setInitiallySelectedIndex(0);
|
||||
|
||||
aController.handleEnter(false);
|
||||
// Verify that the input stayed the same, because no selection was made
|
||||
// with the keyboard:
|
||||
Assert.equal(aController.input.textValue, "http://www.mozilla.com");
|
||||
});
|
||||
});
|
||||
|
||||
function doSearch(aSearchString, aResults, aOnCompleteCallback) {
|
||||
selectByWasCalled = false;
|
||||
let search = new AutoCompleteSearchBase(
|
||||
"search",
|
||||
new AutoCompleteResult(aResults)
|
||||
);
|
||||
registerAutoCompleteSearch(search);
|
||||
|
||||
let controller = Cc["@mozilla.org/autocomplete/controller;1"].
|
||||
getService(Ci.nsIAutoCompleteController);
|
||||
|
||||
// Make an AutoCompleteInput that uses our searches and confirms results.
|
||||
let input = new AutoCompleteInput([ search.name ]);
|
||||
input.textValue = aSearchString;
|
||||
|
||||
controller.input = input;
|
||||
controller.startSearch(aSearchString);
|
||||
|
||||
input.onSearchComplete = function onSearchComplete() {
|
||||
aOnCompleteCallback(controller);
|
||||
|
||||
// Clean up.
|
||||
unregisterAutoCompleteSearch(search);
|
||||
run_next_test();
|
||||
};
|
||||
}
|
||||
|
|
@ -1,107 +0,0 @@
|
|||
function AutoCompleteResult(aResultValues) {
|
||||
this.defaultIndex = 0;
|
||||
this._values = aResultValues.map(x => x[0]);
|
||||
this._finalCompleteValues = aResultValues.map(x => x[1]);
|
||||
}
|
||||
AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype);
|
||||
|
||||
function AutoCompleteInput(aSearches) {
|
||||
this.searches = aSearches;
|
||||
this.popup.selectedIndex = 0;
|
||||
this.completeSelectedIndex = true;
|
||||
this.completeDefaultIndex = true;
|
||||
}
|
||||
AutoCompleteInput.prototype = Object.create(AutoCompleteInputBase.prototype);
|
||||
|
||||
add_test(function test_handleEnter() {
|
||||
let results = [
|
||||
["mozilla.com", "https://www.mozilla.com"],
|
||||
["gomozilla.org", "http://www.gomozilla.org"],
|
||||
];
|
||||
doSearch("moz", results, { selectedIndex: 0 }, controller => {
|
||||
let input = controller.input;
|
||||
Assert.equal(input.textValue, "mozilla.com");
|
||||
Assert.equal(controller.getFinalCompleteValueAt(0), results[0][1]);
|
||||
Assert.equal(controller.getFinalCompleteValueAt(1), results[1][1]);
|
||||
Assert.equal(input.popup.selectedIndex, 0);
|
||||
|
||||
controller.handleEnter(false);
|
||||
// Verify that the keyboard-selected thing got inserted,
|
||||
// and not the mouse selection:
|
||||
Assert.equal(controller.input.textValue, "https://www.mozilla.com");
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_handleEnter_otherSelected() {
|
||||
// The popup selection may not coincide with what is filled into the input
|
||||
// field, for example if the user changed it with the mouse and then pressed
|
||||
// Enter. In such a case we should still use the inputField value and not the
|
||||
// popup selected value.
|
||||
let results = [
|
||||
["mozilla.com", "https://www.mozilla.com"],
|
||||
["gomozilla.org", "http://www.gomozilla.org"],
|
||||
];
|
||||
doSearch("moz", results, { selectedIndex: 1 }, controller => {
|
||||
let input = controller.input;
|
||||
Assert.equal(input.textValue, "mozilla.com");
|
||||
Assert.equal(controller.getFinalCompleteValueAt(0), results[0][1]);
|
||||
Assert.equal(controller.getFinalCompleteValueAt(1), results[1][1]);
|
||||
Assert.equal(input.popup.selectedIndex, 1);
|
||||
|
||||
controller.handleEnter(false);
|
||||
// Verify that the keyboard-selected thing got inserted,
|
||||
// and not the mouse selection:
|
||||
Assert.equal(controller.input.textValue, "https://www.mozilla.com");
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_handleEnter_otherSelected_nocompleteselectedindex() {
|
||||
let results = [
|
||||
["mozilla.com", "https://www.mozilla.com"],
|
||||
["gomozilla.org", "http://www.gomozilla.org"],
|
||||
];
|
||||
doSearch("moz", results, { selectedIndex: 1,
|
||||
completeSelectedIndex: false }, controller => {
|
||||
let input = controller.input;
|
||||
Assert.equal(input.textValue, "mozilla.com");
|
||||
Assert.equal(controller.getFinalCompleteValueAt(0), results[0][1]);
|
||||
Assert.equal(controller.getFinalCompleteValueAt(1), results[1][1]);
|
||||
Assert.equal(input.popup.selectedIndex, 1);
|
||||
|
||||
controller.handleEnter(false);
|
||||
// Verify that the keyboard-selected result is inserted, not the
|
||||
// defaultComplete.
|
||||
Assert.equal(controller.input.textValue, "http://www.gomozilla.org");
|
||||
});
|
||||
});
|
||||
|
||||
function doSearch(aSearchString, aResults, aOptions, aOnCompleteCallback) {
|
||||
let search = new AutoCompleteSearchBase(
|
||||
"search",
|
||||
new AutoCompleteResult(aResults)
|
||||
);
|
||||
registerAutoCompleteSearch(search);
|
||||
|
||||
let input = new AutoCompleteInput([ search.name ]);
|
||||
input.textValue = aSearchString;
|
||||
if ("selectedIndex" in aOptions) {
|
||||
input.popup.selectedIndex = aOptions.selectedIndex;
|
||||
}
|
||||
if ("completeSelectedIndex" in aOptions) {
|
||||
input.completeSelectedIndex = aOptions.completeSelectedIndex;
|
||||
}
|
||||
// Needed for defaultIndex completion.
|
||||
input.selectTextRange(aSearchString.length, aSearchString.length);
|
||||
|
||||
let controller = Cc["@mozilla.org/autocomplete/controller;1"].
|
||||
getService(Ci.nsIAutoCompleteController);
|
||||
controller.input = input;
|
||||
controller.startSearch(aSearchString);
|
||||
|
||||
input.onSearchComplete = function onSearchComplete() {
|
||||
aOnCompleteCallback(controller);
|
||||
|
||||
unregisterAutoCompleteSearch(search);
|
||||
run_next_test();
|
||||
};
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function AutoCompleteResult(aValues, aFinalCompleteValues) {
|
||||
this._values = aValues;
|
||||
this._finalCompleteValues = aFinalCompleteValues;
|
||||
this.defaultIndex = 0;
|
||||
}
|
||||
AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype);
|
||||
|
||||
function AutoCompleteInput(aSearches) {
|
||||
this.searches = aSearches;
|
||||
this.popup.selectedIndex = -1;
|
||||
}
|
||||
AutoCompleteInput.prototype = Object.create(AutoCompleteInputBase.prototype);
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_test(function test_handleEnterWithDirectMatchCompleteSelectedIndex() {
|
||||
doSearch("moz", "mozilla.com", "http://www.mozilla.com",
|
||||
{ forceComplete: true, completeSelectedIndex: true }, function(aController) {
|
||||
do_check_eq(aController.input.textValue, "moz");
|
||||
do_check_eq(aController.getFinalCompleteValueAt(0), "http://www.mozilla.com");
|
||||
aController.handleEnter(false);
|
||||
// After enter the final complete value should be shown in the input.
|
||||
do_check_eq(aController.input.textValue, "http://www.mozilla.com");
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_handleEnterWithDirectMatch() {
|
||||
doSearch("mozilla", "mozilla.com", "http://www.mozilla.com",
|
||||
{ forceComplete: true, completeDefaultIndex: true }, function(aController) {
|
||||
// Should autocomplete the search string to a suggestion.
|
||||
do_check_eq(aController.input.textValue, "mozilla.com");
|
||||
do_check_eq(aController.getFinalCompleteValueAt(0), "http://www.mozilla.com");
|
||||
aController.handleEnter(false);
|
||||
// After enter the final complete value should be shown in the input.
|
||||
do_check_eq(aController.input.textValue, "http://www.mozilla.com");
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_handleEnterWithNoMatch() {
|
||||
doSearch("mozilla", "mozilla.com", "http://www.mozilla.com",
|
||||
{ forceComplete: true, completeDefaultIndex: true }, function(aController) {
|
||||
// Should autocomplete the search string to a suggestion.
|
||||
do_check_eq(aController.input.textValue, "mozilla.com");
|
||||
do_check_eq(aController.getFinalCompleteValueAt(0), "http://www.mozilla.com");
|
||||
// Now input something that does not match...
|
||||
aController.input.textValue = "mozillax";
|
||||
// ... and confirm. We don't want one of the values from the previous
|
||||
// results to be taken, since what's now in the input field doesn't match.
|
||||
aController.handleEnter(false);
|
||||
do_check_eq(aController.input.textValue, "mozillax");
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_handleEnterWithIndirectMatch() {
|
||||
doSearch("com", "mozilla.com", "http://www.mozilla.com",
|
||||
{ forceComplete: true, completeDefaultIndex: true }, function(aController) {
|
||||
// Should autocomplete the search string to a suggestion.
|
||||
do_check_eq(aController.input.textValue, "com >> mozilla.com");
|
||||
do_check_eq(aController.getFinalCompleteValueAt(0), "http://www.mozilla.com");
|
||||
aController.handleEnter(false);
|
||||
// After enter the final complete value from the suggestion should be shown
|
||||
// in the input.
|
||||
do_check_eq(aController.input.textValue, "http://www.mozilla.com");
|
||||
});
|
||||
});
|
||||
|
||||
function doSearch(aSearchString, aResultValue, aFinalCompleteValue,
|
||||
aInputProps, aOnCompleteCallback) {
|
||||
let search = new AutoCompleteSearchBase(
|
||||
"search",
|
||||
new AutoCompleteResult([ aResultValue ], [ aFinalCompleteValue ])
|
||||
);
|
||||
registerAutoCompleteSearch(search);
|
||||
|
||||
let controller = Cc["@mozilla.org/autocomplete/controller;1"].
|
||||
getService(Ci.nsIAutoCompleteController);
|
||||
|
||||
// Make an AutoCompleteInput that uses our searches and confirms results.
|
||||
let input = new AutoCompleteInput([ search.name ]);
|
||||
for (var p in aInputProps) {
|
||||
input[p] = aInputProps[p];
|
||||
}
|
||||
input.textValue = aSearchString;
|
||||
// Place the cursor at the end of the input so that completion to
|
||||
// default index will kick in.
|
||||
input.selectTextRange(aSearchString.length, aSearchString.length);
|
||||
|
||||
controller.input = input;
|
||||
controller.startSearch(aSearchString);
|
||||
|
||||
input.onSearchComplete = function onSearchComplete() {
|
||||
aOnCompleteCallback(controller);
|
||||
|
||||
// Clean up.
|
||||
unregisterAutoCompleteSearch(search);
|
||||
run_next_test();
|
||||
};
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function AutoCompleteResult(aValues, aFinalCompleteValues) {
|
||||
this._values = aValues;
|
||||
this._finalCompleteValues = aFinalCompleteValues;
|
||||
this.defaultIndex = 0;
|
||||
}
|
||||
AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype);
|
||||
|
||||
function AutoCompleteInput(aSearches) {
|
||||
this.searches = aSearches;
|
||||
this.popup.selectedIndex = -1;
|
||||
this.completeDefaultIndex = true;
|
||||
}
|
||||
AutoCompleteInput.prototype = Object.create(AutoCompleteInputBase.prototype);
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_test(function test_keyNavigation() {
|
||||
doSearch("moz", "mozilla.com", "http://www.mozilla.com", function(aController) {
|
||||
do_check_eq(aController.input.textValue, "mozilla.com");
|
||||
aController.handleKeyNavigation(Ci.nsIDOMKeyEvent.DOM_VK_RIGHT);
|
||||
do_check_eq(aController.input.textValue, "mozilla.com");
|
||||
});
|
||||
});
|
||||
|
||||
add_test(function test_handleEnter() {
|
||||
doSearch("moz", "mozilla.com", "http://www.mozilla.com", function(aController) {
|
||||
do_check_eq(aController.input.textValue, "mozilla.com");
|
||||
aController.handleEnter(false);
|
||||
do_check_eq(aController.input.textValue, "http://www.mozilla.com");
|
||||
});
|
||||
});
|
||||
|
||||
function doSearch(aSearchString, aResultValue, aFinalCompleteValue, aOnCompleteCallback) {
|
||||
let search = new AutoCompleteSearchBase(
|
||||
"search",
|
||||
new AutoCompleteResult([ aResultValue ], [ aFinalCompleteValue ])
|
||||
);
|
||||
registerAutoCompleteSearch(search);
|
||||
|
||||
let controller = Cc["@mozilla.org/autocomplete/controller;1"].
|
||||
getService(Ci.nsIAutoCompleteController);
|
||||
|
||||
// Make an AutoCompleteInput that uses our searches and confirms results.
|
||||
let input = new AutoCompleteInput([ search.name ]);
|
||||
input.textValue = aSearchString;
|
||||
|
||||
// Caret must be at the end for autofill to happen.
|
||||
let strLen = aSearchString.length;
|
||||
input.selectTextRange(strLen, strLen);
|
||||
controller.input = input;
|
||||
controller.startSearch(aSearchString);
|
||||
|
||||
input.onSearchComplete = function onSearchComplete() {
|
||||
aOnCompleteCallback(controller);
|
||||
|
||||
// Clean up.
|
||||
unregisterAutoCompleteSearch(search);
|
||||
run_next_test();
|
||||
};
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function AutoCompleteResult(aValues) {
|
||||
this._values = aValues;
|
||||
this.defaultIndex = -1;
|
||||
this._typeAheadResult = false;
|
||||
}
|
||||
AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype);
|
||||
|
||||
function AutoCompleteTypeAheadResult(aValues) {
|
||||
this._values = aValues;
|
||||
this.defaultIndex = 0;
|
||||
this._typeAheadResult = true;
|
||||
}
|
||||
AutoCompleteTypeAheadResult.prototype = Object.create(AutoCompleteResultBase.prototype);
|
||||
|
||||
|
||||
/**
|
||||
* Test AutoComplete with multiple AutoCompleteSearch sources, with one of them
|
||||
* being hidden from the popup, but can still do typeahead completion.
|
||||
*/
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
|
||||
var inputStr = "moz";
|
||||
|
||||
// Type ahead result
|
||||
var searchTypeAhead = new AutoCompleteSearchBase("search1",
|
||||
new AutoCompleteTypeAheadResult(["mozillaTest1"]));
|
||||
// Regular result
|
||||
var searchNormal = new AutoCompleteSearchBase("search2",
|
||||
new AutoCompleteResult(["mozillaTest2"]));
|
||||
|
||||
// Register searches so AutoCompleteController can find them
|
||||
registerAutoCompleteSearch(searchNormal);
|
||||
registerAutoCompleteSearch(searchTypeAhead);
|
||||
|
||||
// Make an AutoCompleteInput that uses our searches
|
||||
// and confirms results on search complete.
|
||||
var input = new AutoCompleteInputBase([searchTypeAhead.name, searchNormal.name]);
|
||||
input.completeDefaultIndex = true;
|
||||
input.textValue = inputStr;
|
||||
|
||||
// Caret must be at the end. Autofill doesn't happen unless you're typing
|
||||
// characters at the end.
|
||||
var strLen = inputStr.length;
|
||||
input.selectTextRange(strLen, strLen);
|
||||
do_check_eq(input.selectionStart, strLen);
|
||||
do_check_eq(input.selectionEnd, strLen);
|
||||
|
||||
var controller = Cc["@mozilla.org/autocomplete/controller;1"].
|
||||
getService(Ci.nsIAutoCompleteController);
|
||||
|
||||
controller.input = input;
|
||||
controller.startSearch(inputStr);
|
||||
|
||||
input.onSearchComplete = function() {
|
||||
// Hidden results should still be able to do inline autocomplete
|
||||
do_check_eq(input.textValue, "mozillaTest1");
|
||||
|
||||
// Now, let's fill the textbox with the first result of the popup.
|
||||
// The first search is marked as hidden, so we must always get the
|
||||
// second search.
|
||||
controller.handleEnter(true);
|
||||
do_check_eq(input.textValue, "mozillaTest2");
|
||||
|
||||
// Only one item in the popup.
|
||||
do_check_eq(controller.matchCount, 1);
|
||||
|
||||
// Unregister searches
|
||||
unregisterAutoCompleteSearch(searchNormal);
|
||||
unregisterAutoCompleteSearch(searchTypeAhead);
|
||||
do_test_finished();
|
||||
};
|
||||
}
|
|
@ -1,157 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
||||
function AutoCompleteImmediateSearch(aName, aResult) {
|
||||
this.name = aName;
|
||||
this._result = aResult;
|
||||
}
|
||||
AutoCompleteImmediateSearch.prototype = Object.create(AutoCompleteSearchBase.prototype);
|
||||
AutoCompleteImmediateSearch.prototype.searchType =
|
||||
Ci.nsIAutoCompleteSearchDescriptor.SEARCH_TYPE_IMMEDIATE;
|
||||
AutoCompleteImmediateSearch.prototype.QueryInterface =
|
||||
XPCOMUtils.generateQI([Ci.nsIFactory,
|
||||
Ci.nsIAutoCompleteSearch,
|
||||
Ci.nsIAutoCompleteSearchDescriptor]);
|
||||
|
||||
function AutoCompleteDelayedSearch(aName, aResult) {
|
||||
this.name = aName;
|
||||
this._result = aResult;
|
||||
}
|
||||
AutoCompleteDelayedSearch.prototype = Object.create(AutoCompleteSearchBase.prototype);
|
||||
|
||||
function AutoCompleteResult(aValues, aDefaultIndex) {
|
||||
this._values = aValues;
|
||||
this.defaultIndex = aDefaultIndex;
|
||||
}
|
||||
AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype);
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
/**
|
||||
* An immediate search should be executed synchronously.
|
||||
*/
|
||||
add_test(function test_immediate_search() {
|
||||
let inputStr = "moz";
|
||||
|
||||
let immediateSearch = new AutoCompleteImmediateSearch(
|
||||
"immediate", new AutoCompleteResult(["moz-immediate"], 0));
|
||||
registerAutoCompleteSearch(immediateSearch);
|
||||
let delayedSearch = new AutoCompleteDelayedSearch(
|
||||
"delayed", new AutoCompleteResult(["moz-delayed"], 0));
|
||||
registerAutoCompleteSearch(delayedSearch);
|
||||
|
||||
let controller = Cc["@mozilla.org/autocomplete/controller;1"].
|
||||
getService(Ci.nsIAutoCompleteController);
|
||||
|
||||
let input = new AutoCompleteInputBase([delayedSearch.name,
|
||||
immediateSearch.name]);
|
||||
input.completeDefaultIndex = true;
|
||||
input.textValue = inputStr;
|
||||
|
||||
// Caret must be at the end. Autofill doesn't happen unless you're typing
|
||||
// characters at the end.
|
||||
let strLen = inputStr.length;
|
||||
input.selectTextRange(strLen, strLen);
|
||||
|
||||
controller.input = input;
|
||||
controller.startSearch(inputStr);
|
||||
|
||||
// Immediately check the result, the immediate search should have finished.
|
||||
do_check_eq(input.textValue, "moz-immediate");
|
||||
|
||||
// Wait for both queries to finish.
|
||||
input.onSearchComplete = function() {
|
||||
// Sanity check.
|
||||
do_check_eq(input.textValue, "moz-immediate");
|
||||
|
||||
unregisterAutoCompleteSearch(immediateSearch);
|
||||
unregisterAutoCompleteSearch(delayedSearch);
|
||||
run_next_test();
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* An immediate search should be executed before any delayed search.
|
||||
*/
|
||||
add_test(function test_immediate_search_notimeout() {
|
||||
let inputStr = "moz";
|
||||
|
||||
let immediateSearch = new AutoCompleteImmediateSearch(
|
||||
"immediate", new AutoCompleteResult(["moz-immediate"], 0));
|
||||
registerAutoCompleteSearch(immediateSearch);
|
||||
|
||||
let delayedSearch = new AutoCompleteDelayedSearch(
|
||||
"delayed", new AutoCompleteResult(["moz-delayed"], 0));
|
||||
registerAutoCompleteSearch(delayedSearch);
|
||||
|
||||
let controller = Cc["@mozilla.org/autocomplete/controller;1"].
|
||||
getService(Ci.nsIAutoCompleteController);
|
||||
|
||||
let input = new AutoCompleteInputBase([delayedSearch.name,
|
||||
immediateSearch.name]);
|
||||
input.completeDefaultIndex = true;
|
||||
input.textValue = inputStr;
|
||||
input.timeout = 0;
|
||||
|
||||
// Caret must be at the end. Autofill doesn't happen unless you're typing
|
||||
// characters at the end.
|
||||
let strLen = inputStr.length;
|
||||
input.selectTextRange(strLen, strLen);
|
||||
|
||||
controller.input = input;
|
||||
let complete = false;
|
||||
input.onSearchComplete = function() {
|
||||
complete = true;
|
||||
};
|
||||
controller.startSearch(inputStr);
|
||||
do_check_true(complete);
|
||||
|
||||
// Immediately check the result, the immediate search should have finished.
|
||||
do_check_eq(input.textValue, "moz-immediate");
|
||||
|
||||
unregisterAutoCompleteSearch(immediateSearch);
|
||||
unregisterAutoCompleteSearch(delayedSearch);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
/**
|
||||
* A delayed search should be executed synchronously with a zero timeout.
|
||||
*/
|
||||
add_test(function test_delayed_search_notimeout() {
|
||||
let inputStr = "moz";
|
||||
|
||||
let delayedSearch = new AutoCompleteDelayedSearch(
|
||||
"delayed", new AutoCompleteResult(["moz-delayed"], 0));
|
||||
registerAutoCompleteSearch(delayedSearch);
|
||||
|
||||
let controller = Cc["@mozilla.org/autocomplete/controller;1"].
|
||||
getService(Ci.nsIAutoCompleteController);
|
||||
|
||||
let input = new AutoCompleteInputBase([delayedSearch.name]);
|
||||
input.completeDefaultIndex = true;
|
||||
input.textValue = inputStr;
|
||||
input.timeout = 0;
|
||||
|
||||
// Caret must be at the end. Autofill doesn't happen unless you're typing
|
||||
// characters at the end.
|
||||
let strLen = inputStr.length;
|
||||
input.selectTextRange(strLen, strLen);
|
||||
|
||||
controller.input = input;
|
||||
let complete = false;
|
||||
input.onSearchComplete = function() {
|
||||
complete = true;
|
||||
};
|
||||
controller.startSearch(inputStr);
|
||||
do_check_true(complete);
|
||||
|
||||
// Immediately check the result, the delayed search should have finished.
|
||||
do_check_eq(input.textValue, "moz-delayed");
|
||||
|
||||
unregisterAutoCompleteSearch(delayedSearch);
|
||||
run_next_test();
|
||||
});
|
|
@ -1,14 +0,0 @@
|
|||
function run_test() {
|
||||
let result = Cc["@mozilla.org/autocomplete/simple-result;1"]
|
||||
.createInstance(Ci.nsIAutoCompleteSimpleResult);
|
||||
result.appendMatch("a", "");
|
||||
result.appendMatch("c", "");
|
||||
result.insertMatchAt(1, "b", "");
|
||||
result.insertMatchAt(3, "d", "");
|
||||
|
||||
Assert.equal(result.matchCount, 4);
|
||||
Assert.equal(result.getValueAt(0), "a");
|
||||
Assert.equal(result.getValueAt(1), "b");
|
||||
Assert.equal(result.getValueAt(2), "c");
|
||||
Assert.equal(result.getValueAt(3), "d");
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function AutoCompleteTypeAheadResult(aValues, aFinalCompleteValues) {
|
||||
this._values = aValues;
|
||||
this._finalCompleteValues = aFinalCompleteValues;
|
||||
this.defaultIndex = 0;
|
||||
this._typeAheadResult = true;
|
||||
}
|
||||
AutoCompleteTypeAheadResult.prototype = Object.create(AutoCompleteResultBase.prototype);
|
||||
|
||||
function AutoCompleteResult(aValues) {
|
||||
this._values = aValues;
|
||||
}
|
||||
AutoCompleteResult.prototype = Object.create(AutoCompleteResultBase.prototype);
|
||||
|
||||
function AutoCompleteInput(aSearches) {
|
||||
this.searches = aSearches;
|
||||
this.popupOpen = true;
|
||||
this.completeDefaultIndex = true;
|
||||
this.completeSelectedIndex = true;
|
||||
}
|
||||
AutoCompleteInput.prototype = Object.create(AutoCompleteInputBase.prototype);
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_test(function test_handleEnter() {
|
||||
doSearch("moz", function(aController) {
|
||||
do_check_eq(aController.input.textValue, "mozilla.com");
|
||||
aController.handleEnter(true);
|
||||
do_check_eq(aController.input.textValue, "mozilla.org");
|
||||
});
|
||||
});
|
||||
|
||||
function doSearch(aSearchString, aOnCompleteCallback) {
|
||||
let typeAheadSearch = new AutoCompleteSearchBase(
|
||||
"typeAheadSearch",
|
||||
new AutoCompleteTypeAheadResult([ "mozilla.com" ], [ "http://www.mozilla.com" ])
|
||||
);
|
||||
registerAutoCompleteSearch(typeAheadSearch);
|
||||
|
||||
let search = new AutoCompleteSearchBase(
|
||||
"search",
|
||||
new AutoCompleteResult([ "mozilla.org" ])
|
||||
);
|
||||
registerAutoCompleteSearch(search);
|
||||
|
||||
let controller = Cc["@mozilla.org/autocomplete/controller;1"].
|
||||
getService(Ci.nsIAutoCompleteController);
|
||||
|
||||
// Make an AutoCompleteInput that uses our searches and confirms results.
|
||||
let input = new AutoCompleteInput([ typeAheadSearch.name, search.name ]);
|
||||
input.textValue = aSearchString;
|
||||
|
||||
// Caret must be at the end for autofill to happen.
|
||||
let strLen = aSearchString.length;
|
||||
input.selectTextRange(strLen, strLen);
|
||||
controller.input = input;
|
||||
controller.startSearch(aSearchString);
|
||||
|
||||
input.onSearchComplete = function onSearchComplete() {
|
||||
aOnCompleteCallback(controller);
|
||||
|
||||
// Clean up.
|
||||
unregisterAutoCompleteSearch(search);
|
||||
run_next_test();
|
||||
};
|
||||
}
|
|
@ -1,280 +0,0 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Unit test for Bug 438861 - Previous search results not returned to multiple
|
||||
* searches.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Dummy nsIAutoCompleteInput source that returns
|
||||
* the given list of AutoCompleteSearch names.
|
||||
*
|
||||
* Implements only the methods needed for this test.
|
||||
*/
|
||||
function AutoCompleteInput(aSearches) {
|
||||
this.searches = aSearches;
|
||||
}
|
||||
AutoCompleteInput.prototype = {
|
||||
constructor: AutoCompleteInput,
|
||||
|
||||
// Array of AutoCompleteSearch names
|
||||
searches: null,
|
||||
|
||||
minResultsForPopup: 0,
|
||||
timeout: 10,
|
||||
searchParam: "",
|
||||
textValue: "",
|
||||
disableAutoComplete: false,
|
||||
completeDefaultIndex: false,
|
||||
|
||||
get searchCount() {
|
||||
return this.searches.length;
|
||||
},
|
||||
|
||||
getSearchAt: function(aIndex) {
|
||||
return this.searches[aIndex];
|
||||
},
|
||||
|
||||
onSearchBegin: function() {},
|
||||
onSearchComplete: function() {},
|
||||
|
||||
popupOpen: false,
|
||||
|
||||
popup: {
|
||||
setSelectedIndex: function(aIndex) {},
|
||||
invalidate: function() {},
|
||||
|
||||
// nsISupports implementation
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsISupports) ||
|
||||
iid.equals(Ci.nsIAutoCompletePopup))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
},
|
||||
|
||||
// nsISupports implementation
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsISupports) ||
|
||||
iid.equals(Ci.nsIAutoCompleteInput))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* nsIAutoCompleteResult implementation
|
||||
*/
|
||||
function AutoCompleteResult(aValues, aComments, aStyles) {
|
||||
this._values = aValues;
|
||||
this._comments = aComments;
|
||||
this._styles = aStyles;
|
||||
if (this._values.length > 0) {
|
||||
this.searchResult = Ci.nsIAutoCompleteResult.RESULT_SUCCESS;
|
||||
} else {
|
||||
this.searchResult = Ci.nsIAutoCompleteResult.NOMATCH;
|
||||
}
|
||||
}
|
||||
AutoCompleteResult.prototype = {
|
||||
constructor: AutoCompleteResult,
|
||||
|
||||
// Arrays
|
||||
_values: null,
|
||||
_comments: null,
|
||||
_styles: null,
|
||||
|
||||
searchString: "",
|
||||
searchResult: null,
|
||||
|
||||
defaultIndex: 0,
|
||||
|
||||
get matchCount() {
|
||||
return this._values.length;
|
||||
},
|
||||
|
||||
getValueAt: function(aIndex) {
|
||||
return this._values[aIndex];
|
||||
},
|
||||
|
||||
getLabelAt: function(aIndex) {
|
||||
return this.getValueAt(aIndex);
|
||||
},
|
||||
|
||||
getCommentAt: function(aIndex) {
|
||||
return this._comments[aIndex];
|
||||
},
|
||||
|
||||
getStyleAt: function(aIndex) {
|
||||
return this._styles[aIndex];
|
||||
},
|
||||
|
||||
getImageAt: function(aIndex) {
|
||||
return "";
|
||||
},
|
||||
|
||||
getFinalCompleteValueAt: function(aIndex) {
|
||||
return this.getValueAt(aIndex);
|
||||
},
|
||||
|
||||
removeValueAt: function (aRowIndex, aRemoveFromDb) {},
|
||||
|
||||
// nsISupports implementation
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsISupports) ||
|
||||
iid.equals(Ci.nsIAutoCompleteResult))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* nsIAutoCompleteSearch implementation that always returns
|
||||
* the same result set.
|
||||
*/
|
||||
function AutoCompleteSearch(aName, aResult) {
|
||||
this.name = aName;
|
||||
this._result = aResult;
|
||||
}
|
||||
AutoCompleteSearch.prototype = {
|
||||
constructor: AutoCompleteSearch,
|
||||
|
||||
// Search name. Used by AutoCompleteController
|
||||
name: null,
|
||||
|
||||
// AutoCompleteResult
|
||||
_result: null,
|
||||
|
||||
_previousResult: null,
|
||||
|
||||
|
||||
/**
|
||||
* Return the same result set for every search
|
||||
*/
|
||||
startSearch: function(aSearchString,
|
||||
aSearchParam,
|
||||
aPreviousResult,
|
||||
aListener)
|
||||
{
|
||||
this._previousResult = aPreviousResult;
|
||||
aListener.onSearchResult(this, this._result);
|
||||
},
|
||||
|
||||
stopSearch: function() {},
|
||||
|
||||
// nsISupports implementation
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsISupports) ||
|
||||
iid.equals(Ci.nsIFactory) ||
|
||||
iid.equals(Ci.nsIAutoCompleteSearch))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
|
||||
// nsIFactory implementation
|
||||
createInstance: function(outer, iid) {
|
||||
return this.QueryInterface(iid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper to register an AutoCompleteSearch with the given name.
|
||||
* Allows the AutoCompleteController to find the search.
|
||||
*/
|
||||
function registerAutoCompleteSearch(aSearch) {
|
||||
var name = "@mozilla.org/autocomplete/search;1?name=" + aSearch.name;
|
||||
|
||||
var uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].
|
||||
getService(Ci.nsIUUIDGenerator);
|
||||
var cid = uuidGenerator.generateUUID();
|
||||
|
||||
var desc = "Test AutoCompleteSearch";
|
||||
|
||||
var componentManager = Components.manager
|
||||
.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
componentManager.registerFactory(cid, desc, name, aSearch);
|
||||
|
||||
// Keep the id on the object so we can unregister later
|
||||
aSearch.cid = cid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper to unregister an AutoCompleteSearch.
|
||||
*/
|
||||
function unregisterAutoCompleteSearch(aSearch) {
|
||||
var componentManager = Components.manager
|
||||
.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
componentManager.unregisterFactory(aSearch.cid, aSearch);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function run_test() {
|
||||
// Make an AutoCompleteSearch that always returns nothing
|
||||
var search1 = new AutoCompleteSearch("test-previous-result1",
|
||||
new AutoCompleteResult(["hello1"], [""], [""]));
|
||||
|
||||
var search2 = new AutoCompleteSearch("test-previous-result2",
|
||||
new AutoCompleteResult(["hello2"], [""], [""]));
|
||||
|
||||
// Register search so AutoCompleteController can find them
|
||||
registerAutoCompleteSearch(search1);
|
||||
registerAutoCompleteSearch(search2);
|
||||
|
||||
var controller = Components.classes["@mozilla.org/autocomplete/controller;1"].
|
||||
getService(Components.interfaces.nsIAutoCompleteController);
|
||||
|
||||
// Make an AutoCompleteInput that uses our search
|
||||
// and confirms results on search complete
|
||||
var input = new AutoCompleteInput([search1.name,
|
||||
search2.name]);
|
||||
var numSearchesStarted = 0;
|
||||
|
||||
input.onSearchBegin = function() {
|
||||
numSearchesStarted++;
|
||||
};
|
||||
|
||||
input.onSearchComplete = function() {
|
||||
do_check_eq(controller.searchStatus,
|
||||
Ci.nsIAutoCompleteController.STATUS_COMPLETE_MATCH);
|
||||
do_check_eq(controller.matchCount, 2);
|
||||
|
||||
if (numSearchesStarted == 1) {
|
||||
do_check_eq(search1._previousResult, null);
|
||||
do_check_eq(search2._previousResult, null);
|
||||
|
||||
// Now start it again
|
||||
controller.startSearch("test");
|
||||
return;
|
||||
}
|
||||
do_check_neq(search1._previousResult, null);
|
||||
do_check_neq(search2._previousResult, null);
|
||||
|
||||
// Unregister searches
|
||||
unregisterAutoCompleteSearch(search1);
|
||||
unregisterAutoCompleteSearch(search2);
|
||||
|
||||
do_test_finished();
|
||||
};
|
||||
|
||||
controller.input = input;
|
||||
|
||||
// Search is asynchronous, so don't let the test finish immediately
|
||||
do_test_pending();
|
||||
|
||||
controller.startSearch("test");
|
||||
}
|
|
@ -1,187 +0,0 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/**
|
||||
* Purpose of the test is to check that a stopSearch call comes always before a
|
||||
* startSearch call.
|
||||
*/
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
|
||||
/**
|
||||
* Dummy nsIAutoCompleteInput source that returns
|
||||
* the given list of AutoCompleteSearch names.
|
||||
*
|
||||
* Implements only the methods needed for this test.
|
||||
*/
|
||||
function AutoCompleteInput(aSearches)
|
||||
{
|
||||
this.searches = aSearches;
|
||||
}
|
||||
AutoCompleteInput.prototype = {
|
||||
constructor: AutoCompleteInput,
|
||||
minResultsForPopup: 0,
|
||||
timeout: 10,
|
||||
searchParam: "",
|
||||
textValue: "hello",
|
||||
disableAutoComplete: false,
|
||||
completeDefaultIndex: false,
|
||||
set popupOpen(val) { return val; }, // ignore
|
||||
get popupOpen() { return false; },
|
||||
get searchCount() { return this.searches.length; },
|
||||
getSearchAt: function(aIndex) { return this.searches[aIndex]; },
|
||||
onSearchBegin: function() {},
|
||||
onSearchComplete: function() {},
|
||||
onTextReverted: function () {},
|
||||
onTextEntered: function () {},
|
||||
popup: {
|
||||
selectBy: function() {},
|
||||
invalidate: function() {},
|
||||
set selectedIndex(val) { return val; }, // ignore
|
||||
get selectedIndex() { return -1 },
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompletePopup])
|
||||
},
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompleteInput])
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* nsIAutoCompleteSearch implementation.
|
||||
*/
|
||||
function AutoCompleteSearch(aName)
|
||||
{
|
||||
this.name = aName;
|
||||
}
|
||||
AutoCompleteSearch.prototype = {
|
||||
constructor: AutoCompleteSearch,
|
||||
stopSearchInvoked: true,
|
||||
startSearch: function(aSearchString, aSearchParam, aPreviousResult, aListener)
|
||||
{
|
||||
print("Check stop search has been called");
|
||||
do_check_true(this.stopSearchInvoked);
|
||||
this.stopSearchInvoked = false;
|
||||
},
|
||||
stopSearch: function()
|
||||
{
|
||||
this.stopSearchInvoked = true;
|
||||
},
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsIFactory
|
||||
, Ci.nsIAutoCompleteSearch
|
||||
]),
|
||||
createInstance: function(outer, iid)
|
||||
{
|
||||
return this.QueryInterface(iid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper to register an AutoCompleteSearch with the given name.
|
||||
* Allows the AutoCompleteController to find the search.
|
||||
*/
|
||||
function registerAutoCompleteSearch(aSearch)
|
||||
{
|
||||
let name = "@mozilla.org/autocomplete/search;1?name=" + aSearch.name;
|
||||
let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].
|
||||
getService(Ci.nsIUUIDGenerator);
|
||||
let cid = uuidGenerator.generateUUID();
|
||||
let desc = "Test AutoCompleteSearch";
|
||||
let componentManager = Components.manager
|
||||
.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
componentManager.registerFactory(cid, desc, name, aSearch);
|
||||
// Keep the id on the object so we can unregister later
|
||||
aSearch.cid = cid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper to unregister an AutoCompleteSearch.
|
||||
*/
|
||||
function unregisterAutoCompleteSearch(aSearch) {
|
||||
let componentManager = Components.manager
|
||||
.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
componentManager.unregisterFactory(aSearch.cid, aSearch);
|
||||
}
|
||||
|
||||
|
||||
var gTests = [
|
||||
function(controller) {
|
||||
print("handleText");
|
||||
controller.input.textValue = "hel";
|
||||
controller.handleText();
|
||||
},
|
||||
function(controller) {
|
||||
print("handleStartComposition");
|
||||
controller.handleStartComposition();
|
||||
},
|
||||
function(controller) {
|
||||
print("handleEndComposition");
|
||||
controller.handleEndComposition();
|
||||
// an input event always follows compositionend event.
|
||||
controller.handleText();
|
||||
},
|
||||
function(controller) {
|
||||
print("handleEscape");
|
||||
controller.handleEscape();
|
||||
},
|
||||
function(controller) {
|
||||
print("handleEnter");
|
||||
controller.handleEnter(false);
|
||||
},
|
||||
function(controller) {
|
||||
print("handleTab");
|
||||
controller.handleTab();
|
||||
},
|
||||
|
||||
function(controller) {
|
||||
print("handleKeyNavigation");
|
||||
controller.handleKeyNavigation(Ci.nsIDOMKeyEvent.DOM_VK_UP);
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
var gSearch;
|
||||
var gCurrentTest;
|
||||
function run_test() {
|
||||
// Make an AutoCompleteSearch that always returns nothing
|
||||
gSearch = new AutoCompleteSearch("test");
|
||||
registerAutoCompleteSearch(gSearch);
|
||||
|
||||
let controller = Cc["@mozilla.org/autocomplete/controller;1"].
|
||||
getService(Ci.nsIAutoCompleteController);
|
||||
|
||||
// Make an AutoCompleteInput that uses our search.
|
||||
let input = new AutoCompleteInput([gSearch.name]);
|
||||
controller.input = input;
|
||||
|
||||
input.onSearchBegin = function() {
|
||||
do_execute_soon(function() {
|
||||
gCurrentTest(controller);
|
||||
});
|
||||
};
|
||||
input.onSearchComplete = function() {
|
||||
run_next_test(controller);
|
||||
}
|
||||
|
||||
// Search is asynchronous, so don't let the test finish immediately
|
||||
do_test_pending();
|
||||
|
||||
run_next_test(controller);
|
||||
}
|
||||
|
||||
function run_next_test(controller) {
|
||||
if (gTests.length == 0) {
|
||||
unregisterAutoCompleteSearch(gSearch);
|
||||
controller.stopSearch();
|
||||
controller.input = null;
|
||||
do_test_finished();
|
||||
return;
|
||||
}
|
||||
|
||||
gCurrentTest = gTests.shift();
|
||||
controller.startSearch("hello");
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
[DEFAULT]
|
||||
head = head_autocomplete.js
|
||||
tail =
|
||||
|
||||
[test_330578.js]
|
||||
[test_378079.js]
|
||||
[test_393191.js]
|
||||
[test_440866.js]
|
||||
[test_463023.js]
|
||||
[test_660156.js]
|
||||
[test_autocomplete_multiple.js]
|
||||
[test_autocomplete_userContextId.js]
|
||||
[test_autofillSelectedPopupIndex.js]
|
||||
[test_badDefaultIndex.js]
|
||||
[test_completeDefaultIndex_casing.js]
|
||||
[test_finalCompleteValue.js]
|
||||
[test_finalCompleteValue_defaultIndex.js]
|
||||
[test_finalCompleteValue_forceComplete.js]
|
||||
[test_finalCompleteValueSelectedIndex.js]
|
||||
[test_finalDefaultCompleteValue.js]
|
||||
[test_hiddenResult.js]
|
||||
[test_immediate_search.js]
|
||||
[test_insertMatchAt.js]
|
||||
[test_popupSelectionVsDefaultCompleteValue.js]
|
||||
[test_previousResult.js]
|
||||
[test_stopSearch.js]
|
|
@ -4,13 +4,6 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
XPCSHELL_TESTS_MANIFESTS += ['test/unit_win/xpcshell.ini']
|
||||
elif CONFIG['OS_ARCH'] != 'Darwin':
|
||||
XPCSHELL_TESTS_MANIFESTS += ['test/unit_unix/xpcshell.ini']
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsICommandLine.idl',
|
||||
'nsICommandLineHandler.idl',
|
||||
|
@ -20,11 +13,6 @@ XPIDL_SOURCES += [
|
|||
|
||||
XPIDL_MODULE = 'commandlines'
|
||||
|
||||
SOURCES += [
|
||||
'nsCommandLine.cpp',
|
||||
]
|
||||
SOURCES += ['nsCommandLine.cpp']
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
with Files('**'):
|
||||
BUG_COMPONENT = ('Toolkit', 'Startup and Profile System')
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"../../../../../testing/xpcshell/xpcshell.eslintrc.js"
|
||||
]
|
||||
};
|
|
@ -1,7 +0,0 @@
|
|||
[Desktop Entry]
|
||||
Version=1.0
|
||||
Encoding=UTF-8
|
||||
Name=test_bug410156
|
||||
Type=Link
|
||||
URL=http://www.bug410156.com/
|
||||
Icon=gnome-fs-bookmark
|
|
@ -1,9 +0,0 @@
|
|||
[InternetShortcut]
|
||||
URL=http://www.bug410156.com/
|
||||
IDList=
|
||||
HotKey=0
|
||||
[{000214A0-0000-0000-C000-000000000046}]
|
||||
Prop3=19,2
|
||||
[InternetShortcut.A]
|
||||
[InternetShortcut.W]
|
||||
URL=http://www.bug410156.com/
|
|
@ -1,6 +0,0 @@
|
|||
function run_test() {
|
||||
var cmdLine=Components.classes["@mozilla.org/toolkit/command-line;1"].createInstance(Components.interfaces.nsICommandLine);
|
||||
try {
|
||||
cmdLine.getArgument(cmdLine.length);
|
||||
} catch (e) {}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function run_test() {
|
||||
var clClass = Components.classes["@mozilla.org/toolkit/command-line;1"];
|
||||
var commandLine = clClass.createInstance();
|
||||
do_check_true("length" in commandLine);
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
[DEFAULT]
|
||||
head =
|
||||
tail =
|
||||
skip-if = toolkit == 'android'
|
||||
support-files =
|
||||
data/test_bug410156.desktop
|
||||
data/test_bug410156.url
|
||||
|
||||
[test_classinfo.js]
|
||||
[test_bug666224.js]
|
|
@ -1,7 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"../../../../../testing/xpcshell/xpcshell.eslintrc.js"
|
||||
]
|
||||
};
|
|
@ -1,11 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function run_test() {
|
||||
var clClass = Components.classes["@mozilla.org/toolkit/command-line;1"];
|
||||
var commandLine = clClass.createInstance();
|
||||
var urlFile = do_get_file("../unit/data/test_bug410156.desktop");
|
||||
var uri = commandLine.resolveURI(urlFile.path);
|
||||
do_check_eq(uri.spec, "http://www.bug410156.com/");
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
[DEFAULT]
|
||||
head =
|
||||
tail =
|
||||
skip-if = toolkit == 'android'
|
||||
support-files =
|
||||
!/toolkit/components/commandlines/test/unit/data/test_bug410156.desktop
|
||||
!/toolkit/components/commandlines/test/unit/data/test_bug410156.url
|
||||
|
||||
[test_bug410156.js]
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue