Remove tests from toolkit.

This commit is contained in:
Fedor 2020-03-12 20:43:39 +03:00
parent 35b20eff09
commit 275db572d9
2528 changed files with 94 additions and 265092 deletions

View File

@ -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']

View File

@ -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')

View File

@ -1,7 +0,0 @@
"use strict";
module.exports = {
"extends": [
"../../../../testing/mochitest/chrome.eslintrc.js"
]
};

View File

@ -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]

View File

@ -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."}
]
}
}

View File

@ -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."}
]
}
}

View File

@ -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."}
]
}
}

View File

@ -1,3 +0,0 @@
{
"version": 1
}

View File

@ -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."}
]
}

View File

@ -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."}
]
}

View File

@ -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."}
]
}

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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']

View File

@ -1,7 +0,0 @@
"use strict";
module.exports = {
"extends": [
"../../../../../testing/mochitest/browser.eslintrc.js"
]
};

View File

@ -1,8 +0,0 @@
[DEFAULT]
head = head.js
support-files =
browser_compartments.html
browser_compartments_frame.html
browser_compartments_script.js
[browser_aboutperformance.js]

View File

@ -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;
});

View File

@ -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>

View File

@ -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>

View File

@ -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);

View File

@ -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;
}

View File

@ -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',

View File

@ -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)
{
}

View File

@ -1 +0,0 @@
content addonshim1 content/

View File

@ -1,2 +0,0 @@
<html>
</html>

View File

@ -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>

View File

@ -1,7 +0,0 @@
"use strict";
module.exports = {
"extends": [
"../../../../../testing/mochitest/browser.eslintrc.js"
]
};

View File

@ -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]

View File

@ -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);
}
});

View File

@ -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>

View File

@ -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>

View File

@ -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)
{
}

View File

@ -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>

View File

@ -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']

View File

@ -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')

View File

@ -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

View File

@ -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();
}

View File

@ -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'

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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')

View File

@ -1,7 +0,0 @@
"use strict";
module.exports = {
"extends": [
"../../../../../testing/xpcshell/xpcshell.eslintrc.js"
]
};

View File

@ -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);
}

View File

@ -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");
});

View File

@ -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");
});

View File

@ -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);
}
}
}

View File

@ -1,8 +0,0 @@
[DEFAULT]
head=head.js
tail=
skip-if = toolkit == 'android'
[test_AsyncShutdown.js]
[test_AsyncShutdown_leave_uncaught.js]
[test_converters.js]

View File

@ -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')

View File

@ -1,7 +0,0 @@
"use strict";
module.exports = {
"extends": [
"../../../../../testing/xpcshell/xpcshell.eslintrc.js"
]
};

View File

@ -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);
}

View File

@ -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");
}

View File

@ -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");
}

View File

@ -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");
}

View File

@ -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");
}

View File

@ -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);
}

View File

@ -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();
};
}

View File

@ -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");
}

View File

@ -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;
}

View File

@ -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");
}

View File

@ -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();
}

View File

@ -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();
};
}

View File

@ -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();
};
}

View File

@ -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();
};
}

View File

@ -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();
};
}

View File

@ -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();
};
}

View File

@ -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();
};
}

View File

@ -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();
};
}

View File

@ -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();
});

View File

@ -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");
}

View File

@ -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();
};
}

View File

@ -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");
}

View File

@ -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");
}

View File

@ -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]

View File

@ -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')

View File

@ -1,7 +0,0 @@
"use strict";
module.exports = {
"extends": [
"../../../../../testing/xpcshell/xpcshell.eslintrc.js"
]
};

View File

@ -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

View File

@ -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/

View File

@ -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) {}
}

View File

@ -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);
}

View File

@ -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]

View File

@ -1,7 +0,0 @@
"use strict";
module.exports = {
"extends": [
"../../../../../testing/xpcshell/xpcshell.eslintrc.js"
]
};

View File

@ -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/");
}

View File

@ -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