mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-05 23:38:38 +09:00
Merge remote-tracking branch 'origin/master' into custom
This commit is contained in:
commit
55828393ce
2798 changed files with 8839 additions and 257595 deletions
|
|
@ -51,9 +51,6 @@ XPCOMUtils.defineLazyGetter(Services, "ppmm", () => {
|
|||
});
|
||||
|
||||
var initTable = [
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
["androidBridge", "@mozilla.org/android/bridge;1", "nsIAndroidBridge"],
|
||||
#endif
|
||||
["appShell", "@mozilla.org/appshell/appShellService;1", "nsIAppShellService"],
|
||||
["cache", "@mozilla.org/network/cache-service;1", "nsICacheService"],
|
||||
["cache2", "@mozilla.org/netwerk/cache-storage-service;1", "nsICacheStorageService"],
|
||||
|
|
|
|||
|
|
@ -4,17 +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/xpcshell/xpcshell.ini']
|
||||
BROWSER_CHROME_MANIFESTS += ['tests/browser/browser.ini']
|
||||
MOCHITEST_MANIFESTS += ['tests/mochitest/mochitest.ini']
|
||||
MOCHITEST_CHROME_MANIFESTS += ['tests/chrome/chrome.ini']
|
||||
|
||||
TESTING_JS_MODULES += [
|
||||
'tests/MockDocument.jsm',
|
||||
'tests/PromiseTestUtils.jsm',
|
||||
'tests/xpcshell/TestIntegration.jsm',
|
||||
]
|
||||
|
||||
SPHINX_TREES['toolkit_modules'] = 'docs'
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
|
|
@ -116,16 +105,14 @@ EXTRA_PP_JS_MODULES += [
|
|||
'Services.jsm',
|
||||
]
|
||||
|
||||
if 'Android' != CONFIG['OS_TARGET']:
|
||||
EXTRA_PP_JS_MODULES += [
|
||||
'LightweightThemeConsumer.jsm',
|
||||
]
|
||||
|
||||
DIRS += [
|
||||
'subprocess',
|
||||
]
|
||||
else:
|
||||
DEFINES['ANDROID'] = True
|
||||
EXTRA_PP_JS_MODULES += [
|
||||
'LightweightThemeConsumer.jsm',
|
||||
]
|
||||
|
||||
DIRS += [
|
||||
'subprocess',
|
||||
]
|
||||
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
|
|
|
|||
|
|
@ -4,9 +4,7 @@
|
|||
# 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/.
|
||||
|
||||
EXTRA_PP_JS_MODULES += [
|
||||
'Subprocess.jsm',
|
||||
]
|
||||
EXTRA_PP_JS_MODULES += ['Subprocess.jsm']
|
||||
|
||||
EXTRA_JS_MODULES.subprocess += [
|
||||
'subprocess_common.jsm',
|
||||
|
|
@ -27,6 +25,4 @@ else:
|
|||
'subprocess_worker_unix.js',
|
||||
]
|
||||
|
||||
XPCSHELL_TESTS_MANIFESTS += ['test/xpcshell/xpcshell.ini']
|
||||
|
||||
SPHINX_TREES['toolkit_modules/subprocess'] = ['docs']
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = { // eslint-disable-line no-undef
|
||||
"extends": "../../../../../testing/xpcshell/xpcshell.eslintrc.js",
|
||||
};
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
#!/usr/bin/env python2
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import signal
|
||||
import struct
|
||||
import sys
|
||||
|
||||
|
||||
def output(line):
|
||||
sys.stdout.write(struct.pack('@I', len(line)))
|
||||
sys.stdout.write(line)
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
def echo_loop():
|
||||
while True:
|
||||
line = sys.stdin.readline()
|
||||
if not line:
|
||||
break
|
||||
|
||||
output(line)
|
||||
|
||||
|
||||
if sys.platform == "win32":
|
||||
import msvcrt
|
||||
msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
|
||||
|
||||
|
||||
cmd = sys.argv[1]
|
||||
if cmd == 'echo':
|
||||
echo_loop()
|
||||
elif cmd == 'exit':
|
||||
sys.exit(int(sys.argv[2]))
|
||||
elif cmd == 'env':
|
||||
for var in sys.argv[2:]:
|
||||
output(os.environ.get(var, ''))
|
||||
elif cmd == 'pwd':
|
||||
output(os.path.abspath(os.curdir))
|
||||
elif cmd == 'print_args':
|
||||
for arg in sys.argv[2:]:
|
||||
output(arg)
|
||||
elif cmd == 'ignore_sigterm':
|
||||
signal.signal(signal.SIGTERM, signal.SIG_IGN)
|
||||
|
||||
output('Ready')
|
||||
while True:
|
||||
try:
|
||||
signal.pause()
|
||||
except AttributeError:
|
||||
import time
|
||||
time.sleep(3600)
|
||||
elif cmd == 'print':
|
||||
sys.stdout.write(sys.argv[2])
|
||||
sys.stderr.write(sys.argv[3])
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
|
||||
"resource://gre/modules/AppConstants.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||
"resource://gre/modules/osfile.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Subprocess",
|
||||
"resource://gre/modules/Subprocess.jsm");
|
||||
|
|
@ -1,769 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
Cu.import("resource://gre/modules/AppConstants.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/Timer.jsm");
|
||||
|
||||
|
||||
const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
|
||||
|
||||
const MAX_ROUND_TRIP_TIME_MS = AppConstants.DEBUG || AppConstants.ASAN ? 18 : 9;
|
||||
const MAX_RETRIES = 5;
|
||||
|
||||
let PYTHON;
|
||||
let PYTHON_BIN;
|
||||
let PYTHON_DIR;
|
||||
|
||||
const TEST_SCRIPT = do_get_file("data_test_script.py").path;
|
||||
|
||||
let read = pipe => {
|
||||
return pipe.readUint32().then(count => {
|
||||
return pipe.readString(count);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
let readAll = Task.async(function* (pipe) {
|
||||
let result = [];
|
||||
let string;
|
||||
while ((string = yield pipe.readString())) {
|
||||
result.push(string);
|
||||
}
|
||||
|
||||
return result.join("");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* setup() {
|
||||
PYTHON = yield Subprocess.pathSearch(env.get("PYTHON"));
|
||||
|
||||
PYTHON_BIN = OS.Path.basename(PYTHON);
|
||||
PYTHON_DIR = OS.Path.dirname(PYTHON);
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_io() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "echo"],
|
||||
});
|
||||
|
||||
Assert.throws(() => { proc.stdout.read(-1); },
|
||||
/non-negative integer/);
|
||||
Assert.throws(() => { proc.stdout.read(1.1); },
|
||||
/non-negative integer/);
|
||||
|
||||
Assert.throws(() => { proc.stdout.read(Infinity); },
|
||||
/non-negative integer/);
|
||||
Assert.throws(() => { proc.stdout.read(NaN); },
|
||||
/non-negative integer/);
|
||||
|
||||
Assert.throws(() => { proc.stdout.readString(-1); },
|
||||
/non-negative integer/);
|
||||
Assert.throws(() => { proc.stdout.readString(1.1); },
|
||||
/non-negative integer/);
|
||||
|
||||
Assert.throws(() => { proc.stdout.readJSON(-1); },
|
||||
/positive integer/);
|
||||
Assert.throws(() => { proc.stdout.readJSON(0); },
|
||||
/positive integer/);
|
||||
Assert.throws(() => { proc.stdout.readJSON(1.1); },
|
||||
/positive integer/);
|
||||
|
||||
|
||||
const LINE1 = "I'm a leaf on the wind.\n";
|
||||
const LINE2 = "Watch how I soar.\n";
|
||||
|
||||
|
||||
let outputPromise = read(proc.stdout);
|
||||
|
||||
yield new Promise(resolve => setTimeout(resolve, 100));
|
||||
|
||||
let [output] = yield Promise.all([
|
||||
outputPromise,
|
||||
proc.stdin.write(LINE1),
|
||||
]);
|
||||
|
||||
equal(output, LINE1, "Got expected output");
|
||||
|
||||
|
||||
// Make sure it succeeds whether the write comes before or after the
|
||||
// read.
|
||||
let inputPromise = proc.stdin.write(LINE2);
|
||||
|
||||
yield new Promise(resolve => setTimeout(resolve, 100));
|
||||
|
||||
[output] = yield Promise.all([
|
||||
read(proc.stdout),
|
||||
inputPromise,
|
||||
]);
|
||||
|
||||
equal(output, LINE2, "Got expected output");
|
||||
|
||||
|
||||
let JSON_BLOB = {foo: {bar: "baz"}};
|
||||
|
||||
inputPromise = proc.stdin.write(JSON.stringify(JSON_BLOB) + "\n");
|
||||
|
||||
output = yield proc.stdout.readUint32().then(count => {
|
||||
return proc.stdout.readJSON(count);
|
||||
});
|
||||
|
||||
Assert.deepEqual(output, JSON_BLOB, "Got expected JSON output");
|
||||
|
||||
|
||||
yield proc.stdin.close();
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_large_io() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "echo"],
|
||||
});
|
||||
|
||||
const LINE = "I'm a leaf on the wind.\n";
|
||||
const BUFFER_SIZE = 4096;
|
||||
|
||||
// Create a message that's ~3/4 the input buffer size.
|
||||
let msg = Array(BUFFER_SIZE * .75 / 16 | 0).fill("0123456789abcdef").join("") + "\n";
|
||||
|
||||
// This sequence of writes and reads crosses several buffer size
|
||||
// boundaries, and causes some branches of the read buffer code to be
|
||||
// exercised which are not exercised by other tests.
|
||||
proc.stdin.write(msg);
|
||||
proc.stdin.write(msg);
|
||||
proc.stdin.write(LINE);
|
||||
|
||||
let output = yield read(proc.stdout);
|
||||
equal(output, msg, "Got the expected output");
|
||||
|
||||
output = yield read(proc.stdout);
|
||||
equal(output, msg, "Got the expected output");
|
||||
|
||||
output = yield read(proc.stdout);
|
||||
equal(output, LINE, "Got the expected output");
|
||||
|
||||
proc.stdin.close();
|
||||
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_huge() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "echo"],
|
||||
});
|
||||
|
||||
// This should be large enough to fill most pipe input/output buffers.
|
||||
const MESSAGE_SIZE = 1024 * 16;
|
||||
|
||||
let msg = Array(MESSAGE_SIZE).fill("0123456789abcdef").join("") + "\n";
|
||||
|
||||
proc.stdin.write(msg);
|
||||
|
||||
let output = yield read(proc.stdout);
|
||||
equal(output, msg, "Got the expected output");
|
||||
|
||||
proc.stdin.close();
|
||||
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_round_trip_perf() {
|
||||
let roundTripTime = Infinity;
|
||||
for (let i = 0; i < MAX_RETRIES && roundTripTime > MAX_ROUND_TRIP_TIME_MS; i++) {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "echo"],
|
||||
});
|
||||
|
||||
|
||||
const LINE = "I'm a leaf on the wind.\n";
|
||||
|
||||
let now = Date.now();
|
||||
const COUNT = 1000;
|
||||
for (let j = 0; j < COUNT; j++) {
|
||||
let [output] = yield Promise.all([
|
||||
read(proc.stdout),
|
||||
proc.stdin.write(LINE),
|
||||
]);
|
||||
|
||||
// We don't want to log this for every iteration, but we still need
|
||||
// to fail if it goes wrong.
|
||||
if (output !== LINE) {
|
||||
equal(output, LINE, "Got expected output");
|
||||
}
|
||||
}
|
||||
|
||||
roundTripTime = (Date.now() - now) / COUNT;
|
||||
|
||||
yield proc.stdin.close();
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
}
|
||||
|
||||
ok(roundTripTime <= MAX_ROUND_TRIP_TIME_MS,
|
||||
`Expected round trip time (${roundTripTime}ms) to be less than ${MAX_ROUND_TRIP_TIME_MS}ms`);
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_stderr_default() {
|
||||
const LINE1 = "I'm a leaf on the wind.\n";
|
||||
const LINE2 = "Watch how I soar.\n";
|
||||
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "print", LINE1, LINE2],
|
||||
});
|
||||
|
||||
equal(proc.stderr, undefined, "There should be no stderr pipe by default");
|
||||
|
||||
let stdout = yield readAll(proc.stdout);
|
||||
|
||||
equal(stdout, LINE1, "Got the expected stdout output");
|
||||
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_stderr_pipe() {
|
||||
const LINE1 = "I'm a leaf on the wind.\n";
|
||||
const LINE2 = "Watch how I soar.\n";
|
||||
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "print", LINE1, LINE2],
|
||||
stderr: "pipe",
|
||||
});
|
||||
|
||||
let [stdout, stderr] = yield Promise.all([
|
||||
readAll(proc.stdout),
|
||||
readAll(proc.stderr),
|
||||
]);
|
||||
|
||||
equal(stdout, LINE1, "Got the expected stdout output");
|
||||
equal(stderr, LINE2, "Got the expected stderr output");
|
||||
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_stderr_merged() {
|
||||
const LINE1 = "I'm a leaf on the wind.\n";
|
||||
const LINE2 = "Watch how I soar.\n";
|
||||
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "print", LINE1, LINE2],
|
||||
stderr: "stdout",
|
||||
});
|
||||
|
||||
equal(proc.stderr, undefined, "There should be no stderr pipe by default");
|
||||
|
||||
let stdout = yield readAll(proc.stdout);
|
||||
|
||||
equal(stdout, LINE1 + LINE2, "Got the expected merged stdout output");
|
||||
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_read_after_exit() {
|
||||
const LINE1 = "I'm a leaf on the wind.\n";
|
||||
const LINE2 = "Watch how I soar.\n";
|
||||
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "print", LINE1, LINE2],
|
||||
stderr: "pipe",
|
||||
});
|
||||
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
equal(exitCode, 0, "Process exited with expected code");
|
||||
|
||||
|
||||
let [stdout, stderr] = yield Promise.all([
|
||||
readAll(proc.stdout),
|
||||
readAll(proc.stderr),
|
||||
]);
|
||||
|
||||
equal(stdout, LINE1, "Got the expected stdout output");
|
||||
equal(stderr, LINE2, "Got the expected stderr output");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_lazy_close_output() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "echo"],
|
||||
});
|
||||
|
||||
const LINE1 = "I'm a leaf on the wind.\n";
|
||||
const LINE2 = "Watch how I soar.\n";
|
||||
|
||||
let writePromises = [
|
||||
proc.stdin.write(LINE1),
|
||||
proc.stdin.write(LINE2),
|
||||
];
|
||||
let closedPromise = proc.stdin.close();
|
||||
|
||||
|
||||
let output1 = yield read(proc.stdout);
|
||||
let output2 = yield read(proc.stdout);
|
||||
|
||||
yield Promise.all([...writePromises, closedPromise]);
|
||||
|
||||
equal(output1, LINE1, "Got expected output");
|
||||
equal(output2, LINE2, "Got expected output");
|
||||
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_lazy_close_input() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "echo"],
|
||||
});
|
||||
|
||||
let readPromise = proc.stdout.readUint32();
|
||||
let closedPromise = proc.stdout.close();
|
||||
|
||||
|
||||
const LINE = "I'm a leaf on the wind.\n";
|
||||
|
||||
proc.stdin.write(LINE);
|
||||
proc.stdin.close();
|
||||
|
||||
let len = yield readPromise;
|
||||
equal(len, LINE.length);
|
||||
|
||||
yield closedPromise;
|
||||
|
||||
|
||||
// Don't test for a successful exit here. The process may exit with a
|
||||
// write error if we close the pipe after it's written the message
|
||||
// size but before it's written the message.
|
||||
yield proc.wait();
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_force_close() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "echo"],
|
||||
});
|
||||
|
||||
let readPromise = proc.stdout.readUint32();
|
||||
let closedPromise = proc.stdout.close(true);
|
||||
|
||||
yield Assert.rejects(
|
||||
readPromise,
|
||||
function(e) {
|
||||
equal(e.errorCode, Subprocess.ERROR_END_OF_FILE,
|
||||
"Got the expected error code");
|
||||
return /File closed/.test(e.message);
|
||||
},
|
||||
"Promise should be rejected when file is closed");
|
||||
|
||||
yield closedPromise;
|
||||
yield proc.stdin.close();
|
||||
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_eof() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "echo"],
|
||||
});
|
||||
|
||||
let readPromise = proc.stdout.readUint32();
|
||||
|
||||
yield proc.stdin.close();
|
||||
|
||||
yield Assert.rejects(
|
||||
readPromise,
|
||||
function(e) {
|
||||
equal(e.errorCode, Subprocess.ERROR_END_OF_FILE,
|
||||
"Got the expected error code");
|
||||
return /File closed/.test(e.message);
|
||||
},
|
||||
"Promise should be rejected on EOF");
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_invalid_json() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "echo"],
|
||||
});
|
||||
|
||||
const LINE = "I'm a leaf on the wind.\n";
|
||||
|
||||
proc.stdin.write(LINE);
|
||||
proc.stdin.close();
|
||||
|
||||
let count = yield proc.stdout.readUint32();
|
||||
let readPromise = proc.stdout.readJSON(count);
|
||||
|
||||
yield Assert.rejects(
|
||||
readPromise,
|
||||
function(e) {
|
||||
equal(e.errorCode, Subprocess.ERROR_INVALID_JSON,
|
||||
"Got the expected error code");
|
||||
return /SyntaxError/.test(e);
|
||||
},
|
||||
"Promise should be rejected on EOF");
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
if (AppConstants.isPlatformAndVersionAtLeast("win", "6")) {
|
||||
add_task(function* test_subprocess_inherited_descriptors() {
|
||||
let {ctypes, libc, win32} = Cu.import("resource://gre/modules/subprocess/subprocess_win.jsm");
|
||||
|
||||
let secAttr = new win32.SECURITY_ATTRIBUTES();
|
||||
secAttr.nLength = win32.SECURITY_ATTRIBUTES.size;
|
||||
secAttr.bInheritHandle = true;
|
||||
|
||||
let handles = win32.createPipe(secAttr, 0);
|
||||
|
||||
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "echo"],
|
||||
});
|
||||
|
||||
|
||||
// Close the output end of the pipe.
|
||||
// Ours should be the only copy, so reads should fail after this.
|
||||
handles[1].dispose();
|
||||
|
||||
let buffer = new ArrayBuffer(1);
|
||||
let succeeded = libc.ReadFile(handles[0], buffer, buffer.byteLength,
|
||||
null, null);
|
||||
|
||||
ok(!succeeded, "ReadFile should fail on broken pipe");
|
||||
equal(ctypes.winLastError, win32.ERROR_BROKEN_PIPE, "Read should fail with ERROR_BROKEN_PIPE");
|
||||
|
||||
|
||||
proc.stdin.close();
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
add_task(function* test_subprocess_wait() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "exit", "42"],
|
||||
});
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 42, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_pathSearch() {
|
||||
let promise = Subprocess.call({
|
||||
command: PYTHON_BIN,
|
||||
arguments: ["-u", TEST_SCRIPT, "exit", "13"],
|
||||
environment: {
|
||||
PATH: PYTHON_DIR,
|
||||
},
|
||||
});
|
||||
|
||||
yield Assert.rejects(
|
||||
promise,
|
||||
function(error) {
|
||||
return error.errorCode == Subprocess.ERROR_BAD_EXECUTABLE;
|
||||
},
|
||||
"Subprocess.call should fail for a bad executable");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_workdir() {
|
||||
let procDir = yield OS.File.getCurrentDirectory();
|
||||
let tmpDirFile = Components.classes["@mozilla.org/file/local;1"]
|
||||
.createInstance(Components.interfaces.nsILocalFile);
|
||||
tmpDirFile.initWithPath(OS.Constants.Path.tmpDir);
|
||||
tmpDirFile.normalize();
|
||||
let tmpDir = tmpDirFile.path;
|
||||
|
||||
notEqual(procDir, tmpDir,
|
||||
"Current process directory must not be the current temp directory");
|
||||
|
||||
function* pwd(options) {
|
||||
let proc = yield Subprocess.call(Object.assign({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "pwd"],
|
||||
}, options));
|
||||
|
||||
let pwdOutput = read(proc.stdout);
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
|
||||
return pwdOutput;
|
||||
}
|
||||
|
||||
let dir = yield pwd({});
|
||||
equal(dir, procDir, "Process should normally launch in current process directory");
|
||||
|
||||
dir = yield pwd({workdir: tmpDir});
|
||||
equal(dir, tmpDir, "Process should launch in the directory specified in `workdir`");
|
||||
|
||||
dir = yield OS.File.getCurrentDirectory();
|
||||
equal(dir, procDir, "`workdir` should not change the working directory of the current process");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_term() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "echo"],
|
||||
});
|
||||
|
||||
// Windows does not support killing processes gracefully, so they will
|
||||
// always exit with -9 there.
|
||||
let retVal = AppConstants.platform == "win" ? -9 : -15;
|
||||
|
||||
// Kill gracefully with the default timeout of 300ms.
|
||||
let {exitCode} = yield proc.kill();
|
||||
|
||||
equal(exitCode, retVal, "Got expected exit code");
|
||||
|
||||
({exitCode} = yield proc.wait());
|
||||
|
||||
equal(exitCode, retVal, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_kill() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "echo"],
|
||||
});
|
||||
|
||||
// Force kill with no gracefull termination timeout.
|
||||
let {exitCode} = yield proc.kill(0);
|
||||
|
||||
equal(exitCode, -9, "Got expected exit code");
|
||||
|
||||
({exitCode} = yield proc.wait());
|
||||
|
||||
equal(exitCode, -9, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_kill_timeout() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "ignore_sigterm"],
|
||||
});
|
||||
|
||||
// Wait for the process to set up its signal handler and tell us it's
|
||||
// ready.
|
||||
let msg = yield read(proc.stdout);
|
||||
equal(msg, "Ready", "Process is ready");
|
||||
|
||||
// Kill gracefully with the default timeout of 300ms.
|
||||
// Expect a force kill after 300ms, since the process traps SIGTERM.
|
||||
const TIMEOUT = 300;
|
||||
let startTime = Date.now();
|
||||
|
||||
let {exitCode} = yield proc.kill(TIMEOUT);
|
||||
|
||||
// Graceful termination is not supported on Windows, so don't bother
|
||||
// testing the timeout there.
|
||||
if (AppConstants.platform != "win") {
|
||||
let diff = Date.now() - startTime;
|
||||
ok(diff >= TIMEOUT, `Process was killed after ${diff}ms (expected ~${TIMEOUT}ms)`);
|
||||
}
|
||||
|
||||
equal(exitCode, -9, "Got expected exit code");
|
||||
|
||||
({exitCode} = yield proc.wait());
|
||||
|
||||
equal(exitCode, -9, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_arguments() {
|
||||
let args = [
|
||||
String.raw`C:\Program Files\Company\Program.exe`,
|
||||
String.raw`\\NETWORK SHARE\Foo Directory${"\\"}`,
|
||||
String.raw`foo bar baz`,
|
||||
String.raw`"foo bar baz"`,
|
||||
String.raw`foo " bar`,
|
||||
String.raw`Thing \" with "" "\" \\\" \\\\" quotes\\" \\`,
|
||||
];
|
||||
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "print_args", ...args],
|
||||
});
|
||||
|
||||
for (let [i, arg] of args.entries()) {
|
||||
let val = yield read(proc.stdout);
|
||||
equal(val, arg, `Got correct value for args[${i}]`);
|
||||
}
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
// Windows XP can't handle launching Python with a partial environment.
|
||||
if (!AppConstants.isPlatformAndVersionAtMost("win", "5.2")) {
|
||||
add_task(function* test_subprocess_environment() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "env", "PATH", "FOO"],
|
||||
environment: {
|
||||
FOO: "BAR",
|
||||
},
|
||||
});
|
||||
|
||||
let path = yield read(proc.stdout);
|
||||
let foo = yield read(proc.stdout);
|
||||
|
||||
equal(path, "", "Got expected $PATH value");
|
||||
equal(foo, "BAR", "Got expected $FOO value");
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
add_task(function* test_subprocess_environmentAppend() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "env", "PATH", "FOO"],
|
||||
environmentAppend: true,
|
||||
environment: {
|
||||
FOO: "BAR",
|
||||
},
|
||||
});
|
||||
|
||||
let path = yield read(proc.stdout);
|
||||
let foo = yield read(proc.stdout);
|
||||
|
||||
equal(path, env.get("PATH"), "Got expected $PATH value");
|
||||
equal(foo, "BAR", "Got expected $FOO value");
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
|
||||
proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "env", "PATH", "FOO"],
|
||||
environmentAppend: true,
|
||||
});
|
||||
|
||||
path = yield read(proc.stdout);
|
||||
foo = yield read(proc.stdout);
|
||||
|
||||
equal(path, env.get("PATH"), "Got expected $PATH value");
|
||||
equal(foo, "", "Got expected $FOO value");
|
||||
|
||||
({exitCode} = yield proc.wait());
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_bad_executable() {
|
||||
// Test with a non-executable file.
|
||||
|
||||
let textFile = do_get_file("data_text_file.txt").path;
|
||||
|
||||
let promise = Subprocess.call({
|
||||
command: textFile,
|
||||
arguments: [],
|
||||
});
|
||||
|
||||
yield Assert.rejects(
|
||||
promise,
|
||||
function(error) {
|
||||
if (AppConstants.platform == "win") {
|
||||
return /Failed to create process/.test(error.message);
|
||||
}
|
||||
return error.errorCode == Subprocess.ERROR_BAD_EXECUTABLE;
|
||||
},
|
||||
"Subprocess.call should fail for a bad executable");
|
||||
|
||||
// Test with a nonexistent file.
|
||||
promise = Subprocess.call({
|
||||
command: textFile + ".doesNotExist",
|
||||
arguments: [],
|
||||
});
|
||||
|
||||
yield Assert.rejects(
|
||||
promise,
|
||||
function(error) {
|
||||
return error.errorCode == Subprocess.ERROR_BAD_EXECUTABLE;
|
||||
},
|
||||
"Subprocess.call should fail for a bad executable");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_cleanup() {
|
||||
let {SubprocessImpl} = Cu.import("resource://gre/modules/Subprocess.jsm");
|
||||
|
||||
let worker = SubprocessImpl.Process.getWorker();
|
||||
|
||||
let openFiles = yield worker.call("getOpenFiles", []);
|
||||
let processes = yield worker.call("getProcesses", []);
|
||||
|
||||
equal(openFiles.size, 0, "No remaining open files");
|
||||
equal(processes.size, 0, "No remaining processes");
|
||||
});
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
let env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
|
||||
|
||||
add_task(function* test_getEnvironment() {
|
||||
env.set("FOO", "BAR");
|
||||
|
||||
let environment = Subprocess.getEnvironment();
|
||||
|
||||
equal(environment.FOO, "BAR");
|
||||
equal(environment.PATH, env.get("PATH"));
|
||||
|
||||
env.set("FOO", null);
|
||||
|
||||
environment = Subprocess.getEnvironment();
|
||||
equal(environment.FOO || "", "");
|
||||
});
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
let envService = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
|
||||
|
||||
const PYTHON = envService.get("PYTHON");
|
||||
|
||||
const PYTHON_BIN = OS.Path.basename(PYTHON);
|
||||
const PYTHON_DIR = OS.Path.dirname(PYTHON);
|
||||
|
||||
const DOES_NOT_EXIST = OS.Path.join(OS.Constants.Path.tmpDir,
|
||||
"ThisPathDoesNotExist");
|
||||
|
||||
const PATH_SEP = AppConstants.platform == "win" ? ";" : ":";
|
||||
|
||||
|
||||
add_task(function* test_pathSearchAbsolute() {
|
||||
let env = {};
|
||||
|
||||
let path = yield Subprocess.pathSearch(PYTHON, env);
|
||||
equal(path, PYTHON, "Full path resolves even with no PATH.");
|
||||
|
||||
env.PATH = "";
|
||||
path = yield Subprocess.pathSearch(PYTHON, env);
|
||||
equal(path, PYTHON, "Full path resolves even with empty PATH.");
|
||||
|
||||
yield Assert.rejects(
|
||||
Subprocess.pathSearch(DOES_NOT_EXIST, env),
|
||||
function(e) {
|
||||
equal(e.errorCode, Subprocess.ERROR_BAD_EXECUTABLE,
|
||||
"Got the expected error code");
|
||||
return /File at path .* does not exist, or is not (executable|a normal file)/.test(e.message);
|
||||
},
|
||||
"Absolute path should throw for a nonexistent execuable");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_pathSearchRelative() {
|
||||
let env = {};
|
||||
|
||||
yield Assert.rejects(
|
||||
Subprocess.pathSearch(PYTHON_BIN, env),
|
||||
function(e) {
|
||||
equal(e.errorCode, Subprocess.ERROR_BAD_EXECUTABLE,
|
||||
"Got the expected error code");
|
||||
return /Executable not found:/.test(e.message);
|
||||
},
|
||||
"Relative path should not be found when PATH is missing");
|
||||
|
||||
env.PATH = [DOES_NOT_EXIST, PYTHON_DIR].join(PATH_SEP);
|
||||
|
||||
let path = yield Subprocess.pathSearch(PYTHON_BIN, env);
|
||||
equal(path, PYTHON, "Correct executable should be found in the path");
|
||||
});
|
||||
|
||||
|
||||
add_task({
|
||||
skip_if: () => AppConstants.platform != "win",
|
||||
}, function* test_pathSearch_PATHEXT() {
|
||||
ok(PYTHON_BIN.endsWith(".exe"), "Python executable must end with .exe");
|
||||
|
||||
const python_bin = PYTHON_BIN.slice(0, -4);
|
||||
|
||||
let env = {
|
||||
PATH: PYTHON_DIR,
|
||||
PATHEXT: [".com", ".exe", ".foobar"].join(";"),
|
||||
};
|
||||
|
||||
let path = yield Subprocess.pathSearch(python_bin, env);
|
||||
equal(path, PYTHON, "Correct executable should be found in the path, with guessed extension");
|
||||
});
|
||||
// IMPORTANT: Do not add any tests beyond this point without removing
|
||||
// the `skip_if` condition from the previous task, or it will prevent
|
||||
// all succeeding tasks from running when it does not match.
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
[DEFAULT]
|
||||
head = head.js
|
||||
tail =
|
||||
firefox-appdir = browser
|
||||
skip-if = os == 'android'
|
||||
subprocess = true
|
||||
support-files =
|
||||
data_text_file.txt
|
||||
data_test_script.py
|
||||
|
||||
[test_subprocess.js]
|
||||
skip-if = os == 'win' # Path issues due to venv changes on the test machines
|
||||
[test_subprocess_getEnvironment.js]
|
||||
[test_subprocess_pathSearch.js]
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
/**
|
||||
* Provides infrastructure for tests that would require mock document.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["MockDocument"]
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.importGlobalProperties(["URL"]);
|
||||
|
||||
const MockDocument = {
|
||||
/**
|
||||
* Create a document for the given URL containing the given HTML with the ownerDocument of all <form>s having a mocked location.
|
||||
*/
|
||||
createTestDocument(aDocumentURL, aContent = "<form>", aType = "text/html") {
|
||||
let parser = Cc["@mozilla.org/xmlextras/domparser;1"].
|
||||
createInstance(Ci.nsIDOMParser);
|
||||
parser.init();
|
||||
let parsedDoc = parser.parseFromString(aContent, aType);
|
||||
|
||||
for (let element of parsedDoc.forms) {
|
||||
this.mockOwnerDocumentProperty(element, parsedDoc, aDocumentURL);
|
||||
}
|
||||
return parsedDoc;
|
||||
},
|
||||
|
||||
mockOwnerDocumentProperty(aElement, aDoc, aURL) {
|
||||
// Mock the document.location object so we can unit test without a frame. We use a proxy
|
||||
// instead of just assigning to the property since it's not configurable or writable.
|
||||
let document = new Proxy(aDoc, {
|
||||
get(target, property, receiver) {
|
||||
// document.location is normally null when a document is outside of a "browsing context".
|
||||
// See https://html.spec.whatwg.org/#the-location-interface
|
||||
if (property == "location") {
|
||||
return new URL(aURL);
|
||||
}
|
||||
return target[property];
|
||||
},
|
||||
});
|
||||
|
||||
// Assign element.ownerDocument to the proxy so document.location works.
|
||||
Object.defineProperty(aElement, "ownerDocument", {
|
||||
value: document,
|
||||
});
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
|
|
@ -1,241 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/*
|
||||
* Detects and reports unhandled rejections during test runs. Test harnesses
|
||||
* will fail tests in this case, unless the test whitelists itself.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
"PromiseTestUtils",
|
||||
];
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm", this);
|
||||
|
||||
// Keep "JSMPromise" separate so "Promise" still refers to DOM Promises.
|
||||
let JSMPromise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
|
||||
|
||||
// For now, we need test harnesses to provide a reference to Assert.jsm.
|
||||
let Assert = null;
|
||||
|
||||
this.PromiseTestUtils = {
|
||||
/**
|
||||
* Array of objects containing the details of the Promise rejections that are
|
||||
* currently left uncaught. This includes DOM Promise and Promise.jsm. When
|
||||
* rejections in DOM Promises are consumed, they are removed from this list.
|
||||
*
|
||||
* The objects contain at least the following properties:
|
||||
* {
|
||||
* message: The error message associated with the rejection, if any.
|
||||
* date: Date object indicating when the rejection was observed.
|
||||
* id: For DOM Promise only, the Promise ID from PromiseDebugging. This is
|
||||
* only used for tracking and should not be checked by the callers.
|
||||
* stack: nsIStackFrame, SavedFrame, or string indicating the stack at the
|
||||
* time the rejection was triggered. May also be null if the
|
||||
* rejection was triggered while a script was on the stack.
|
||||
* }
|
||||
*/
|
||||
_rejections: [],
|
||||
|
||||
/**
|
||||
* When an uncaught rejection is detected, it is ignored if one of the
|
||||
* functions in this array returns true when called with the rejection details
|
||||
* as its only argument. When a function matches an expected rejection, it is
|
||||
* then removed from the array.
|
||||
*/
|
||||
_rejectionIgnoreFns: [],
|
||||
|
||||
/**
|
||||
* Called only by the test infrastructure, registers the rejection observers.
|
||||
*
|
||||
* This should be called only once, and a matching "uninit" call must be made
|
||||
* or the tests will crash on shutdown.
|
||||
*/
|
||||
init() {
|
||||
if (this._initialized) {
|
||||
Cu.reportError("This object was already initialized.");
|
||||
return;
|
||||
}
|
||||
|
||||
PromiseDebugging.addUncaughtRejectionObserver(this);
|
||||
|
||||
// Promise.jsm rejections are only reported to this observer when requested,
|
||||
// so we don't have to store a key to remove them when consumed.
|
||||
JSMPromise.Debugging.addUncaughtErrorObserver(
|
||||
rejection => this._rejections.push(rejection));
|
||||
|
||||
this._initialized = true;
|
||||
},
|
||||
_initialized: false,
|
||||
|
||||
/**
|
||||
* Called only by the test infrastructure, unregisters the observers.
|
||||
*/
|
||||
uninit() {
|
||||
if (!this._initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
PromiseDebugging.removeUncaughtRejectionObserver(this);
|
||||
JSMPromise.Debugging.clearUncaughtErrorObservers();
|
||||
|
||||
this._initialized = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Called only by the test infrastructure, spins the event loop until the
|
||||
* messages for pending DOM Promise rejections have been processed.
|
||||
*/
|
||||
ensureDOMPromiseRejectionsProcessed() {
|
||||
let observed = false;
|
||||
let observer = {
|
||||
onLeftUncaught: promise => {
|
||||
if (PromiseDebugging.getState(promise).reason ===
|
||||
this._ensureDOMPromiseRejectionsProcessedReason) {
|
||||
observed = true;
|
||||
}
|
||||
},
|
||||
onConsumed() {},
|
||||
};
|
||||
|
||||
PromiseDebugging.addUncaughtRejectionObserver(observer);
|
||||
Promise.reject(this._ensureDOMPromiseRejectionsProcessedReason);
|
||||
while (!observed) {
|
||||
Services.tm.mainThread.processNextEvent(true);
|
||||
}
|
||||
PromiseDebugging.removeUncaughtRejectionObserver(observer);
|
||||
},
|
||||
_ensureDOMPromiseRejectionsProcessedReason: {},
|
||||
|
||||
/**
|
||||
* Called only by the tests for PromiseDebugging.addUncaughtRejectionObserver
|
||||
* and for JSMPromise.Debugging, disables the observers in this module.
|
||||
*/
|
||||
disableUncaughtRejectionObserverForSelfTest() {
|
||||
this.uninit();
|
||||
},
|
||||
|
||||
/**
|
||||
* Called by tests that have been whitelisted, disables the observers in this
|
||||
* module. For new tests where uncaught rejections are expected, you should
|
||||
* use the more granular expectUncaughtRejection function instead.
|
||||
*/
|
||||
thisTestLeaksUncaughtRejectionsAndShouldBeFixed() {
|
||||
this.uninit();
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets or updates the Assert object instance to be used for error reporting.
|
||||
*/
|
||||
set Assert(assert) {
|
||||
Assert = assert;
|
||||
},
|
||||
|
||||
// UncaughtRejectionObserver
|
||||
onLeftUncaught(promise) {
|
||||
let message = "(Unable to convert rejection reason to string.)";
|
||||
try {
|
||||
let reason = PromiseDebugging.getState(promise).reason;
|
||||
if (reason === this._ensureDOMPromiseRejectionsProcessedReason) {
|
||||
// Ignore the special promise for ensureDOMPromiseRejectionsProcessed.
|
||||
return;
|
||||
}
|
||||
message = reason.message || ("" + reason);
|
||||
} catch (ex) {}
|
||||
|
||||
// It's important that we don't store any reference to the provided Promise
|
||||
// object or its value after this function returns in order to avoid leaks.
|
||||
this._rejections.push({
|
||||
id: PromiseDebugging.getPromiseID(promise),
|
||||
message,
|
||||
date: new Date(),
|
||||
stack: PromiseDebugging.getRejectionStack(promise),
|
||||
});
|
||||
},
|
||||
|
||||
// UncaughtRejectionObserver
|
||||
onConsumed(promise) {
|
||||
// We don't expect that many unhandled rejections will appear at the same
|
||||
// time, so the algorithm doesn't need to be optimized for that case.
|
||||
let id = PromiseDebugging.getPromiseID(promise);
|
||||
let index = this._rejections.findIndex(rejection => rejection.id == id);
|
||||
// If we get a consumption notification for a rejection that was left
|
||||
// uncaught before this module was initialized, we can safely ignore it.
|
||||
if (index != -1) {
|
||||
this._rejections.splice(index, 1);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Informs the test suite that the test code will generate a Promise rejection
|
||||
* that will still be unhandled when the test file terminates.
|
||||
*
|
||||
* This method must be called once for each instance of Promise that is
|
||||
* expected to be uncaught, even if the rejection reason is the same for each
|
||||
* instance.
|
||||
*
|
||||
* If the expected rejection does not occur, the test will fail.
|
||||
*
|
||||
* @param regExpOrCheckFn
|
||||
* This can either be a regular expression that should match the error
|
||||
* message of the rejection, or a check function that is invoked with
|
||||
* the rejection details object as its first argument.
|
||||
*/
|
||||
expectUncaughtRejection(regExpOrCheckFn) {
|
||||
let checkFn = !("test" in regExpOrCheckFn) ? regExpOrCheckFn :
|
||||
rejection => regExpOrCheckFn.test(rejection.message);
|
||||
this._rejectionIgnoreFns.push(checkFn);
|
||||
},
|
||||
|
||||
/**
|
||||
* Fails the test if there are any uncaught rejections at this time that have
|
||||
* not been whitelisted using expectUncaughtRejection.
|
||||
*
|
||||
* Depending on the configuration of the test suite, this function might only
|
||||
* report the details of the first uncaught rejection that was generated.
|
||||
*
|
||||
* This is called by the test suite at the end of each test function.
|
||||
*/
|
||||
assertNoUncaughtRejections() {
|
||||
// Ask Promise.jsm to report all uncaught rejections to the observer now.
|
||||
JSMPromise.Debugging.flushUncaughtErrors();
|
||||
|
||||
// If there is any uncaught rejection left at this point, the test fails.
|
||||
while (this._rejections.length > 0) {
|
||||
let rejection = this._rejections.shift();
|
||||
|
||||
// If one of the ignore functions matches, ignore the rejection, then
|
||||
// remove the function so that each function only matches one rejection.
|
||||
let index = this._rejectionIgnoreFns.findIndex(f => f(rejection));
|
||||
if (index != -1) {
|
||||
this._rejectionIgnoreFns.splice(index, 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Report the error. This operation can throw an exception, depending on
|
||||
// the configuration of the test suite that handles the assertion.
|
||||
Assert.ok(false,
|
||||
`A promise chain failed to handle a rejection:` +
|
||||
` ${rejection.message} - rejection date: ${rejection.date}`+
|
||||
` - stack: ${rejection.stack}`);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Fails the test if any rejection indicated by expectUncaughtRejection has
|
||||
* not yet been reported at this time.
|
||||
*
|
||||
* This is called by the test suite at the end of each test file.
|
||||
*/
|
||||
assertNoMoreExpectedRejections() {
|
||||
// Only log this condition is there is a failure.
|
||||
if (this._rejectionIgnoreFns.length > 0) {
|
||||
Assert.equal(this._rejectionIgnoreFns.length, 0,
|
||||
"Unable to find a rejection expected by expectUncaughtRejection.");
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"../../../../testing/mochitest/browser.eslintrc.js"
|
||||
]
|
||||
};
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
function handleRequest(aRequest, aResponse) {
|
||||
aResponse.setStatusLine(aRequest.httpVersion, 200);
|
||||
if (aRequest.hasHeader('Cookie')) {
|
||||
let value = aRequest.getHeader("Cookie");
|
||||
if (value == "blinky=1") {
|
||||
aResponse.setHeader("Set-Cookie", "dinky=1");
|
||||
}
|
||||
aResponse.write("cookie-present");
|
||||
} else {
|
||||
aResponse.setHeader("Set-Cookie", "foopy=1");
|
||||
aResponse.write("cookie-not-present");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
function handleRequest(aRequest, aResponse) {
|
||||
aResponse.setStatusLine(aRequest.httpVersion, 302);
|
||||
aResponse.setHeader("Location", "./dummy_page.html");
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
dummy_page.html
|
||||
metadata_*.html
|
||||
testremotepagemanager.html
|
||||
file_WebNavigation_page1.html
|
||||
file_WebNavigation_page2.html
|
||||
file_WebNavigation_page3.html
|
||||
file_WebRequest_page1.html
|
||||
file_WebRequest_page2.html
|
||||
file_image_good.png
|
||||
file_image_bad.png
|
||||
file_image_redirect.png
|
||||
file_style_good.css
|
||||
file_style_bad.css
|
||||
file_style_redirect.css
|
||||
file_script_good.js
|
||||
file_script_bad.js
|
||||
file_script_redirect.js
|
||||
file_script_xhr.js
|
||||
WebRequest_dynamic.sjs
|
||||
WebRequest_redirection.sjs
|
||||
|
||||
[browser_AsyncPrefs.js]
|
||||
[browser_Battery.js]
|
||||
[browser_Deprecated.js]
|
||||
[browser_Finder.js]
|
||||
[browser_Finder_hidden_textarea.js]
|
||||
[browser_FinderHighlighter.js]
|
||||
skip-if = debug || os = "linux"
|
||||
support-files = file_FinderSample.html
|
||||
[browser_Geometry.js]
|
||||
[browser_InlineSpellChecker.js]
|
||||
[browser_WebNavigation.js]
|
||||
[browser_WebRequest.js]
|
||||
[browser_WebRequest_cookies.js]
|
||||
[browser_WebRequest_filtering.js]
|
||||
[browser_PageMetadata.js]
|
||||
[browser_PromiseMessage.js]
|
||||
[browser_RemotePageManager.js]
|
||||
[browser_Troubleshoot.js]
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
const kWhiteListedBool = "testing.allowed-prefs.some-bool-pref";
|
||||
const kWhiteListedChar = "testing.allowed-prefs.some-char-pref";
|
||||
const kWhiteListedInt = "testing.allowed-prefs.some-int-pref";
|
||||
|
||||
function resetPrefs() {
|
||||
for (let pref of [kWhiteListedBool, kWhiteListedChar, kWhiteListedBool]) {
|
||||
Services.prefs.clearUserPref(pref);
|
||||
}
|
||||
}
|
||||
|
||||
registerCleanupFunction(resetPrefs);
|
||||
|
||||
Services.prefs.getDefaultBranch("testing.allowed-prefs.").setBoolPref("some-bool-pref", false);
|
||||
Services.prefs.getDefaultBranch("testing.allowed-prefs.").setCharPref("some-char-pref", "");
|
||||
Services.prefs.getDefaultBranch("testing.allowed-prefs.").setIntPref("some-int-pref", 0);
|
||||
|
||||
function* runTest() {
|
||||
let {AsyncPrefs} = Cu.import("resource://gre/modules/AsyncPrefs.jsm", {});
|
||||
const kInChildProcess = Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT;
|
||||
|
||||
// Need to define these again because when run in a content task we have no scope access.
|
||||
const kNotWhiteListed = "some.pref.thats.not.whitelisted";
|
||||
const kWhiteListedBool = "testing.allowed-prefs.some-bool-pref";
|
||||
const kWhiteListedChar = "testing.allowed-prefs.some-char-pref";
|
||||
const kWhiteListedInt = "testing.allowed-prefs.some-int-pref";
|
||||
|
||||
const procDesc = kInChildProcess ? "child process" : "parent process";
|
||||
|
||||
const valueResultMap = [
|
||||
[true, "Bool"],
|
||||
[false, "Bool"],
|
||||
[10, "Int"],
|
||||
[-1, "Int"],
|
||||
["", "Char"],
|
||||
["stuff", "Char"],
|
||||
[[], false],
|
||||
[{}, false],
|
||||
[BrowserUtils.makeURI("http://mozilla.org/"), false],
|
||||
];
|
||||
|
||||
const prefMap = [
|
||||
["Bool", kWhiteListedBool],
|
||||
["Char", kWhiteListedChar],
|
||||
["Int", kWhiteListedInt],
|
||||
];
|
||||
|
||||
function doesFail(pref, value) {
|
||||
let msg = `Should not succeed setting ${pref} to ${value} in ${procDesc}`;
|
||||
return AsyncPrefs.set(pref, value).then(() => ok(false, msg), error => ok(true, msg + "; " + error));
|
||||
}
|
||||
|
||||
function doesWork(pref, value) {
|
||||
let msg = `Should be able to set ${pref} to ${value} in ${procDesc}`;
|
||||
return AsyncPrefs.set(pref, value).then(() => ok(true, msg), error => ok(false, msg + "; " + error));
|
||||
}
|
||||
|
||||
function doReset(pref) {
|
||||
let msg = `Should be able to reset ${pref} in ${procDesc}`;
|
||||
return AsyncPrefs.reset(pref).then(() => ok(true, msg), () => ok(false, msg));
|
||||
}
|
||||
|
||||
for (let [val, ] of valueResultMap) {
|
||||
yield doesFail(kNotWhiteListed, val);
|
||||
is(Services.prefs.prefHasUserValue(kNotWhiteListed), false, "Pref shouldn't get changed");
|
||||
}
|
||||
|
||||
let resetMsg = `Should not succeed resetting ${kNotWhiteListed} in ${procDesc}`;
|
||||
AsyncPrefs.reset(kNotWhiteListed).then(() => ok(false, resetMsg), error => ok(true, resetMsg + "; " + error));
|
||||
|
||||
for (let [type, pref] of prefMap) {
|
||||
for (let [val, result] of valueResultMap) {
|
||||
if (result == type) {
|
||||
yield doesWork(pref, val);
|
||||
is(Services.prefs["get" + type + "Pref"](pref), val, "Pref should have been updated");
|
||||
yield doReset(pref);
|
||||
} else {
|
||||
yield doesFail(pref, val);
|
||||
is(Services.prefs.prefHasUserValue(pref), false, `Pref ${pref} shouldn't get changed`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add_task(function* runInParent() {
|
||||
yield runTest();
|
||||
resetPrefs();
|
||||
});
|
||||
|
||||
if (gMultiProcessBrowser) {
|
||||
add_task(function* runInChild() {
|
||||
ok(gBrowser.selectedBrowser.isRemoteBrowser, "Should actually run this in child process");
|
||||
yield ContentTask.spawn(gBrowser.selectedBrowser, null, runTest);
|
||||
resetPrefs();
|
||||
});
|
||||
}
|
||||
|
|
@ -1,51 +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/. */
|
||||
"use strict";
|
||||
var imported = Components.utils.import("resource://gre/modules/Battery.jsm", this);
|
||||
Cu.import("resource://gre/modules/Services.jsm", this);
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
is(imported.Debugging.fake, false, "Battery spoofing is initially false")
|
||||
|
||||
GetBattery().then(function (battery) {
|
||||
for (let k of ["charging", "chargingTime", "dischargingTime", "level"]) {
|
||||
let backup = battery[k];
|
||||
try {
|
||||
battery[k] = "__magic__";
|
||||
} catch (e) {
|
||||
// We are testing that we cannot set battery to new values
|
||||
// when "use strict" is enabled, this throws a TypeError
|
||||
if (e.name != "TypeError")
|
||||
throw e;
|
||||
}
|
||||
is(battery[k], backup, "Setting battery " + k + " preference without spoofing enabled should fail");
|
||||
}
|
||||
|
||||
imported.Debugging.fake = true;
|
||||
|
||||
// reload again to get the fake one
|
||||
GetBattery().then(function (battery) {
|
||||
battery.charging = true;
|
||||
battery.chargingTime = 100;
|
||||
battery.level = 0.5;
|
||||
ok(battery.charging, "Test for charging setter");
|
||||
is(battery.chargingTime, 100, "Test for chargingTime setter");
|
||||
is(battery.level, 0.5, "Test for level setter");
|
||||
|
||||
battery.charging = false;
|
||||
battery.dischargingTime = 50;
|
||||
battery.level = 0.7;
|
||||
ok(!battery.charging, "Test for charging setter");
|
||||
is(battery.dischargingTime, 50, "Test for dischargingTime setter");
|
||||
is(battery.level, 0.7, "Test for level setter");
|
||||
|
||||
// Resetting the value to make the test run successful
|
||||
// for multiple runs in same browser session.
|
||||
imported.Debugging.fake = false;
|
||||
finish();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -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/. */
|
||||
|
||||
var Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
const PREF_DEPRECATION_WARNINGS = "devtools.errorconsole.deprecation_warnings";
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm", this);
|
||||
Cu.import("resource://gre/modules/Deprecated.jsm", this);
|
||||
|
||||
// Using this named functions to test deprecation and the properly logged
|
||||
// callstacks.
|
||||
function basicDeprecatedFunction () {
|
||||
Deprecated.warning("this method is deprecated.", "http://example.com");
|
||||
return true;
|
||||
}
|
||||
|
||||
function deprecationFunctionBogusCallstack () {
|
||||
Deprecated.warning("this method is deprecated.", "http://example.com", {
|
||||
caller: {}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
function deprecationFunctionCustomCallstack () {
|
||||
// Get the nsIStackFrame that will contain the name of this function.
|
||||
function getStack () {
|
||||
return Components.stack;
|
||||
}
|
||||
Deprecated.warning("this method is deprecated.", "http://example.com",
|
||||
getStack());
|
||||
return true;
|
||||
}
|
||||
|
||||
var tests = [
|
||||
// Test deprecation warning without passing the callstack.
|
||||
{
|
||||
deprecatedFunction: basicDeprecatedFunction,
|
||||
expectedObservation: function (aMessage) {
|
||||
testAMessage(aMessage);
|
||||
ok(aMessage.errorMessage.indexOf("basicDeprecatedFunction") > 0,
|
||||
"Callstack is correctly logged.");
|
||||
}
|
||||
},
|
||||
// Test a reported error when URL to documentation is not passed.
|
||||
{
|
||||
deprecatedFunction: function () {
|
||||
Deprecated.warning("this method is deprecated.");
|
||||
return true;
|
||||
},
|
||||
expectedObservation: function (aMessage) {
|
||||
ok(aMessage.errorMessage.indexOf("must provide a URL") > 0,
|
||||
"Deprecation warning logged an empty URL argument.");
|
||||
}
|
||||
},
|
||||
// Test deprecation with a bogus callstack passed as an argument (it will be
|
||||
// replaced with the current call stack).
|
||||
{
|
||||
deprecatedFunction: deprecationFunctionBogusCallstack,
|
||||
expectedObservation: function (aMessage) {
|
||||
testAMessage(aMessage);
|
||||
ok(aMessage.errorMessage.indexOf("deprecationFunctionBogusCallstack") > 0,
|
||||
"Callstack is correctly logged.");
|
||||
}
|
||||
},
|
||||
// When pref is unset Deprecated.warning should not log anything.
|
||||
{
|
||||
deprecatedFunction: basicDeprecatedFunction,
|
||||
expectedObservation: null,
|
||||
// Set pref to false.
|
||||
logWarnings: false
|
||||
},
|
||||
// Test deprecation with a valid custom callstack passed as an argument.
|
||||
{
|
||||
deprecatedFunction: deprecationFunctionCustomCallstack,
|
||||
expectedObservation: function (aMessage) {
|
||||
testAMessage(aMessage);
|
||||
ok(aMessage.errorMessage.indexOf("deprecationFunctionCustomCallstack") > 0,
|
||||
"Callstack is correctly logged.");
|
||||
},
|
||||
// Set pref to true.
|
||||
logWarnings: true
|
||||
}];
|
||||
|
||||
// Which test are we running now?
|
||||
var idx = -1;
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
// Check if Deprecated is loaded.
|
||||
ok(Deprecated, "Deprecated object exists");
|
||||
|
||||
nextTest();
|
||||
}
|
||||
|
||||
// Test Consle Message attributes.
|
||||
function testAMessage (aMessage) {
|
||||
ok(aMessage.errorMessage.indexOf("DEPRECATION WARNING: " +
|
||||
"this method is deprecated.") === 0,
|
||||
"Deprecation is correctly logged.");
|
||||
ok(aMessage.errorMessage.indexOf("http://example.com") > 0,
|
||||
"URL is correctly logged.");
|
||||
}
|
||||
|
||||
function nextTest() {
|
||||
idx++;
|
||||
|
||||
if (idx == tests.length) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
info("Running test #" + idx);
|
||||
let test = tests[idx];
|
||||
|
||||
// Deprecation warnings will be logged only when the preference is set.
|
||||
if (typeof test.logWarnings !== "undefined") {
|
||||
Services.prefs.setBoolPref(PREF_DEPRECATION_WARNINGS, test.logWarnings);
|
||||
}
|
||||
|
||||
// Create a console listener.
|
||||
let consoleListener = {
|
||||
observe: function (aMessage) {
|
||||
// Ignore unexpected messages.
|
||||
if (!(aMessage instanceof Ci.nsIScriptError)) {
|
||||
return;
|
||||
}
|
||||
if (aMessage.errorMessage.indexOf("DEPRECATION WARNING: ") < 0 &&
|
||||
aMessage.errorMessage.indexOf("must provide a URL") < 0) {
|
||||
return;
|
||||
}
|
||||
ok(aMessage instanceof Ci.nsIScriptError,
|
||||
"Deprecation log message is an instance of type nsIScriptError.");
|
||||
|
||||
|
||||
if (test.expectedObservation === null) {
|
||||
ok(false, "Deprecated warning not expected");
|
||||
}
|
||||
else {
|
||||
test.expectedObservation(aMessage);
|
||||
}
|
||||
|
||||
Services.console.unregisterListener(consoleListener);
|
||||
executeSoon(nextTest);
|
||||
}
|
||||
};
|
||||
Services.console.registerListener(consoleListener);
|
||||
test.deprecatedFunction();
|
||||
if (test.expectedObservation === null) {
|
||||
executeSoon(function() {
|
||||
Services.console.unregisterListener(consoleListener);
|
||||
executeSoon(nextTest);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,62 +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/. */
|
||||
|
||||
var Ci = Components.interfaces;
|
||||
|
||||
add_task(function* () {
|
||||
const url = "data:text/html;base64," +
|
||||
btoa("<body><iframe srcdoc=\"content\"/></iframe>" +
|
||||
"<a href=\"http://test.com\">test link</a>");
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, url);
|
||||
|
||||
let finder = tab.linkedBrowser.finder;
|
||||
let listener = {
|
||||
onFindResult: function () {
|
||||
ok(false, "onFindResult callback wasn't replaced");
|
||||
},
|
||||
onHighlightFinished: function () {
|
||||
ok(false, "onHighlightFinished callback wasn't replaced");
|
||||
}
|
||||
};
|
||||
finder.addResultListener(listener);
|
||||
|
||||
function waitForFind(which = "onFindResult") {
|
||||
return new Promise(resolve => {
|
||||
listener[which] = resolve;
|
||||
})
|
||||
}
|
||||
|
||||
let promiseFind = waitForFind("onHighlightFinished");
|
||||
finder.highlight(true, "content");
|
||||
let findResult = yield promiseFind;
|
||||
Assert.ok(findResult.found, "should find string");
|
||||
|
||||
promiseFind = waitForFind("onHighlightFinished");
|
||||
finder.highlight(true, "Bla");
|
||||
findResult = yield promiseFind;
|
||||
Assert.ok(!findResult.found, "should not find string");
|
||||
|
||||
// Search only for links and draw outlines.
|
||||
promiseFind = waitForFind();
|
||||
finder.fastFind("test link", true, true);
|
||||
findResult = yield promiseFind;
|
||||
is(findResult.result, Ci.nsITypeAheadFind.FIND_FOUND, "should find link");
|
||||
|
||||
yield ContentTask.spawn(tab.linkedBrowser, {}, function* (arg) {
|
||||
Assert.ok(!!content.document.getElementsByTagName("a")[0].style.outline, "outline set");
|
||||
});
|
||||
|
||||
// Just a simple search for "test link".
|
||||
promiseFind = waitForFind();
|
||||
finder.fastFind("test link", false, false);
|
||||
findResult = yield promiseFind;
|
||||
is(findResult.result, Ci.nsITypeAheadFind.FIND_FOUND, "should find link again");
|
||||
|
||||
yield ContentTask.spawn(tab.linkedBrowser, {}, function* (arg) {
|
||||
Assert.ok(!content.document.getElementsByTagName("a")[0].style.outline, "outline not set");
|
||||
});
|
||||
|
||||
finder.removeResultListener(listener);
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
|
|
@ -1,460 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
Cu.import("resource://testing-common/BrowserTestUtils.jsm", this);
|
||||
Cu.import("resource://testing-common/ContentTask.jsm", this);
|
||||
Cu.import("resource://gre/modules/Promise.jsm", this);
|
||||
Cu.import("resource://gre/modules/Services.jsm", this);
|
||||
Cu.import("resource://gre/modules/Task.jsm", this);
|
||||
Cu.import("resource://gre/modules/Timer.jsm", this);
|
||||
Cu.import("resource://gre/modules/AppConstants.jsm");
|
||||
|
||||
const kHighlightAllPref = "findbar.highlightAll";
|
||||
const kPrefModalHighlight = "findbar.modalHighlight";
|
||||
const kFixtureBaseURL = "https://example.com/browser/toolkit/modules/tests/browser/";
|
||||
const kIteratorTimeout = Services.prefs.getIntPref("findbar.iteratorTimeout");
|
||||
|
||||
function promiseOpenFindbar(findbar) {
|
||||
findbar.onFindCommand()
|
||||
return gFindBar._startFindDeferred && gFindBar._startFindDeferred.promise;
|
||||
}
|
||||
|
||||
function promiseFindResult(findbar, str = null) {
|
||||
let highlightFinished = false;
|
||||
let findFinished = false;
|
||||
return new Promise(resolve => {
|
||||
let listener = {
|
||||
onFindResult({ searchString }) {
|
||||
if (str !== null && str != searchString) {
|
||||
return;
|
||||
}
|
||||
findFinished = true;
|
||||
if (highlightFinished) {
|
||||
findbar.browser.finder.removeResultListener(listener);
|
||||
resolve();
|
||||
}
|
||||
},
|
||||
onHighlightFinished() {
|
||||
highlightFinished = true;
|
||||
if (findFinished) {
|
||||
findbar.browser.finder.removeResultListener(listener);
|
||||
resolve();
|
||||
}
|
||||
},
|
||||
onMatchesCountResult: () => {}
|
||||
};
|
||||
findbar.browser.finder.addResultListener(listener);
|
||||
});
|
||||
}
|
||||
|
||||
function promiseEnterStringIntoFindField(findbar, str) {
|
||||
let promise = promiseFindResult(findbar, str);
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
let event = document.createEvent("KeyboardEvent");
|
||||
event.initKeyEvent("keypress", true, true, null, false, false,
|
||||
false, false, 0, str.charCodeAt(i));
|
||||
findbar._findField.inputField.dispatchEvent(event);
|
||||
}
|
||||
return promise;
|
||||
}
|
||||
|
||||
function promiseTestHighlighterOutput(browser, word, expectedResult, extraTest = () => {}) {
|
||||
return ContentTask.spawn(browser, { word, expectedResult, extraTest: extraTest.toSource() },
|
||||
function* ({ word, expectedResult, extraTest }) {
|
||||
Cu.import("resource://gre/modules/Timer.jsm", this);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let stubbed = {};
|
||||
let callCounts = {
|
||||
insertCalls: [],
|
||||
removeCalls: []
|
||||
};
|
||||
let lastMaskNode, lastOutlineNode;
|
||||
let rects = [];
|
||||
|
||||
// Amount of milliseconds to wait after the last time one of our stubs
|
||||
// was called.
|
||||
const kTimeoutMs = 1000;
|
||||
// The initial timeout may wait for a while for results to come in.
|
||||
let timeout = setTimeout(() => finish(false, "Timeout"), kTimeoutMs * 5);
|
||||
|
||||
function finish(ok = true, message = "finished with error") {
|
||||
// Restore the functions we stubbed out.
|
||||
try {
|
||||
content.document.insertAnonymousContent = stubbed.insert;
|
||||
content.document.removeAnonymousContent = stubbed.remove;
|
||||
} catch (ex) {}
|
||||
stubbed = {};
|
||||
clearTimeout(timeout);
|
||||
|
||||
if (expectedResult.rectCount !== 0)
|
||||
Assert.ok(ok, message);
|
||||
|
||||
Assert.greaterOrEqual(callCounts.insertCalls.length, expectedResult.insertCalls[0],
|
||||
`Min. insert calls should match for '${word}'.`);
|
||||
Assert.lessOrEqual(callCounts.insertCalls.length, expectedResult.insertCalls[1],
|
||||
`Max. insert calls should match for '${word}'.`);
|
||||
Assert.greaterOrEqual(callCounts.removeCalls.length, expectedResult.removeCalls[0],
|
||||
`Min. remove calls should match for '${word}'.`);
|
||||
Assert.lessOrEqual(callCounts.removeCalls.length, expectedResult.removeCalls[1],
|
||||
`Max. remove calls should match for '${word}'.`);
|
||||
|
||||
// We reached the amount of calls we expected, so now we can check
|
||||
// the amount of rects.
|
||||
if (!lastMaskNode && expectedResult.rectCount !== 0) {
|
||||
Assert.ok(false, `No mask node found, but expected ${expectedResult.rectCount} rects.`);
|
||||
}
|
||||
|
||||
Assert.equal(rects.length, expectedResult.rectCount,
|
||||
`Amount of inserted rects should match for '${word}'.`);
|
||||
|
||||
// Allow more specific assertions to be tested in `extraTest`.
|
||||
extraTest = eval(extraTest);
|
||||
extraTest(lastMaskNode, lastOutlineNode, rects);
|
||||
|
||||
resolve();
|
||||
}
|
||||
|
||||
function stubAnonymousContentNode(domNode, anonNode) {
|
||||
let originals = [anonNode.setTextContentForElement,
|
||||
anonNode.setAttributeForElement, anonNode.removeAttributeForElement,
|
||||
anonNode.setCutoutRectsForElement];
|
||||
anonNode.setTextContentForElement = (id, text) => {
|
||||
try {
|
||||
(domNode.querySelector("#" + id) || domNode).textContent = text;
|
||||
} catch (ex) {}
|
||||
return originals[0].call(anonNode, id, text);
|
||||
};
|
||||
anonNode.setAttributeForElement = (id, attrName, attrValue) => {
|
||||
try {
|
||||
(domNode.querySelector("#" + id) || domNode).setAttribute(attrName, attrValue);
|
||||
} catch (ex) {}
|
||||
return originals[1].call(anonNode, id, attrName, attrValue);
|
||||
};
|
||||
anonNode.removeAttributeForElement = (id, attrName) => {
|
||||
try {
|
||||
let node = domNode.querySelector("#" + id) || domNode;
|
||||
if (node.hasAttribute(attrName))
|
||||
node.removeAttribute(attrName);
|
||||
} catch (ex) {}
|
||||
return originals[2].call(anonNode, id, attrName);
|
||||
};
|
||||
anonNode.setCutoutRectsForElement = (id, cutoutRects) => {
|
||||
rects = cutoutRects;
|
||||
return originals[3].call(anonNode, id, cutoutRects);
|
||||
};
|
||||
}
|
||||
|
||||
// Create a function that will stub the original version and collects
|
||||
// the arguments so we can check the results later.
|
||||
function stub(which) {
|
||||
stubbed[which] = content.document[which + "AnonymousContent"];
|
||||
let prop = which + "Calls";
|
||||
return function(node) {
|
||||
callCounts[prop].push(node);
|
||||
if (which == "insert") {
|
||||
if (node.outerHTML.indexOf("outlineMask") > -1)
|
||||
lastMaskNode = node;
|
||||
else
|
||||
lastOutlineNode = node;
|
||||
}
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(() => {
|
||||
finish();
|
||||
}, kTimeoutMs);
|
||||
let res = stubbed[which].call(content.document, node);
|
||||
if (which == "insert")
|
||||
stubAnonymousContentNode(node, res);
|
||||
return res;
|
||||
};
|
||||
}
|
||||
content.document.insertAnonymousContent = stub("insert");
|
||||
content.document.removeAnonymousContent = stub("remove");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function* setup() {
|
||||
yield SpecialPowers.pushPrefEnv({ set: [
|
||||
[kHighlightAllPref, true],
|
||||
[kPrefModalHighlight, true]
|
||||
]});
|
||||
});
|
||||
|
||||
// Test the results of modal highlighting, which is on by default.
|
||||
add_task(function* testModalResults() {
|
||||
let tests = new Map([
|
||||
["Roland", {
|
||||
rectCount: 2,
|
||||
insertCalls: [2, 4],
|
||||
removeCalls: [0, 1]
|
||||
}],
|
||||
["their law might propagate their kind", {
|
||||
rectCount: 2,
|
||||
insertCalls: [5, 6],
|
||||
removeCalls: [4, 5],
|
||||
extraTest: function(maskNode, outlineNode, rects) {
|
||||
Assert.equal(outlineNode.getElementsByTagName("div").length, 2,
|
||||
"There should be multiple rects drawn");
|
||||
}
|
||||
}],
|
||||
["ro", {
|
||||
rectCount: 41,
|
||||
insertCalls: [1, 4],
|
||||
removeCalls: [1, 3]
|
||||
}],
|
||||
["new", {
|
||||
rectCount: 2,
|
||||
insertCalls: [1, 4],
|
||||
removeCalls: [0, 2]
|
||||
}],
|
||||
["o", {
|
||||
rectCount: 492,
|
||||
insertCalls: [1, 4],
|
||||
removeCalls: [0, 2]
|
||||
}]
|
||||
]);
|
||||
let url = kFixtureBaseURL + "file_FinderSample.html";
|
||||
yield BrowserTestUtils.withNewTab(url, function* (browser) {
|
||||
let findbar = gBrowser.getFindBar();
|
||||
|
||||
for (let [word, expectedResult] of tests) {
|
||||
yield promiseOpenFindbar(findbar);
|
||||
Assert.ok(!findbar.hidden, "Findbar should be open now.");
|
||||
|
||||
let timeout = kIteratorTimeout;
|
||||
if (word.length == 1)
|
||||
timeout *= 4;
|
||||
else if (word.length == 2)
|
||||
timeout *= 2;
|
||||
yield new Promise(resolve => setTimeout(resolve, timeout));
|
||||
let promise = promiseTestHighlighterOutput(browser, word, expectedResult,
|
||||
expectedResult.extraTest);
|
||||
yield promiseEnterStringIntoFindField(findbar, word);
|
||||
yield promise;
|
||||
|
||||
findbar.close(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Test if runtime switching of highlight modes between modal and non-modal works
|
||||
// as expected.
|
||||
add_task(function* testModalSwitching() {
|
||||
let url = kFixtureBaseURL + "file_FinderSample.html";
|
||||
yield BrowserTestUtils.withNewTab(url, function* (browser) {
|
||||
let findbar = gBrowser.getFindBar();
|
||||
|
||||
yield promiseOpenFindbar(findbar);
|
||||
Assert.ok(!findbar.hidden, "Findbar should be open now.");
|
||||
|
||||
let word = "Roland";
|
||||
let expectedResult = {
|
||||
rectCount: 2,
|
||||
insertCalls: [2, 4],
|
||||
removeCalls: [0, 1]
|
||||
};
|
||||
let promise = promiseTestHighlighterOutput(browser, word, expectedResult);
|
||||
yield promiseEnterStringIntoFindField(findbar, word);
|
||||
yield promise;
|
||||
|
||||
yield SpecialPowers.pushPrefEnv({ "set": [[ kPrefModalHighlight, false ]] });
|
||||
|
||||
expectedResult = {
|
||||
rectCount: 0,
|
||||
insertCalls: [0, 0],
|
||||
removeCalls: [0, 0]
|
||||
};
|
||||
promise = promiseTestHighlighterOutput(browser, word, expectedResult);
|
||||
findbar.clear();
|
||||
yield promiseEnterStringIntoFindField(findbar, word);
|
||||
yield promise;
|
||||
|
||||
findbar.close(true);
|
||||
});
|
||||
|
||||
yield SpecialPowers.pushPrefEnv({ "set": [[ kPrefModalHighlight, true ]] });
|
||||
});
|
||||
|
||||
// Test if highlighting a dark page is detected properly.
|
||||
add_task(function* testDarkPageDetection() {
|
||||
let url = kFixtureBaseURL + "file_FinderSample.html";
|
||||
yield BrowserTestUtils.withNewTab(url, function* (browser) {
|
||||
let findbar = gBrowser.getFindBar();
|
||||
|
||||
yield promiseOpenFindbar(findbar);
|
||||
|
||||
let word = "Roland";
|
||||
let expectedResult = {
|
||||
rectCount: 2,
|
||||
insertCalls: [1, 3],
|
||||
removeCalls: [0, 1]
|
||||
};
|
||||
let promise = promiseTestHighlighterOutput(browser, word, expectedResult, function(node) {
|
||||
Assert.ok(node.style.background.startsWith("rgba(0, 0, 0"),
|
||||
"White HTML page should have a black background color set for the mask");
|
||||
});
|
||||
yield promiseEnterStringIntoFindField(findbar, word);
|
||||
yield promise;
|
||||
|
||||
findbar.close(true);
|
||||
});
|
||||
|
||||
yield BrowserTestUtils.withNewTab(url, function* (browser) {
|
||||
let findbar = gBrowser.getFindBar();
|
||||
|
||||
yield promiseOpenFindbar(findbar);
|
||||
|
||||
let word = "Roland";
|
||||
let expectedResult = {
|
||||
rectCount: 2,
|
||||
insertCalls: [2, 4],
|
||||
removeCalls: [0, 1]
|
||||
};
|
||||
|
||||
yield ContentTask.spawn(browser, null, function* () {
|
||||
let dwu = content.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
let uri = "data:text/css;charset=utf-8," + encodeURIComponent(`
|
||||
body {
|
||||
background: maroon radial-gradient(circle, #a01010 0%, #800000 80%) center center / cover no-repeat;
|
||||
color: white;
|
||||
}`);
|
||||
try {
|
||||
dwu.loadSheetUsingURIString(uri, dwu.USER_SHEET);
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
let promise = promiseTestHighlighterOutput(browser, word, expectedResult, node => {
|
||||
Assert.ok(node.style.background.startsWith("rgba(255, 255, 255"),
|
||||
"Dark HTML page should have a white background color set for the mask");
|
||||
});
|
||||
yield promiseEnterStringIntoFindField(findbar, word);
|
||||
yield promise;
|
||||
|
||||
findbar.close(true);
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* testHighlightAllToggle() {
|
||||
let url = kFixtureBaseURL + "file_FinderSample.html";
|
||||
yield BrowserTestUtils.withNewTab(url, function* (browser) {
|
||||
let findbar = gBrowser.getFindBar();
|
||||
|
||||
yield promiseOpenFindbar(findbar);
|
||||
|
||||
let word = "Roland";
|
||||
let expectedResult = {
|
||||
rectCount: 2,
|
||||
insertCalls: [2, 4],
|
||||
removeCalls: [0, 1]
|
||||
};
|
||||
let promise = promiseTestHighlighterOutput(browser, word, expectedResult);
|
||||
yield promiseEnterStringIntoFindField(findbar, word);
|
||||
yield promise;
|
||||
|
||||
// We now know we have multiple rectangles highlighted, so it's a good time
|
||||
// to flip the pref.
|
||||
expectedResult = {
|
||||
rectCount: 0,
|
||||
insertCalls: [0, 1],
|
||||
removeCalls: [0, 1]
|
||||
};
|
||||
promise = promiseTestHighlighterOutput(browser, word, expectedResult);
|
||||
yield SpecialPowers.pushPrefEnv({ "set": [[ kHighlightAllPref, false ]] });
|
||||
yield promise;
|
||||
|
||||
// For posterity, let's switch back.
|
||||
expectedResult = {
|
||||
rectCount: 2,
|
||||
insertCalls: [1, 3],
|
||||
removeCalls: [0, 1]
|
||||
};
|
||||
promise = promiseTestHighlighterOutput(browser, word, expectedResult);
|
||||
yield SpecialPowers.pushPrefEnv({ "set": [[ kHighlightAllPref, true ]] });
|
||||
yield promise;
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* testXMLDocument() {
|
||||
let url = "data:text/xml;charset=utf-8," + encodeURIComponent(`<?xml version="1.0"?>
|
||||
<result>
|
||||
<Title>Example</Title>
|
||||
<Error>Error</Error>
|
||||
</result>`);
|
||||
yield BrowserTestUtils.withNewTab(url, function* (browser) {
|
||||
let findbar = gBrowser.getFindBar();
|
||||
|
||||
yield promiseOpenFindbar(findbar);
|
||||
|
||||
let word = "Example";
|
||||
let expectedResult = {
|
||||
rectCount: 0,
|
||||
insertCalls: [1, 4],
|
||||
removeCalls: [0, 1]
|
||||
};
|
||||
let promise = promiseTestHighlighterOutput(browser, word, expectedResult);
|
||||
yield promiseEnterStringIntoFindField(findbar, word);
|
||||
yield promise;
|
||||
|
||||
findbar.close(true);
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* testHideOnLocationChange() {
|
||||
let url = kFixtureBaseURL + "file_FinderSample.html";
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, url);
|
||||
let browser = tab.linkedBrowser;
|
||||
let findbar = gBrowser.getFindBar();
|
||||
|
||||
yield promiseOpenFindbar(findbar);
|
||||
|
||||
let word = "Roland";
|
||||
let expectedResult = {
|
||||
rectCount: 2,
|
||||
insertCalls: [2, 4],
|
||||
removeCalls: [0, 1]
|
||||
};
|
||||
let promise = promiseTestHighlighterOutput(browser, word, expectedResult);
|
||||
yield promiseEnterStringIntoFindField(findbar, word);
|
||||
yield promise;
|
||||
|
||||
// Now we try to navigate away! (Using the same page)
|
||||
promise = promiseTestHighlighterOutput(browser, word, {
|
||||
rectCount: 0,
|
||||
insertCalls: [0, 0],
|
||||
removeCalls: [1, 2]
|
||||
});
|
||||
yield BrowserTestUtils.loadURI(browser, url);
|
||||
yield promise;
|
||||
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
add_task(function* testHideOnClear() {
|
||||
let url = kFixtureBaseURL + "file_FinderSample.html";
|
||||
yield BrowserTestUtils.withNewTab(url, function* (browser) {
|
||||
let findbar = gBrowser.getFindBar();
|
||||
yield promiseOpenFindbar(findbar);
|
||||
|
||||
let word = "Roland";
|
||||
let expectedResult = {
|
||||
rectCount: 2,
|
||||
insertCalls: [2, 4],
|
||||
removeCalls: [0, 2]
|
||||
};
|
||||
let promise = promiseTestHighlighterOutput(browser, word, expectedResult);
|
||||
yield promiseEnterStringIntoFindField(findbar, word);
|
||||
yield promise;
|
||||
|
||||
yield new Promise(resolve => setTimeout(resolve, kIteratorTimeout));
|
||||
promise = promiseTestHighlighterOutput(browser, "", {
|
||||
rectCount: 0,
|
||||
insertCalls: [0, 0],
|
||||
removeCalls: [1, 2]
|
||||
});
|
||||
findbar.clear();
|
||||
yield promise;
|
||||
|
||||
findbar.close(true);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,52 +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/. */
|
||||
add_task(function* test_bug1174036() {
|
||||
const URI =
|
||||
"<body><textarea>e1</textarea><textarea>e2</textarea><textarea>e3</textarea></body>";
|
||||
yield BrowserTestUtils.withNewTab({ gBrowser, url: "data:text/html;charset=utf-8," + encodeURIComponent(URI) },
|
||||
function* (browser) {
|
||||
// Hide the first textarea.
|
||||
yield ContentTask.spawn(browser, null, function() {
|
||||
content.document.getElementsByTagName("textarea")[0].style.display = "none";
|
||||
});
|
||||
|
||||
let finder = browser.finder;
|
||||
let listener = {
|
||||
onFindResult: function () {
|
||||
ok(false, "callback wasn't replaced");
|
||||
}
|
||||
};
|
||||
finder.addResultListener(listener);
|
||||
|
||||
function waitForFind() {
|
||||
return new Promise(resolve => {
|
||||
listener.onFindResult = resolve;
|
||||
})
|
||||
}
|
||||
|
||||
// Find the first 'e' (which should be in the second textarea).
|
||||
let promiseFind = waitForFind();
|
||||
finder.fastFind("e", false, false);
|
||||
let findResult = yield promiseFind;
|
||||
is(findResult.result, Ci.nsITypeAheadFind.FIND_FOUND, "find first string");
|
||||
|
||||
let firstRect = findResult.rect;
|
||||
|
||||
// Find the second 'e' (in the third textarea).
|
||||
promiseFind = waitForFind();
|
||||
finder.findAgain(false, false, false);
|
||||
findResult = yield promiseFind;
|
||||
is(findResult.result, Ci.nsITypeAheadFind.FIND_FOUND, "find second string");
|
||||
ok(!findResult.rect.equals(firstRect), "found new string");
|
||||
|
||||
// Ensure that we properly wrap to the second textarea.
|
||||
promiseFind = waitForFind();
|
||||
finder.findAgain(false, false, false);
|
||||
findResult = yield promiseFind;
|
||||
is(findResult.result, Ci.nsITypeAheadFind.FIND_WRAPPED, "wrapped to first string");
|
||||
ok(findResult.rect.equals(firstRect), "wrapped to original string");
|
||||
|
||||
finder.removeResultListener(listener);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,111 +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/. */
|
||||
|
||||
var tempScope = {};
|
||||
Components.utils.import("resource://gre/modules/Geometry.jsm", tempScope);
|
||||
var Point = tempScope.Point;
|
||||
var Rect = tempScope.Rect;
|
||||
|
||||
function test() {
|
||||
ok(Rect, "Rect class exists");
|
||||
for (var fname in tests) {
|
||||
tests[fname]();
|
||||
}
|
||||
}
|
||||
|
||||
var tests = {
|
||||
testGetDimensions: function() {
|
||||
let r = new Rect(5, 10, 100, 50);
|
||||
ok(r.left == 5, "rect has correct left value");
|
||||
ok(r.top == 10, "rect has correct top value");
|
||||
ok(r.right == 105, "rect has correct right value");
|
||||
ok(r.bottom == 60, "rect has correct bottom value");
|
||||
ok(r.width == 100, "rect has correct width value");
|
||||
ok(r.height == 50, "rect has correct height value");
|
||||
ok(r.x == 5, "rect has correct x value");
|
||||
ok(r.y == 10, "rect has correct y value");
|
||||
},
|
||||
|
||||
testIsEmpty: function() {
|
||||
let r = new Rect(0, 0, 0, 10);
|
||||
ok(r.isEmpty(), "rect with nonpositive width is empty");
|
||||
r = new Rect(0, 0, 10, 0);
|
||||
ok(r.isEmpty(), "rect with nonpositive height is empty");
|
||||
r = new Rect(0, 0, 10, 10);
|
||||
ok(!r.isEmpty(), "rect with positive dimensions is not empty");
|
||||
},
|
||||
|
||||
testRestrictTo: function() {
|
||||
let r1 = new Rect(10, 10, 100, 100);
|
||||
let r2 = new Rect(50, 50, 100, 100);
|
||||
r1.restrictTo(r2);
|
||||
ok(r1.equals(new Rect(50, 50, 60, 60)), "intersection is non-empty");
|
||||
|
||||
r1 = new Rect(10, 10, 100, 100);
|
||||
r2 = new Rect(120, 120, 100, 100);
|
||||
r1.restrictTo(r2);
|
||||
ok(r1.isEmpty(), "intersection is empty");
|
||||
|
||||
r1 = new Rect(10, 10, 100, 100);
|
||||
r2 = new Rect(0, 0, 0, 0);
|
||||
r1.restrictTo(r2);
|
||||
ok(r1.isEmpty(), "intersection of rect and empty is empty");
|
||||
|
||||
r1 = new Rect(0, 0, 0, 0);
|
||||
r2 = new Rect(0, 0, 0, 0);
|
||||
r1.restrictTo(r2);
|
||||
ok(r1.isEmpty(), "intersection of empty and empty is empty");
|
||||
},
|
||||
|
||||
testExpandToContain: function() {
|
||||
let r1 = new Rect(10, 10, 100, 100);
|
||||
let r2 = new Rect(50, 50, 100, 100);
|
||||
r1.expandToContain(r2);
|
||||
ok(r1.equals(new Rect(10, 10, 140, 140)), "correct expandToContain on intersecting rectangles");
|
||||
|
||||
r1 = new Rect(10, 10, 100, 100);
|
||||
r2 = new Rect(120, 120, 100, 100);
|
||||
r1.expandToContain(r2);
|
||||
ok(r1.equals(new Rect(10, 10, 210, 210)), "correct expandToContain on non-intersecting rectangles");
|
||||
|
||||
r1 = new Rect(10, 10, 100, 100);
|
||||
r2 = new Rect(0, 0, 0, 0);
|
||||
r1.expandToContain(r2);
|
||||
ok(r1.equals(new Rect(10, 10, 100, 100)), "expandToContain of rect and empty is rect");
|
||||
|
||||
r1 = new Rect(10, 10, 0, 0);
|
||||
r2 = new Rect(0, 0, 0, 0);
|
||||
r1.expandToContain(r2);
|
||||
ok(r1.isEmpty(), "expandToContain of empty and empty is empty");
|
||||
},
|
||||
|
||||
testSubtract: function testSubtract() {
|
||||
function equals(rects1, rects2) {
|
||||
return rects1.length == rects2.length && rects1.every(function(r, i) {
|
||||
return r.equals(rects2[i]);
|
||||
});
|
||||
}
|
||||
|
||||
let r1 = new Rect(0, 0, 100, 100);
|
||||
let r2 = new Rect(500, 500, 100, 100);
|
||||
ok(equals(r1.subtract(r2), [r1]), "subtract area outside of region yields same region");
|
||||
|
||||
r1 = new Rect(0, 0, 100, 100);
|
||||
r2 = new Rect(-10, -10, 50, 120);
|
||||
ok(equals(r1.subtract(r2), [new Rect(40, 0, 60, 100)]), "subtracting vertical bar from edge leaves one rect");
|
||||
|
||||
r1 = new Rect(0, 0, 100, 100);
|
||||
r2 = new Rect(-10, -10, 120, 50);
|
||||
ok(equals(r1.subtract(r2), [new Rect(0, 40, 100, 60)]), "subtracting horizontal bar from edge leaves one rect");
|
||||
|
||||
r1 = new Rect(0, 0, 100, 100);
|
||||
r2 = new Rect(40, 40, 20, 20);
|
||||
ok(equals(r1.subtract(r2), [
|
||||
new Rect(0, 0, 40, 100),
|
||||
new Rect(40, 0, 20, 40),
|
||||
new Rect(40, 60, 20, 40),
|
||||
new Rect(60, 0, 40, 100)]),
|
||||
"subtracting rect in middle leaves union of rects");
|
||||
},
|
||||
};
|
||||
|
|
@ -1,121 +0,0 @@
|
|||
function test() {
|
||||
let tempScope = {};
|
||||
Components.utils.import("resource://gre/modules/InlineSpellChecker.jsm", tempScope);
|
||||
let InlineSpellChecker = tempScope.InlineSpellChecker;
|
||||
|
||||
ok(InlineSpellChecker, "InlineSpellChecker class exists");
|
||||
for (var fname in tests) {
|
||||
tests[fname]();
|
||||
}
|
||||
}
|
||||
|
||||
var tests = {
|
||||
// Test various possible dictionary name to ensure they display as expected.
|
||||
// XXX: This only works for the 'en-US' locale, as the testing involves localized output.
|
||||
testDictionaryDisplayNames: function() {
|
||||
let isc = new InlineSpellChecker();
|
||||
|
||||
// Check non-well-formed language tag.
|
||||
is(isc.getDictionaryDisplayName("-invalid-"), "-invalid-", "'-invalid-' should display as '-invalid-'");
|
||||
|
||||
// XXX: It isn't clear how we'd ideally want to display variant subtags.
|
||||
|
||||
// Check valid language subtag.
|
||||
is(isc.getDictionaryDisplayName("en"), "English", "'en' should display as 'English'");
|
||||
is(isc.getDictionaryDisplayName("en-fonipa"), "English (fonipa)", "'en-fonipa' should display as 'English (fonipa)'");
|
||||
is(isc.getDictionaryDisplayName("en-qxqaaaaz"), "English (qxqaaaaz)", "'en-qxqaaaaz' should display as 'English (qxqaaaaz)'");
|
||||
|
||||
// Check valid language subtag and valid region subtag.
|
||||
is(isc.getDictionaryDisplayName("en-US"), "English (United States)", "'en-US' should display as 'English (United States)'");
|
||||
is(isc.getDictionaryDisplayName("en-US-fonipa"), "English (United States) (fonipa)", "'en-US-fonipa' should display as 'English (United States) (fonipa)'");
|
||||
is(isc.getDictionaryDisplayName("en-US-qxqaaaaz"), "English (United States) (qxqaaaaz)", "'en-US-qxqaaaaz' should display as 'English (United States) (qxqaaaaz)'");
|
||||
|
||||
// Check valid language subtag and invalid but well-formed region subtag.
|
||||
is(isc.getDictionaryDisplayName("en-WO"), "English (WO)", "'en-WO' should display as 'English (WO)'");
|
||||
is(isc.getDictionaryDisplayName("en-WO-fonipa"), "English (WO) (fonipa)", "'en-WO-fonipa' should display as 'English (WO) (fonipa)'");
|
||||
is(isc.getDictionaryDisplayName("en-WO-qxqaaaaz"), "English (WO) (qxqaaaaz)", "'en-WO-qxqaaaaz' should display as 'English (WO) (qxqaaaaz)'");
|
||||
|
||||
// Check valid language subtag and valid script subtag.
|
||||
todo_is(isc.getDictionaryDisplayName("en-Cyrl"), "English / Cyrillic", "'en-Cyrl' should display as 'English / Cyrillic'");
|
||||
todo_is(isc.getDictionaryDisplayName("en-Cyrl-fonipa"), "English / Cyrillic (fonipa)", "'en-Cyrl-fonipa' should display as 'English / Cyrillic (fonipa)'");
|
||||
todo_is(isc.getDictionaryDisplayName("en-Cyrl-qxqaaaaz"), "English / Cyrillic (qxqaaaaz)", "'en-Cyrl-qxqaaaaz' should display as 'English / Cyrillic (qxqaaaaz)'");
|
||||
todo_is(isc.getDictionaryDisplayName("en-Cyrl-US"), "English (United States) / Cyrillic", "'en-Cyrl-US' should display as 'English (United States) / Cyrillic'");
|
||||
todo_is(isc.getDictionaryDisplayName("en-Cyrl-US-fonipa"), "English (United States) / Cyrillic (fonipa)", "'en-Cyrl-US-fonipa' should display as 'English (United States) / Cyrillic (fonipa)'");
|
||||
todo_is(isc.getDictionaryDisplayName("en-Cyrl-US-qxqaaaaz"), "English (United States) / Cyrillic (qxqaaaaz)", "'en-Cyrl-US-qxqaaaaz' should display as 'English (United States) / Cyrillic (qxqaaaaz)'");
|
||||
todo_is(isc.getDictionaryDisplayName("en-Cyrl-WO"), "English (WO) / Cyrillic", "'en-Cyrl-WO' should display as 'English (WO) / Cyrillic'");
|
||||
todo_is(isc.getDictionaryDisplayName("en-Cyrl-WO-fonipa"), "English (WO) / Cyrillic (fonipa)", "'en-Cyrl-WO-fonipa' should display as 'English (WO) / Cyrillic (fonipa)'");
|
||||
todo_is(isc.getDictionaryDisplayName("en-Cyrl-WO-qxqaaaaz"), "English (WO) / Cyrillic (qxqaaaaz)", "'en-Cyrl-WO-qxqaaaaz' should display as 'English (WO) / Cyrillic (qxqaaaaz)'");
|
||||
|
||||
// Check valid language subtag and invalid but well-formed script subtag.
|
||||
is(isc.getDictionaryDisplayName("en-Qaaz"), "English / Qaaz", "'en-Qaaz' should display as 'English / Qaaz'");
|
||||
is(isc.getDictionaryDisplayName("en-Qaaz-fonipa"), "English / Qaaz (fonipa)", "'en-Qaaz-fonipa' should display as 'English / Qaaz (fonipa)'");
|
||||
is(isc.getDictionaryDisplayName("en-Qaaz-qxqaaaaz"), "English / Qaaz (qxqaaaaz)", "'en-Qaaz-qxqaaaaz' should display as 'English / Qaaz (qxqaaaaz)'");
|
||||
is(isc.getDictionaryDisplayName("en-Qaaz-US"), "English (United States) / Qaaz", "'en-Qaaz-US' should display as 'English (United States) / Qaaz'");
|
||||
is(isc.getDictionaryDisplayName("en-Qaaz-US-fonipa"), "English (United States) / Qaaz (fonipa)", "'en-Qaaz-US-fonipa' should display as 'English (United States) / Qaaz (fonipa)'");
|
||||
is(isc.getDictionaryDisplayName("en-Qaaz-US-qxqaaaaz"), "English (United States) / Qaaz (qxqaaaaz)", "'en-Qaaz-US-qxqaaaaz' should display as 'English (United States) / Qaaz (qxqaaaaz)'");
|
||||
is(isc.getDictionaryDisplayName("en-Qaaz-WO"), "English (WO) / Qaaz", "'en-Qaaz-WO' should display as 'English (WO) / Qaaz'");
|
||||
is(isc.getDictionaryDisplayName("en-Qaaz-WO-fonipa"), "English (WO) / Qaaz (fonipa)", "'en-Qaaz-WO-fonipa' should display as 'English (WO) / Qaaz (fonipa)'");
|
||||
is(isc.getDictionaryDisplayName("en-Qaaz-WO-qxqaaaaz"), "English (WO) / Qaaz (qxqaaaaz)", "'en-Qaaz-WO-qxqaaaaz' should display as 'English (WO) / Qaaz (qxqaaaaz)'");
|
||||
|
||||
// Check invalid but well-formed language subtag.
|
||||
is(isc.getDictionaryDisplayName("qaz"), "qaz", "'qaz' should display as 'qaz'");
|
||||
is(isc.getDictionaryDisplayName("qaz-fonipa"), "qaz (fonipa)", "'qaz-fonipa' should display as 'qaz (fonipa)'");
|
||||
is(isc.getDictionaryDisplayName("qaz-qxqaaaaz"), "qaz (qxqaaaaz)", "'qaz-qxqaaaaz' should display as 'qaz (qxqaaaaz)'");
|
||||
|
||||
// Check invalid but well-formed language subtag and valid region subtag.
|
||||
is(isc.getDictionaryDisplayName("qaz-US"), "qaz (United States)", "'qaz-US' should display as 'qaz (United States)'");
|
||||
is(isc.getDictionaryDisplayName("qaz-US-fonipa"), "qaz (United States) (fonipa)", "'qaz-US-fonipa' should display as 'qaz (United States) (fonipa)'");
|
||||
is(isc.getDictionaryDisplayName("qaz-US-qxqaaaaz"), "qaz (United States) (qxqaaaaz)", "'qaz-US-qxqaaaaz' should display as 'qaz (United States) (qxqaaaaz)'");
|
||||
|
||||
// Check invalid but well-formed language subtag and invalid but well-formed region subtag.
|
||||
is(isc.getDictionaryDisplayName("qaz-WO"), "qaz (WO)", "'qaz-WO' should display as 'qaz (WO)'");
|
||||
is(isc.getDictionaryDisplayName("qaz-WO-fonipa"), "qaz (WO) (fonipa)", "'qaz-WO-fonipa' should display as 'qaz (WO) (fonipa)'");
|
||||
is(isc.getDictionaryDisplayName("qaz-WO-qxqaaaaz"), "qaz (WO) (qxqaaaaz)", "'qaz-WO-qxqaaaaz' should display as 'qaz (WO) (qxqaaaaz)'");
|
||||
|
||||
// Check invalid but well-formed language subtag and valid script subtag.
|
||||
todo_is(isc.getDictionaryDisplayName("qaz-Cyrl"), "qaz / Cyrillic", "'qaz-Cyrl' should display as 'qaz / Cyrillic'");
|
||||
todo_is(isc.getDictionaryDisplayName("qaz-Cyrl-fonipa"), "qaz / Cyrillic (fonipa)", "'qaz-Cyrl-fonipa' should display as 'qaz / Cyrillic (fonipa)'");
|
||||
todo_is(isc.getDictionaryDisplayName("qaz-Cyrl-qxqaaaaz"), "qaz / Cyrillic (qxqaaaaz)", "'qaz-Cyrl-qxqaaaaz' should display as 'qaz / Cyrillic (qxqaaaaz)'");
|
||||
todo_is(isc.getDictionaryDisplayName("qaz-Cyrl-US"), "qaz (United States) / Cyrillic", "'qaz-Cyrl-US' should display as 'qaz (United States) / Cyrillic'");
|
||||
todo_is(isc.getDictionaryDisplayName("qaz-Cyrl-US-fonipa"), "qaz (United States) / Cyrillic (fonipa)", "'qaz-Cyrl-US-fonipa' should display as 'qaz (United States) / Cyrillic (fonipa)'");
|
||||
todo_is(isc.getDictionaryDisplayName("qaz-Cyrl-US-qxqaaaaz"), "qaz (United States) / Cyrillic (qxqaaaaz)", "'qaz-Cyrl-US-qxqaaaaz' should display as 'qaz (United States) / Cyrillic (qxqaaaaz)'");
|
||||
todo_is(isc.getDictionaryDisplayName("qaz-Cyrl-WO"), "qaz (WO) / Cyrillic", "'qaz-Cyrl-WO' should display as 'qaz (WO) / Cyrillic'");
|
||||
todo_is(isc.getDictionaryDisplayName("qaz-Cyrl-WO-fonipa"), "qaz (WO) / Cyrillic (fonipa)", "'qaz-Cyrl-WO-fonipa' should display as 'qaz (WO) / Cyrillic (fonipa)'");
|
||||
todo_is(isc.getDictionaryDisplayName("qaz-Cyrl-WO-qxqaaaaz"), "qaz (WO) / Cyrillic (qxqaaaaz)", "'qaz-Cyrl-WO-qxqaaaaz' should display as 'qaz (WO) / Cyrillic (qxqaaaaz)'");
|
||||
|
||||
// Check invalid but well-formed language subtag and invalid but well-formed script subtag.
|
||||
is(isc.getDictionaryDisplayName("qaz-Qaaz"), "qaz / Qaaz", "'qaz-Qaaz' should display as 'qaz / Qaaz'");
|
||||
is(isc.getDictionaryDisplayName("qaz-Qaaz-fonipa"), "qaz / Qaaz (fonipa)", "'qaz-Qaaz-fonipa' should display as 'qaz / Qaaz (fonipa)'");
|
||||
is(isc.getDictionaryDisplayName("qaz-Qaaz-qxqaaaaz"), "qaz / Qaaz (qxqaaaaz)", "'qaz-Qaaz-qxqaaaaz' should display as 'qaz / Qaaz (qxqaaaaz)'");
|
||||
is(isc.getDictionaryDisplayName("qaz-Qaaz-US"), "qaz (United States) / Qaaz", "'qaz-Qaaz-US' should display as 'qaz (United States) / Qaaz'");
|
||||
is(isc.getDictionaryDisplayName("qaz-Qaaz-US-fonipa"), "qaz (United States) / Qaaz (fonipa)", "'qaz-Qaaz-US-fonipa' should display as 'qaz (United States) / Qaaz (fonipa)'");
|
||||
is(isc.getDictionaryDisplayName("qaz-Qaaz-US-qxqaaaaz"), "qaz (United States) / Qaaz (qxqaaaaz)", "'qaz-Qaaz-US-qxqaaaaz' should display as 'qaz (United States) / Qaaz (qxqaaaaz)'");
|
||||
is(isc.getDictionaryDisplayName("qaz-Qaaz-WO"), "qaz (WO) / Qaaz", "'qaz-Qaaz-WO' should display as 'qaz (WO) / Qaaz'");
|
||||
is(isc.getDictionaryDisplayName("qaz-Qaaz-WO-fonipa"), "qaz (WO) / Qaaz (fonipa)", "'qaz-Qaaz-WO-fonipa' should display as 'qaz (WO) / Qaaz (fonipa)'");
|
||||
is(isc.getDictionaryDisplayName("qaz-Qaaz-WO-qxqaaaaz"), "qaz (WO) / Qaaz (qxqaaaaz)", "'qaz-Qaaz-WO-qxqaaaaz' should display as 'qaz (WO) / Qaaz (qxqaaaaz)'");
|
||||
|
||||
// Check multiple variant subtags.
|
||||
todo_is(isc.getDictionaryDisplayName("en-Cyrl-US-fonipa-fonxsamp"), "English (United States) / Cyrillic (fonipa / fonxsamp)", "'en-Cyrl-US-fonipa-fonxsamp' should display as 'English (United States) / Cyrillic (fonipa / fonxsamp)'");
|
||||
todo_is(isc.getDictionaryDisplayName("en-Cyrl-US-fonipa-qxqaaaaz"), "English (United States) / Cyrillic (fonipa / qxqaaaaz)", "'en-Cyrl-US-fonipa-qxqaaaaz' should display as 'English (United States) / Cyrillic (fonipa / qxqaaaaz)'");
|
||||
todo_is(isc.getDictionaryDisplayName("en-Cyrl-US-fonipa-fonxsamp-qxqaaaaz"), "English (United States) / Cyrillic (fonipa / fonxsamp / qxqaaaaz)", "'en-Cyrl-US-fonipa-fonxsamp-qxqaaaaz' should display as 'English (United States) / Cyrillic (fonipa / fonxsamp / qxqaaaaz)'");
|
||||
is(isc.getDictionaryDisplayName("qaz-Qaaz-WO-fonipa-fonxsamp"), "qaz (WO) / Qaaz (fonipa / fonxsamp)", "'qaz-Qaaz-WO-fonipa-fonxsamp' should display as 'qaz (WO) / Qaaz (fonipa / fonxsamp)'");
|
||||
is(isc.getDictionaryDisplayName("qaz-Qaaz-WO-fonipa-qxqaaaaz"), "qaz (WO) / Qaaz (fonipa / qxqaaaaz)", "'qaz-Qaaz-WO-fonipa-qxqaaaaz' should display as 'qaz (WO) / Qaaz (fonipa / qxqaaaaz)'");
|
||||
is(isc.getDictionaryDisplayName("qaz-Qaaz-WO-fonipa-fonxsamp-qxqaaaaz"), "qaz (WO) / Qaaz (fonipa / fonxsamp / qxqaaaaz)", "'qaz-Qaaz-WO-fonipa-fonxsamp-qxqaaaaz' should display as 'qaz (WO) / Qaaz (fonipa / fonxsamp / qxqaaaaz)'");
|
||||
|
||||
// Check numeric region subtag.
|
||||
todo_is(isc.getDictionaryDisplayName("es-419"), "Spanish (Latin America and the Caribbean)", "'es-419' should display as 'Spanish (Latin America and the Caribbean)'");
|
||||
|
||||
// Check that extension subtags are ignored.
|
||||
todo_is(isc.getDictionaryDisplayName("en-Cyrl-t-en-latn-m0-ungegn-2007"), "English / Cyrillic", "'en-Cyrl-t-en-latn-m0-ungegn-2007' should display as 'English / Cyrillic'");
|
||||
|
||||
// Check that privateuse subtags are ignored.
|
||||
is(isc.getDictionaryDisplayName("en-x-ignore"), "English", "'en-x-ignore' should display as 'English'");
|
||||
is(isc.getDictionaryDisplayName("en-x-ignore-this"), "English", "'en-x-ignore-this' should display as 'English'");
|
||||
is(isc.getDictionaryDisplayName("en-x-ignore-this-subtag"), "English", "'en-x-ignore-this-subtag' should display as 'English'");
|
||||
|
||||
// Check that both extension and privateuse subtags are ignored.
|
||||
todo_is(isc.getDictionaryDisplayName("en-Cyrl-t-en-latn-m0-ungegn-2007-x-ignore-this-subtag"), "English / Cyrillic", "'en-Cyrl-t-en-latn-m0-ungegn-2007-x-ignore-this-subtag' should display as 'English / Cyrillic'");
|
||||
|
||||
// XXX: Check grandfathered tags.
|
||||
},
|
||||
};
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
/**
|
||||
* Tests PageMetadata.jsm, which extracts metadata and microdata from a
|
||||
* document.
|
||||
*/
|
||||
|
||||
var {PageMetadata} = Cu.import("resource://gre/modules/PageMetadata.jsm", {});
|
||||
|
||||
var rootURL = "http://example.com/browser/toolkit/modules/tests/browser/";
|
||||
|
||||
function promiseDocument(fileName) {
|
||||
let url = rootURL + fileName;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.onload = () => resolve(xhr.responseXML);
|
||||
xhr.onerror = () => reject(new Error("Error loading document"));
|
||||
xhr.open("GET", url);
|
||||
xhr.responseType = "document";
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a simple document.
|
||||
*/
|
||||
add_task(function* simpleDoc() {
|
||||
let fileName = "metadata_simple.html";
|
||||
info(`Loading a simple page, ${fileName}`);
|
||||
|
||||
let doc = yield promiseDocument(fileName);
|
||||
Assert.notEqual(doc, null,
|
||||
"Should have a document to analyse");
|
||||
|
||||
let data = PageMetadata.getData(doc);
|
||||
Assert.notEqual(data, null,
|
||||
"Should have non-null result");
|
||||
Assert.equal(data.url, rootURL + fileName,
|
||||
"Should have expected url property");
|
||||
Assert.equal(data.title, "Test Title",
|
||||
"Should have expected title property");
|
||||
Assert.equal(data.description, "A very simple test page",
|
||||
"Should have expected title property");
|
||||
});
|
||||
|
||||
add_task(function* titlesDoc() {
|
||||
let fileName = "metadata_titles.html";
|
||||
info(`Loading titles page, ${fileName}`);
|
||||
|
||||
let doc = yield promiseDocument(fileName);
|
||||
Assert.notEqual(doc, null,
|
||||
"Should have a document to analyse");
|
||||
|
||||
let data = PageMetadata.getData(doc);
|
||||
Assert.notEqual(data, null,
|
||||
"Should have non-null result");
|
||||
Assert.equal(data.title, "Test Titles",
|
||||
"Should use the page title, not the open graph title");
|
||||
});
|
||||
|
||||
add_task(function* titlesFallbackDoc() {
|
||||
let fileName = "metadata_titles_fallback.html";
|
||||
info(`Loading titles page, ${fileName}`);
|
||||
|
||||
let doc = yield promiseDocument(fileName);
|
||||
Assert.notEqual(doc, null,
|
||||
"Should have a document to analyse");
|
||||
|
||||
let data = PageMetadata.getData(doc);
|
||||
Assert.notEqual(data, null,
|
||||
"Should have non-null result");
|
||||
Assert.equal(data.title, "Title",
|
||||
"Should use the open graph title");
|
||||
});
|
||||
|
|
@ -1,38 +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/. */
|
||||
/* global Cu, BrowserTestUtils, is, ok, add_task, gBrowser */
|
||||
"use strict";
|
||||
Cu.import("resource://gre/modules/PromiseMessage.jsm", this);
|
||||
|
||||
|
||||
const url = "http://example.org/tests/dom/manifest/test/resource.sjs";
|
||||
|
||||
/**
|
||||
* Test basic API error conditions
|
||||
*/
|
||||
add_task(function* () {
|
||||
yield BrowserTestUtils.withNewTab({gBrowser, url}, testPromiseMessageAPI)
|
||||
});
|
||||
|
||||
function* testPromiseMessageAPI(aBrowser) {
|
||||
// Reusing an existing message.
|
||||
const msgKey = "DOM:WebManifest:hasManifestLink";
|
||||
const mm = aBrowser.messageManager;
|
||||
const id = "this should not change";
|
||||
const foo = "neitherShouldThis";
|
||||
const data = {id, foo};
|
||||
|
||||
// This just returns false, and it doesn't matter for this test.
|
||||
yield PromiseMessage.send(mm, msgKey, data);
|
||||
|
||||
// Check that no new props were added
|
||||
const props = Object.getOwnPropertyNames(data);
|
||||
ok(props.length === 2, "There should only be 2 props");
|
||||
ok(props.includes("id"), "Has the id property");
|
||||
ok(props.includes("foo"), "Has the foo property");
|
||||
|
||||
// Check that the props didn't change.
|
||||
is(data.id, id, "The id prop must not change.");
|
||||
is(data.foo, foo, "The foo prop must not change.");
|
||||
}
|
||||
|
|
@ -1,400 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
const TEST_URL = "http://www.example.com/browser/toolkit/modules/tests/browser/testremotepagemanager.html";
|
||||
|
||||
var { RemotePages, RemotePageManager } = Cu.import("resource://gre/modules/RemotePageManager.jsm", {});
|
||||
|
||||
function failOnMessage(message) {
|
||||
ok(false, "Should not have seen message " + message.name);
|
||||
}
|
||||
|
||||
function waitForMessage(port, message, expectedPort = port) {
|
||||
return new Promise((resolve) => {
|
||||
function listener(message) {
|
||||
is(message.target, expectedPort, "Message should be from the right port.");
|
||||
|
||||
port.removeMessageListener(listener);
|
||||
resolve(message);
|
||||
}
|
||||
|
||||
port.addMessageListener(message, listener);
|
||||
});
|
||||
}
|
||||
|
||||
function waitForPort(url, createTab = true) {
|
||||
return new Promise((resolve) => {
|
||||
RemotePageManager.addRemotePageListener(url, (port) => {
|
||||
RemotePageManager.removeRemotePageListener(url);
|
||||
|
||||
waitForMessage(port, "RemotePage:Load").then(() => resolve(port));
|
||||
});
|
||||
|
||||
if (createTab)
|
||||
gBrowser.selectedTab = gBrowser.addTab(url);
|
||||
});
|
||||
}
|
||||
|
||||
function waitForPage(pages) {
|
||||
return new Promise((resolve) => {
|
||||
function listener({ target }) {
|
||||
pages.removeMessageListener("RemotePage:Init", listener);
|
||||
|
||||
waitForMessage(target, "RemotePage:Load").then(() => resolve(target));
|
||||
}
|
||||
|
||||
pages.addMessageListener("RemotePage:Init", listener);
|
||||
gBrowser.selectedTab = gBrowser.addTab(TEST_URL);
|
||||
});
|
||||
}
|
||||
|
||||
function swapDocShells(browser1, browser2) {
|
||||
// Swap frameLoaders.
|
||||
browser1.swapDocShells(browser2);
|
||||
|
||||
// Swap permanentKeys.
|
||||
let tmp = browser1.permanentKey;
|
||||
browser1.permanentKey = browser2.permanentKey;
|
||||
browser2.permanentKey = tmp;
|
||||
}
|
||||
|
||||
// Test that opening a page creates a port, sends the load event and then
|
||||
// navigating to a new page sends the unload event. Going back should create a
|
||||
// new port
|
||||
add_task(function* init_navigate() {
|
||||
let port = yield waitForPort(TEST_URL);
|
||||
is(port.browser, gBrowser.selectedBrowser, "Port is for the correct browser");
|
||||
|
||||
let loaded = new Promise(resolve => {
|
||||
function listener() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", listener, true);
|
||||
resolve();
|
||||
}
|
||||
gBrowser.selectedBrowser.addEventListener("load", listener, true);
|
||||
gBrowser.loadURI("about:blank");
|
||||
});
|
||||
|
||||
yield waitForMessage(port, "RemotePage:Unload");
|
||||
|
||||
// Port should be destroyed now
|
||||
try {
|
||||
port.addMessageListener("Foo", failOnMessage);
|
||||
ok(false, "Should have seen exception");
|
||||
}
|
||||
catch (e) {
|
||||
ok(true, "Should have seen exception");
|
||||
}
|
||||
|
||||
try {
|
||||
port.sendAsyncMessage("Foo");
|
||||
ok(false, "Should have seen exception");
|
||||
}
|
||||
catch (e) {
|
||||
ok(true, "Should have seen exception");
|
||||
}
|
||||
|
||||
yield loaded;
|
||||
|
||||
gBrowser.goBack();
|
||||
port = yield waitForPort(TEST_URL, false);
|
||||
|
||||
port.sendAsyncMessage("Ping2");
|
||||
let message = yield waitForMessage(port, "Pong2");
|
||||
port.destroy();
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
// Test that opening a page creates a port, sends the load event and then
|
||||
// closing the tab sends the unload event
|
||||
add_task(function* init_close() {
|
||||
let port = yield waitForPort(TEST_URL);
|
||||
is(port.browser, gBrowser.selectedBrowser, "Port is for the correct browser");
|
||||
|
||||
let unloadPromise = waitForMessage(port, "RemotePage:Unload");
|
||||
gBrowser.removeCurrentTab();
|
||||
yield unloadPromise;
|
||||
|
||||
// Port should be destroyed now
|
||||
try {
|
||||
port.addMessageListener("Foo", failOnMessage);
|
||||
ok(false, "Should have seen exception");
|
||||
}
|
||||
catch (e) {
|
||||
ok(true, "Should have seen exception");
|
||||
}
|
||||
|
||||
try {
|
||||
port.sendAsyncMessage("Foo");
|
||||
ok(false, "Should have seen exception");
|
||||
}
|
||||
catch (e) {
|
||||
ok(true, "Should have seen exception");
|
||||
}
|
||||
});
|
||||
|
||||
// Tests that we can send messages to individual pages even when more than one
|
||||
// is open
|
||||
add_task(function* multiple_ports() {
|
||||
let port1 = yield waitForPort(TEST_URL);
|
||||
is(port1.browser, gBrowser.selectedBrowser, "Port is for the correct browser");
|
||||
|
||||
let port2 = yield waitForPort(TEST_URL);
|
||||
is(port2.browser, gBrowser.selectedBrowser, "Port is for the correct browser");
|
||||
|
||||
port2.addMessageListener("Pong", failOnMessage);
|
||||
port1.sendAsyncMessage("Ping", { str: "foobar", counter: 0 });
|
||||
let message = yield waitForMessage(port1, "Pong");
|
||||
port2.removeMessageListener("Pong", failOnMessage);
|
||||
is(message.data.str, "foobar", "String should pass through");
|
||||
is(message.data.counter, 1, "Counter should be incremented");
|
||||
|
||||
port1.addMessageListener("Pong", failOnMessage);
|
||||
port2.sendAsyncMessage("Ping", { str: "foobaz", counter: 5 });
|
||||
message = yield waitForMessage(port2, "Pong");
|
||||
port1.removeMessageListener("Pong", failOnMessage);
|
||||
is(message.data.str, "foobaz", "String should pass through");
|
||||
is(message.data.counter, 6, "Counter should be incremented");
|
||||
|
||||
let unloadPromise = waitForMessage(port2, "RemotePage:Unload");
|
||||
gBrowser.removeTab(gBrowser.getTabForBrowser(port2.browser));
|
||||
yield unloadPromise;
|
||||
|
||||
try {
|
||||
port2.addMessageListener("Pong", failOnMessage);
|
||||
ok(false, "Should not have been able to add a new message listener to a destroyed port.");
|
||||
}
|
||||
catch (e) {
|
||||
ok(true, "Should not have been able to add a new message listener to a destroyed port.");
|
||||
}
|
||||
|
||||
port1.sendAsyncMessage("Ping", { str: "foobar", counter: 0 });
|
||||
message = yield waitForMessage(port1, "Pong");
|
||||
is(message.data.str, "foobar", "String should pass through");
|
||||
is(message.data.counter, 1, "Counter should be incremented");
|
||||
|
||||
unloadPromise = waitForMessage(port1, "RemotePage:Unload");
|
||||
gBrowser.removeTab(gBrowser.getTabForBrowser(port1.browser));
|
||||
yield unloadPromise;
|
||||
});
|
||||
|
||||
// Tests that swapping browser docshells doesn't break the ports
|
||||
add_task(function* browser_switch() {
|
||||
let port1 = yield waitForPort(TEST_URL);
|
||||
is(port1.browser, gBrowser.selectedBrowser, "Port is for the correct browser");
|
||||
let browser1 = gBrowser.selectedBrowser;
|
||||
port1.sendAsyncMessage("SetCookie", { value: "om nom" });
|
||||
|
||||
let port2 = yield waitForPort(TEST_URL);
|
||||
is(port2.browser, gBrowser.selectedBrowser, "Port is for the correct browser");
|
||||
let browser2 = gBrowser.selectedBrowser;
|
||||
port2.sendAsyncMessage("SetCookie", { value: "om nom nom" });
|
||||
|
||||
port2.addMessageListener("Cookie", failOnMessage);
|
||||
port1.sendAsyncMessage("GetCookie");
|
||||
let message = yield waitForMessage(port1, "Cookie");
|
||||
port2.removeMessageListener("Cookie", failOnMessage);
|
||||
is(message.data.value, "om nom", "Should have the right cookie");
|
||||
|
||||
port1.addMessageListener("Cookie", failOnMessage);
|
||||
port2.sendAsyncMessage("GetCookie", { str: "foobaz", counter: 5 });
|
||||
message = yield waitForMessage(port2, "Cookie");
|
||||
port1.removeMessageListener("Cookie", failOnMessage);
|
||||
is(message.data.value, "om nom nom", "Should have the right cookie");
|
||||
|
||||
swapDocShells(browser1, browser2);
|
||||
is(port1.browser, browser2, "Should have noticed the swap");
|
||||
is(port2.browser, browser1, "Should have noticed the swap");
|
||||
|
||||
// Cookies should have stayed the same
|
||||
port2.addMessageListener("Cookie", failOnMessage);
|
||||
port1.sendAsyncMessage("GetCookie");
|
||||
message = yield waitForMessage(port1, "Cookie");
|
||||
port2.removeMessageListener("Cookie", failOnMessage);
|
||||
is(message.data.value, "om nom", "Should have the right cookie");
|
||||
|
||||
port1.addMessageListener("Cookie", failOnMessage);
|
||||
port2.sendAsyncMessage("GetCookie", { str: "foobaz", counter: 5 });
|
||||
message = yield waitForMessage(port2, "Cookie");
|
||||
port1.removeMessageListener("Cookie", failOnMessage);
|
||||
is(message.data.value, "om nom nom", "Should have the right cookie");
|
||||
|
||||
swapDocShells(browser1, browser2);
|
||||
is(port1.browser, browser1, "Should have noticed the swap");
|
||||
is(port2.browser, browser2, "Should have noticed the swap");
|
||||
|
||||
// Cookies should have stayed the same
|
||||
port2.addMessageListener("Cookie", failOnMessage);
|
||||
port1.sendAsyncMessage("GetCookie");
|
||||
message = yield waitForMessage(port1, "Cookie");
|
||||
port2.removeMessageListener("Cookie", failOnMessage);
|
||||
is(message.data.value, "om nom", "Should have the right cookie");
|
||||
|
||||
port1.addMessageListener("Cookie", failOnMessage);
|
||||
port2.sendAsyncMessage("GetCookie", { str: "foobaz", counter: 5 });
|
||||
message = yield waitForMessage(port2, "Cookie");
|
||||
port1.removeMessageListener("Cookie", failOnMessage);
|
||||
is(message.data.value, "om nom nom", "Should have the right cookie");
|
||||
|
||||
let unloadPromise = waitForMessage(port2, "RemotePage:Unload");
|
||||
gBrowser.removeTab(gBrowser.getTabForBrowser(browser2));
|
||||
yield unloadPromise;
|
||||
|
||||
unloadPromise = waitForMessage(port1, "RemotePage:Unload");
|
||||
gBrowser.removeTab(gBrowser.getTabForBrowser(browser1));
|
||||
yield unloadPromise;
|
||||
});
|
||||
|
||||
// Tests that removeMessageListener in chrome works
|
||||
add_task(function* remove_chrome_listener() {
|
||||
let port = yield waitForPort(TEST_URL);
|
||||
is(port.browser, gBrowser.selectedBrowser, "Port is for the correct browser");
|
||||
|
||||
// This relies on messages sent arriving in the same order. Pong will be
|
||||
// sent back before Pong2 so if removeMessageListener fails the test will fail
|
||||
port.addMessageListener("Pong", failOnMessage);
|
||||
port.removeMessageListener("Pong", failOnMessage);
|
||||
port.sendAsyncMessage("Ping", { str: "remove_listener", counter: 27 });
|
||||
port.sendAsyncMessage("Ping2");
|
||||
yield waitForMessage(port, "Pong2");
|
||||
|
||||
let unloadPromise = waitForMessage(port, "RemotePage:Unload");
|
||||
gBrowser.removeCurrentTab();
|
||||
yield unloadPromise;
|
||||
});
|
||||
|
||||
// Tests that removeMessageListener in content works
|
||||
add_task(function* remove_content_listener() {
|
||||
let port = yield waitForPort(TEST_URL);
|
||||
is(port.browser, gBrowser.selectedBrowser, "Port is for the correct browser");
|
||||
|
||||
// This relies on messages sent arriving in the same order. Pong3 would be
|
||||
// sent back before Pong2 so if removeMessageListener fails the test will fail
|
||||
port.addMessageListener("Pong3", failOnMessage);
|
||||
port.sendAsyncMessage("Ping3");
|
||||
port.sendAsyncMessage("Ping2");
|
||||
yield waitForMessage(port, "Pong2");
|
||||
|
||||
let unloadPromise = waitForMessage(port, "RemotePage:Unload");
|
||||
gBrowser.removeCurrentTab();
|
||||
yield unloadPromise;
|
||||
});
|
||||
|
||||
// Test RemotePages works
|
||||
add_task(function* remote_pages_basic() {
|
||||
let pages = new RemotePages(TEST_URL);
|
||||
let port = yield waitForPage(pages);
|
||||
is(port.browser, gBrowser.selectedBrowser, "Port is for the correct browser");
|
||||
|
||||
// Listening to global messages should work
|
||||
let unloadPromise = waitForMessage(pages, "RemotePage:Unload", port);
|
||||
gBrowser.removeCurrentTab();
|
||||
yield unloadPromise;
|
||||
|
||||
pages.destroy();
|
||||
|
||||
// RemotePages should be destroyed now
|
||||
try {
|
||||
pages.addMessageListener("Foo", failOnMessage);
|
||||
ok(false, "Should have seen exception");
|
||||
}
|
||||
catch (e) {
|
||||
ok(true, "Should have seen exception");
|
||||
}
|
||||
|
||||
try {
|
||||
pages.sendAsyncMessage("Foo");
|
||||
ok(false, "Should have seen exception");
|
||||
}
|
||||
catch (e) {
|
||||
ok(true, "Should have seen exception");
|
||||
}
|
||||
});
|
||||
|
||||
// Test sending messages to all remote pages works
|
||||
add_task(function* remote_pages_multiple() {
|
||||
let pages = new RemotePages(TEST_URL);
|
||||
let port1 = yield waitForPage(pages);
|
||||
let port2 = yield waitForPage(pages);
|
||||
|
||||
let pongPorts = [];
|
||||
yield new Promise((resolve) => {
|
||||
function listener({ name, target, data }) {
|
||||
is(name, "Pong", "Should have seen the right response.");
|
||||
is(data.str, "remote_pages", "String should pass through");
|
||||
is(data.counter, 43, "Counter should be incremented");
|
||||
pongPorts.push(target);
|
||||
if (pongPorts.length == 2)
|
||||
resolve();
|
||||
}
|
||||
|
||||
pages.addMessageListener("Pong", listener);
|
||||
pages.sendAsyncMessage("Ping", { str: "remote_pages", counter: 42 });
|
||||
});
|
||||
|
||||
// We don't make any guarantees about which order messages are sent to known
|
||||
// pages so the pongs could have come back in any order.
|
||||
isnot(pongPorts[0], pongPorts[1], "Should have received pongs from different ports");
|
||||
ok(pongPorts.indexOf(port1) >= 0, "Should have seen a pong from port1");
|
||||
ok(pongPorts.indexOf(port2) >= 0, "Should have seen a pong from port2");
|
||||
|
||||
// After destroy we should see no messages
|
||||
pages.addMessageListener("RemotePage:Unload", failOnMessage);
|
||||
pages.destroy();
|
||||
|
||||
gBrowser.removeTab(gBrowser.getTabForBrowser(port1.browser));
|
||||
gBrowser.removeTab(gBrowser.getTabForBrowser(port2.browser));
|
||||
});
|
||||
|
||||
// Test sending various types of data across the boundary
|
||||
add_task(function* send_data() {
|
||||
let port = yield waitForPort(TEST_URL);
|
||||
is(port.browser, gBrowser.selectedBrowser, "Port is for the correct browser");
|
||||
|
||||
let data = {
|
||||
integer: 45,
|
||||
real: 45.78,
|
||||
str: "foobar",
|
||||
array: [1, 2, 3, 5, 27]
|
||||
};
|
||||
|
||||
port.sendAsyncMessage("SendData", data);
|
||||
let message = yield waitForMessage(port, "ReceivedData");
|
||||
|
||||
ok(message.data.result, message.data.status);
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
// Test sending an object of data across the boundary
|
||||
add_task(function* send_data2() {
|
||||
let port = yield waitForPort(TEST_URL);
|
||||
is(port.browser, gBrowser.selectedBrowser, "Port is for the correct browser");
|
||||
|
||||
let data = {
|
||||
integer: 45,
|
||||
real: 45.78,
|
||||
str: "foobar",
|
||||
array: [1, 2, 3, 5, 27]
|
||||
};
|
||||
|
||||
port.sendAsyncMessage("SendData2", {data});
|
||||
let message = yield waitForMessage(port, "ReceivedData2");
|
||||
|
||||
ok(message.data.result, message.data.status);
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
add_task(function* get_ports_for_browser() {
|
||||
let pages = new RemotePages(TEST_URL);
|
||||
let port = yield waitForPage(pages);
|
||||
// waitForPage creates a new tab and selects it by default, so
|
||||
// the selected tab should be the one hosting this port.
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
let foundPorts = pages.portsForBrowser(browser);
|
||||
is(foundPorts.length, 1, "There should only be one port for this simple page");
|
||||
is(foundPorts[0], port, "Should find the port");
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
|
@ -1,566 +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/. */
|
||||
|
||||
// Ideally this would be an xpcshell test, but Troubleshoot relies on things
|
||||
// that aren't initialized outside of a XUL app environment like AddonManager
|
||||
// and the "@mozilla.org/xre/app-info;1" component.
|
||||
|
||||
Components.utils.import("resource://gre/modules/AppConstants.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource://gre/modules/Troubleshoot.jsm");
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
function doNextTest() {
|
||||
if (!tests.length) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
tests.shift()(doNextTest);
|
||||
}
|
||||
doNextTest();
|
||||
}
|
||||
|
||||
registerCleanupFunction(function () {
|
||||
// Troubleshoot.jsm is imported into the global scope -- the window -- above.
|
||||
// If it's not deleted, it outlives the test and is reported as a leak.
|
||||
delete window.Troubleshoot;
|
||||
});
|
||||
|
||||
var tests = [
|
||||
|
||||
function snapshotSchema(done) {
|
||||
Troubleshoot.snapshot(function (snapshot) {
|
||||
try {
|
||||
validateObject(snapshot, SNAPSHOT_SCHEMA);
|
||||
ok(true, "The snapshot should conform to the schema.");
|
||||
}
|
||||
catch (err) {
|
||||
ok(false, "Schema mismatch, " + err);
|
||||
}
|
||||
done();
|
||||
});
|
||||
},
|
||||
|
||||
function modifiedPreferences(done) {
|
||||
let prefs = [
|
||||
"javascript.troubleshoot",
|
||||
"troubleshoot.foo",
|
||||
"javascript.print_to_filename",
|
||||
"network.proxy.troubleshoot",
|
||||
];
|
||||
prefs.forEach(function (p) {
|
||||
Services.prefs.setBoolPref(p, true);
|
||||
is(Services.prefs.getBoolPref(p), true, "The pref should be set: " + p);
|
||||
});
|
||||
Troubleshoot.snapshot(function (snapshot) {
|
||||
let p = snapshot.modifiedPreferences;
|
||||
is(p["javascript.troubleshoot"], true,
|
||||
"The pref should be present because it's whitelisted " +
|
||||
"but not blacklisted.");
|
||||
ok(!("troubleshoot.foo" in p),
|
||||
"The pref should be absent because it's not in the whitelist.");
|
||||
ok(!("javascript.print_to_filename" in p),
|
||||
"The pref should be absent because it's blacklisted.");
|
||||
ok(!("network.proxy.troubleshoot" in p),
|
||||
"The pref should be absent because it's blacklisted.");
|
||||
prefs.forEach(p => Services.prefs.deleteBranch(p));
|
||||
done();
|
||||
});
|
||||
},
|
||||
|
||||
function unicodePreferences(done) {
|
||||
let name = "font.name.sans-serif.x-western";
|
||||
let utf8Value = "\xc4\x8capk\xc5\xafv Krasopis"
|
||||
let unicodeValue = "\u010Capk\u016Fv Krasopis";
|
||||
|
||||
// set/getCharPref work with 8bit strings (utf8)
|
||||
Services.prefs.setCharPref(name, utf8Value);
|
||||
|
||||
Troubleshoot.snapshot(function (snapshot) {
|
||||
let p = snapshot.modifiedPreferences;
|
||||
is(p[name], unicodeValue, "The pref should have correct Unicode value.");
|
||||
Services.prefs.deleteBranch(name);
|
||||
done();
|
||||
});
|
||||
}
|
||||
];
|
||||
|
||||
// This is inspired by JSON Schema, or by the example on its Wikipedia page
|
||||
// anyway.
|
||||
const SNAPSHOT_SCHEMA = {
|
||||
type: "object",
|
||||
required: true,
|
||||
properties: {
|
||||
application: {
|
||||
required: true,
|
||||
type: "object",
|
||||
properties: {
|
||||
name: {
|
||||
required: true,
|
||||
type: "string",
|
||||
},
|
||||
version: {
|
||||
required: true,
|
||||
type: "string",
|
||||
},
|
||||
buildID: {
|
||||
required: true,
|
||||
type: "string",
|
||||
},
|
||||
userAgent: {
|
||||
required: true,
|
||||
type: "string",
|
||||
},
|
||||
osVersion: {
|
||||
required: true,
|
||||
type: "string",
|
||||
},
|
||||
vendor: {
|
||||
type: "string",
|
||||
},
|
||||
updateChannel: {
|
||||
type: "string",
|
||||
},
|
||||
supportURL: {
|
||||
type: "string",
|
||||
},
|
||||
remoteAutoStart: {
|
||||
type: "boolean",
|
||||
required: true,
|
||||
},
|
||||
autoStartStatus: {
|
||||
type: "number",
|
||||
},
|
||||
numTotalWindows: {
|
||||
type: "number",
|
||||
},
|
||||
numRemoteWindows: {
|
||||
type: "number",
|
||||
},
|
||||
safeMode: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
},
|
||||
crashes: {
|
||||
required: false,
|
||||
type: "object",
|
||||
properties: {
|
||||
pending: {
|
||||
required: true,
|
||||
type: "number",
|
||||
},
|
||||
submitted: {
|
||||
required: true,
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
properties: {
|
||||
id: {
|
||||
required: true,
|
||||
type: "string",
|
||||
},
|
||||
date: {
|
||||
required: true,
|
||||
type: "number",
|
||||
},
|
||||
pending: {
|
||||
required: true,
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
extensions: {
|
||||
required: true,
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
properties: {
|
||||
name: {
|
||||
required: true,
|
||||
type: "string",
|
||||
},
|
||||
version: {
|
||||
required: true,
|
||||
type: "string",
|
||||
},
|
||||
id: {
|
||||
required: true,
|
||||
type: "string",
|
||||
},
|
||||
isActive: {
|
||||
required: true,
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
modifiedPreferences: {
|
||||
required: true,
|
||||
type: "object",
|
||||
},
|
||||
lockedPreferences: {
|
||||
required: true,
|
||||
type: "object",
|
||||
},
|
||||
graphics: {
|
||||
required: true,
|
||||
type: "object",
|
||||
properties: {
|
||||
numTotalWindows: {
|
||||
required: true,
|
||||
type: "number",
|
||||
},
|
||||
numAcceleratedWindows: {
|
||||
required: true,
|
||||
type: "number",
|
||||
},
|
||||
windowLayerManagerType: {
|
||||
type: "string",
|
||||
},
|
||||
windowLayerManagerRemote: {
|
||||
type: "boolean",
|
||||
},
|
||||
supportsHardwareH264: {
|
||||
type: "string",
|
||||
},
|
||||
currentAudioBackend: {
|
||||
type: "string",
|
||||
},
|
||||
numAcceleratedWindowsMessage: {
|
||||
type: "array",
|
||||
},
|
||||
adapterDescription: {
|
||||
type: "string",
|
||||
},
|
||||
adapterVendorID: {
|
||||
type: "string",
|
||||
},
|
||||
adapterDeviceID: {
|
||||
type: "string",
|
||||
},
|
||||
adapterSubsysID: {
|
||||
type: "string",
|
||||
},
|
||||
adapterRAM: {
|
||||
type: "string",
|
||||
},
|
||||
adapterDrivers: {
|
||||
type: "string",
|
||||
},
|
||||
driverVersion: {
|
||||
type: "string",
|
||||
},
|
||||
driverDate: {
|
||||
type: "string",
|
||||
},
|
||||
adapterDescription2: {
|
||||
type: "string",
|
||||
},
|
||||
adapterVendorID2: {
|
||||
type: "string",
|
||||
},
|
||||
adapterDeviceID2: {
|
||||
type: "string",
|
||||
},
|
||||
adapterSubsysID2: {
|
||||
type: "string",
|
||||
},
|
||||
adapterRAM2: {
|
||||
type: "string",
|
||||
},
|
||||
adapterDrivers2: {
|
||||
type: "string",
|
||||
},
|
||||
driverVersion2: {
|
||||
type: "string",
|
||||
},
|
||||
driverDate2: {
|
||||
type: "string",
|
||||
},
|
||||
isGPU2Active: {
|
||||
type: "boolean",
|
||||
},
|
||||
direct2DEnabled: {
|
||||
type: "boolean",
|
||||
},
|
||||
directWriteEnabled: {
|
||||
type: "boolean",
|
||||
},
|
||||
directWriteVersion: {
|
||||
type: "string",
|
||||
},
|
||||
clearTypeParameters: {
|
||||
type: "string",
|
||||
},
|
||||
webgl1Renderer: {
|
||||
type: "string",
|
||||
},
|
||||
webgl1Version: {
|
||||
type: "string",
|
||||
},
|
||||
webgl1DriverExtensions: {
|
||||
type: "string",
|
||||
},
|
||||
webgl1Extensions: {
|
||||
type: "string",
|
||||
},
|
||||
webgl1WSIInfo: {
|
||||
type: "string",
|
||||
},
|
||||
webgl2Renderer: {
|
||||
type: "string",
|
||||
},
|
||||
webgl2Version: {
|
||||
type: "string",
|
||||
},
|
||||
webgl2DriverExtensions: {
|
||||
type: "string",
|
||||
},
|
||||
webgl2Extensions: {
|
||||
type: "string",
|
||||
},
|
||||
webgl2WSIInfo: {
|
||||
type: "string",
|
||||
},
|
||||
info: {
|
||||
type: "object",
|
||||
},
|
||||
failures: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
indices: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "number",
|
||||
},
|
||||
},
|
||||
featureLog: {
|
||||
type: "object",
|
||||
},
|
||||
crashGuards: {
|
||||
type: "array",
|
||||
},
|
||||
direct2DEnabledMessage: {
|
||||
type: "array",
|
||||
},
|
||||
},
|
||||
},
|
||||
javaScript: {
|
||||
required: true,
|
||||
type: "object",
|
||||
properties: {
|
||||
incrementalGCEnabled: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
},
|
||||
accessibility: {
|
||||
required: true,
|
||||
type: "object",
|
||||
properties: {
|
||||
isActive: {
|
||||
required: true,
|
||||
type: "boolean",
|
||||
},
|
||||
forceDisabled: {
|
||||
type: "number",
|
||||
},
|
||||
},
|
||||
},
|
||||
libraryVersions: {
|
||||
required: true,
|
||||
type: "object",
|
||||
properties: {
|
||||
NSPR: {
|
||||
required: true,
|
||||
type: "object",
|
||||
properties: {
|
||||
minVersion: {
|
||||
required: true,
|
||||
type: "string",
|
||||
},
|
||||
version: {
|
||||
required: true,
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
NSS: {
|
||||
required: true,
|
||||
type: "object",
|
||||
properties: {
|
||||
minVersion: {
|
||||
required: true,
|
||||
type: "string",
|
||||
},
|
||||
version: {
|
||||
required: true,
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
NSSUTIL: {
|
||||
required: true,
|
||||
type: "object",
|
||||
properties: {
|
||||
minVersion: {
|
||||
required: true,
|
||||
type: "string",
|
||||
},
|
||||
version: {
|
||||
required: true,
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
NSSSSL: {
|
||||
required: true,
|
||||
type: "object",
|
||||
properties: {
|
||||
minVersion: {
|
||||
required: true,
|
||||
type: "string",
|
||||
},
|
||||
version: {
|
||||
required: true,
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
NSSSMIME: {
|
||||
required: true,
|
||||
type: "object",
|
||||
properties: {
|
||||
minVersion: {
|
||||
required: true,
|
||||
type: "string",
|
||||
},
|
||||
version: {
|
||||
required: true,
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
userJS: {
|
||||
required: true,
|
||||
type: "object",
|
||||
properties: {
|
||||
exists: {
|
||||
required: true,
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
},
|
||||
experiments: {
|
||||
type: "array",
|
||||
},
|
||||
sandbox: {
|
||||
required: false,
|
||||
type: "object",
|
||||
properties: {
|
||||
hasSeccompBPF: {
|
||||
required: AppConstants.platform == "linux",
|
||||
type: "boolean"
|
||||
},
|
||||
hasSeccompTSync: {
|
||||
required: AppConstants.platform == "linux",
|
||||
type: "boolean"
|
||||
},
|
||||
hasUserNamespaces: {
|
||||
required: AppConstants.platform == "linux",
|
||||
type: "boolean"
|
||||
},
|
||||
hasPrivilegedUserNamespaces: {
|
||||
required: AppConstants.platform == "linux",
|
||||
type: "boolean"
|
||||
},
|
||||
canSandboxContent: {
|
||||
required: false,
|
||||
type: "boolean"
|
||||
},
|
||||
canSandboxMedia: {
|
||||
required: false,
|
||||
type: "boolean"
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Throws an Error if obj doesn't conform to schema. That way you get a nice
|
||||
* error message and a stack to help you figure out what went wrong, which you
|
||||
* wouldn't get if this just returned true or false instead. There's still
|
||||
* room for improvement in communicating validation failures, however.
|
||||
*
|
||||
* @param obj The object to validate.
|
||||
* @param schema The schema that obj should conform to.
|
||||
*/
|
||||
function validateObject(obj, schema) {
|
||||
if (obj === undefined && !schema.required)
|
||||
return;
|
||||
if (typeof(schema.type) != "string")
|
||||
throw schemaErr("'type' must be a string", schema);
|
||||
if (objType(obj) != schema.type)
|
||||
throw validationErr("Object is not of the expected type", obj, schema);
|
||||
let validatorFnName = "validateObject_" + schema.type;
|
||||
if (!(validatorFnName in this))
|
||||
throw schemaErr("Validator function not defined for type", schema);
|
||||
this[validatorFnName](obj, schema);
|
||||
}
|
||||
|
||||
function validateObject_object(obj, schema) {
|
||||
if (typeof(schema.properties) != "object")
|
||||
// Don't care what obj's properties are.
|
||||
return;
|
||||
// First check that all the schema's properties match the object.
|
||||
for (let prop in schema.properties)
|
||||
validateObject(obj[prop], schema.properties[prop]);
|
||||
// Now check that the object doesn't have any properties not in the schema.
|
||||
for (let prop in obj)
|
||||
if (!(prop in schema.properties))
|
||||
throw validationErr("Object has property "+prop+" not in schema", obj, schema);
|
||||
}
|
||||
|
||||
function validateObject_array(array, schema) {
|
||||
if (typeof(schema.items) != "object")
|
||||
// Don't care what the array's elements are.
|
||||
return;
|
||||
array.forEach(elt => validateObject(elt, schema.items));
|
||||
}
|
||||
|
||||
function validateObject_string(str, schema) {}
|
||||
function validateObject_boolean(bool, schema) {}
|
||||
function validateObject_number(num, schema) {}
|
||||
|
||||
function validationErr(msg, obj, schema) {
|
||||
return new Error("Validation error: " + msg +
|
||||
": object=" + JSON.stringify(obj) +
|
||||
", schema=" + JSON.stringify(schema));
|
||||
}
|
||||
|
||||
function schemaErr(msg, schema) {
|
||||
return new Error("Schema error: " + msg + ": " + JSON.stringify(schema));
|
||||
}
|
||||
|
||||
function objType(obj) {
|
||||
let type = typeof(obj);
|
||||
if (type != "object")
|
||||
return type;
|
||||
if (Array.isArray(obj))
|
||||
return "array";
|
||||
if (obj === null)
|
||||
return "null";
|
||||
return type;
|
||||
}
|
||||
|
|
@ -1,140 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
var { interfaces: Ci, classes: Cc, utils: Cu, results: Cr } = Components;
|
||||
|
||||
var {WebNavigation} = Cu.import("resource://gre/modules/WebNavigation.jsm", {});
|
||||
|
||||
const BASE = "http://example.com/browser/toolkit/modules/tests/browser";
|
||||
const URL = BASE + "/file_WebNavigation_page1.html";
|
||||
const FRAME = BASE + "/file_WebNavigation_page2.html";
|
||||
const FRAME2 = BASE + "/file_WebNavigation_page3.html";
|
||||
|
||||
const EVENTS = [
|
||||
"onBeforeNavigate",
|
||||
"onCommitted",
|
||||
"onDOMContentLoaded",
|
||||
"onCompleted",
|
||||
"onErrorOccurred",
|
||||
"onReferenceFragmentUpdated",
|
||||
];
|
||||
|
||||
const REQUIRED = [
|
||||
"onBeforeNavigate",
|
||||
"onCommitted",
|
||||
"onDOMContentLoaded",
|
||||
"onCompleted",
|
||||
];
|
||||
|
||||
var expectedBrowser;
|
||||
var received = [];
|
||||
var completedResolve;
|
||||
var waitingURL, waitingEvent;
|
||||
var rootWindowID;
|
||||
|
||||
function gotEvent(event, details)
|
||||
{
|
||||
if (!details.url.startsWith(BASE)) {
|
||||
return;
|
||||
}
|
||||
info(`Got ${event} ${details.url} ${details.windowId} ${details.parentWindowId}`);
|
||||
|
||||
is(details.browser, expectedBrowser, "correct <browser> element");
|
||||
|
||||
received.push({url: details.url, event});
|
||||
|
||||
if (typeof(rootWindowID) == "undefined") {
|
||||
rootWindowID = details.windowId;
|
||||
}
|
||||
|
||||
if (details.url == URL) {
|
||||
is(details.windowId, rootWindowID, "root window ID correct");
|
||||
} else {
|
||||
is(details.parentWindowId, rootWindowID, "parent window ID correct");
|
||||
isnot(details.windowId, rootWindowID, "window ID probably okay");
|
||||
}
|
||||
|
||||
isnot(details.windowId, undefined);
|
||||
isnot(details.parentWindowId, undefined);
|
||||
|
||||
if (details.url == waitingURL && event == waitingEvent) {
|
||||
completedResolve();
|
||||
}
|
||||
}
|
||||
|
||||
function loadViaFrameScript(url, event, script)
|
||||
{
|
||||
// Loading via a frame script ensures that the chrome process never
|
||||
// "gets ahead" of frame scripts in non-e10s mode.
|
||||
received = [];
|
||||
waitingURL = url;
|
||||
waitingEvent = event;
|
||||
expectedBrowser.messageManager.loadFrameScript("data:," + script, false);
|
||||
return new Promise(resolve => { completedResolve = resolve; });
|
||||
}
|
||||
|
||||
add_task(function* webnav_ordering() {
|
||||
let listeners = {};
|
||||
for (let event of EVENTS) {
|
||||
listeners[event] = gotEvent.bind(null, event);
|
||||
WebNavigation[event].addListener(listeners[event]);
|
||||
}
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
expectedBrowser = browser;
|
||||
|
||||
yield BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
yield loadViaFrameScript(URL, "onCompleted", `content.location = "${URL}";`);
|
||||
|
||||
function checkRequired(url) {
|
||||
for (let event of REQUIRED) {
|
||||
let found = false;
|
||||
for (let r of received) {
|
||||
if (r.url == url && r.event == event) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
ok(found, `Received event ${event} from ${url}`);
|
||||
}
|
||||
}
|
||||
|
||||
checkRequired(URL);
|
||||
checkRequired(FRAME);
|
||||
|
||||
function checkBefore(action1, action2) {
|
||||
function find(action) {
|
||||
for (let i = 0; i < received.length; i++) {
|
||||
if (received[i].url == action.url && received[i].event == action.event) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
let index1 = find(action1);
|
||||
let index2 = find(action2);
|
||||
ok(index1 != -1, `Action ${JSON.stringify(action1)} happened`);
|
||||
ok(index2 != -1, `Action ${JSON.stringify(action2)} happened`);
|
||||
ok(index1 < index2, `Action ${JSON.stringify(action1)} happened before ${JSON.stringify(action2)}`);
|
||||
}
|
||||
|
||||
checkBefore({url: URL, event: "onCommitted"}, {url: FRAME, event: "onBeforeNavigate"});
|
||||
checkBefore({url: FRAME, event: "onCompleted"}, {url: URL, event: "onCompleted"});
|
||||
|
||||
yield loadViaFrameScript(FRAME2, "onCompleted", `content.frames[0].location = "${FRAME2}";`);
|
||||
|
||||
checkRequired(FRAME2);
|
||||
|
||||
yield loadViaFrameScript(FRAME2 + "#ref", "onReferenceFragmentUpdated",
|
||||
"content.frames[0].document.getElementById('elt').click();");
|
||||
|
||||
info("Received onReferenceFragmentUpdated from FRAME2");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
|
||||
for (let event of EVENTS) {
|
||||
WebNavigation[event].removeListener(listeners[event]);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -1,214 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
var { interfaces: Ci, classes: Cc, utils: Cu, results: Cr } = Components;
|
||||
|
||||
var {WebRequest} = Cu.import("resource://gre/modules/WebRequest.jsm", {});
|
||||
|
||||
const BASE = "http://example.com/browser/toolkit/modules/tests/browser";
|
||||
const URL = BASE + "/file_WebRequest_page1.html";
|
||||
|
||||
var expected_browser;
|
||||
|
||||
function checkType(details)
|
||||
{
|
||||
let expected_type = "???";
|
||||
if (details.url.indexOf("style") != -1) {
|
||||
expected_type = "stylesheet";
|
||||
} else if (details.url.indexOf("image") != -1) {
|
||||
expected_type = "image";
|
||||
} else if (details.url.indexOf("script") != -1) {
|
||||
expected_type = "script";
|
||||
} else if (details.url.indexOf("page1") != -1) {
|
||||
expected_type = "main_frame";
|
||||
} else if (/page2|_redirection\.|dummy_page/.test(details.url)) {
|
||||
expected_type = "sub_frame";
|
||||
} else if (details.url.indexOf("xhr") != -1) {
|
||||
expected_type = "xmlhttprequest";
|
||||
}
|
||||
is(details.type, expected_type, "resource type is correct");
|
||||
}
|
||||
|
||||
var windowIDs = new Map();
|
||||
|
||||
var requested = [];
|
||||
|
||||
function onBeforeRequest(details)
|
||||
{
|
||||
info(`onBeforeRequest ${details.url}`);
|
||||
if (details.url.startsWith(BASE)) {
|
||||
requested.push(details.url);
|
||||
|
||||
is(details.browser, expected_browser, "correct <browser> element");
|
||||
checkType(details);
|
||||
|
||||
windowIDs.set(details.url, details.windowId);
|
||||
if (details.url.indexOf("page2") != -1) {
|
||||
let page1id = windowIDs.get(URL);
|
||||
ok(details.windowId != page1id, "sub-frame gets its own window ID");
|
||||
is(details.parentWindowId, page1id, "parent window id is correct");
|
||||
}
|
||||
}
|
||||
if (details.url.indexOf("_bad.") != -1) {
|
||||
return {cancel: true};
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var sendHeaders = [];
|
||||
|
||||
function onBeforeSendHeaders(details)
|
||||
{
|
||||
info(`onBeforeSendHeaders ${details.url}`);
|
||||
if (details.url.startsWith(BASE)) {
|
||||
sendHeaders.push(details.url);
|
||||
|
||||
is(details.browser, expected_browser, "correct <browser> element");
|
||||
checkType(details);
|
||||
|
||||
let id = windowIDs.get(details.url);
|
||||
is(id, details.windowId, "window ID same in onBeforeSendHeaders as onBeforeRequest");
|
||||
}
|
||||
if (details.url.indexOf("_redirect.") != -1) {
|
||||
return {redirectUrl: details.url.replace("_redirect.", "_good.")};
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var beforeRedirect = [];
|
||||
|
||||
function onBeforeRedirect(details)
|
||||
{
|
||||
info(`onBeforeRedirect ${details.url} -> ${details.redirectUrl}`);
|
||||
checkType(details);
|
||||
if (details.url.startsWith(BASE)) {
|
||||
beforeRedirect.push(details.url);
|
||||
|
||||
is(details.browser, expected_browser, "correct <browser> element");
|
||||
checkType(details);
|
||||
|
||||
let expectedUrl = details.url.replace("_redirect.", "_good.").replace(/\w+_redirection\..*/, "dummy_page.html")
|
||||
is(details.redirectUrl, expectedUrl, "Correct redirectUrl value");
|
||||
}
|
||||
let id = windowIDs.get(details.url);
|
||||
is(id, details.windowId, "window ID same in onBeforeRedirect as onBeforeRequest");
|
||||
// associate stored windowId with final url
|
||||
windowIDs.set(details.redirectUrl, details.windowId);
|
||||
return {};
|
||||
}
|
||||
|
||||
var headersReceived = [];
|
||||
|
||||
function onResponseStarted(details)
|
||||
{
|
||||
if (details.url.startsWith(BASE)) {
|
||||
headersReceived.push(details.url);
|
||||
}
|
||||
}
|
||||
|
||||
const expected_requested = [BASE + "/file_WebRequest_page1.html",
|
||||
BASE + "/file_style_good.css",
|
||||
BASE + "/file_style_bad.css",
|
||||
BASE + "/file_style_redirect.css",
|
||||
BASE + "/file_image_good.png",
|
||||
BASE + "/file_image_bad.png",
|
||||
BASE + "/file_image_redirect.png",
|
||||
BASE + "/file_script_good.js",
|
||||
BASE + "/file_script_bad.js",
|
||||
BASE + "/file_script_redirect.js",
|
||||
BASE + "/file_script_xhr.js",
|
||||
BASE + "/file_WebRequest_page2.html",
|
||||
BASE + "/nonexistent_script_url.js",
|
||||
BASE + "/WebRequest_redirection.sjs",
|
||||
BASE + "/dummy_page.html",
|
||||
BASE + "/xhr_resource"];
|
||||
|
||||
const expected_sendHeaders = [BASE + "/file_WebRequest_page1.html",
|
||||
BASE + "/file_style_good.css",
|
||||
BASE + "/file_style_redirect.css",
|
||||
BASE + "/file_image_good.png",
|
||||
BASE + "/file_image_redirect.png",
|
||||
BASE + "/file_script_good.js",
|
||||
BASE + "/file_script_redirect.js",
|
||||
BASE + "/file_script_xhr.js",
|
||||
BASE + "/file_WebRequest_page2.html",
|
||||
BASE + "/nonexistent_script_url.js",
|
||||
BASE + "/WebRequest_redirection.sjs",
|
||||
BASE + "/dummy_page.html",
|
||||
BASE + "/xhr_resource"];
|
||||
|
||||
const expected_beforeRedirect = expected_sendHeaders.filter(u => /_redirect\./.test(u))
|
||||
.concat(BASE + "/WebRequest_redirection.sjs");
|
||||
|
||||
const expected_headersReceived = [BASE + "/file_WebRequest_page1.html",
|
||||
BASE + "/file_style_good.css",
|
||||
BASE + "/file_image_good.png",
|
||||
BASE + "/file_script_good.js",
|
||||
BASE + "/file_script_xhr.js",
|
||||
BASE + "/file_WebRequest_page2.html",
|
||||
BASE + "/nonexistent_script_url.js",
|
||||
BASE + "/dummy_page.html",
|
||||
BASE + "/xhr_resource"];
|
||||
|
||||
function removeDupes(list)
|
||||
{
|
||||
let j = 0;
|
||||
for (let i = 1; i < list.length; i++) {
|
||||
if (list[i] != list[j]) {
|
||||
j++;
|
||||
if (i != j) {
|
||||
list[j] = list[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
list.length = j + 1;
|
||||
}
|
||||
|
||||
function compareLists(list1, list2, kind)
|
||||
{
|
||||
list1.sort();
|
||||
removeDupes(list1);
|
||||
list2.sort();
|
||||
removeDupes(list2);
|
||||
is(String(list1), String(list2), `${kind} URLs correct`);
|
||||
}
|
||||
|
||||
function* test_once()
|
||||
{
|
||||
WebRequest.onBeforeRequest.addListener(onBeforeRequest, null, ["blocking"]);
|
||||
WebRequest.onBeforeSendHeaders.addListener(onBeforeSendHeaders, null, ["blocking"]);
|
||||
WebRequest.onBeforeRedirect.addListener(onBeforeRedirect);
|
||||
WebRequest.onResponseStarted.addListener(onResponseStarted);
|
||||
|
||||
yield BrowserTestUtils.withNewTab({ gBrowser, url: "about:blank" },
|
||||
function* (browser) {
|
||||
expected_browser = browser;
|
||||
BrowserTestUtils.loadURI(browser, URL);
|
||||
yield BrowserTestUtils.browserLoaded(expected_browser);
|
||||
|
||||
expected_browser = null;
|
||||
|
||||
yield ContentTask.spawn(browser, null, function() {
|
||||
let win = content.wrappedJSObject;
|
||||
is(win.success, 2, "Good script ran");
|
||||
is(win.failure, undefined, "Failure script didn't run");
|
||||
|
||||
let style =
|
||||
content.getComputedStyle(content.document.getElementById("test"), null);
|
||||
is(style.getPropertyValue("color"), "rgb(255, 0, 0)", "Good CSS loaded");
|
||||
});
|
||||
});
|
||||
|
||||
compareLists(requested, expected_requested, "requested");
|
||||
compareLists(sendHeaders, expected_sendHeaders, "sendHeaders");
|
||||
compareLists(beforeRedirect, expected_beforeRedirect, "beforeRedirect");
|
||||
compareLists(headersReceived, expected_headersReceived, "headersReceived");
|
||||
|
||||
WebRequest.onBeforeRequest.removeListener(onBeforeRequest);
|
||||
WebRequest.onBeforeSendHeaders.removeListener(onBeforeSendHeaders);
|
||||
WebRequest.onBeforeRedirect.removeListener(onBeforeRedirect);
|
||||
WebRequest.onResponseStarted.removeListener(onResponseStarted);
|
||||
}
|
||||
|
||||
// Run the test twice to make sure it works with caching.
|
||||
add_task(test_once);
|
||||
add_task(test_once);
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
var { interfaces: Ci, classes: Cc, utils: Cu, results: Cr } = Components;
|
||||
|
||||
var {WebRequest} = Cu.import("resource://gre/modules/WebRequest.jsm", {});
|
||||
|
||||
const BASE = "http://example.com/browser/toolkit/modules/tests/browser";
|
||||
const URL = BASE + "/WebRequest_dynamic.sjs";
|
||||
|
||||
var countBefore = 0;
|
||||
var countAfter = 0;
|
||||
|
||||
function onBeforeSendHeaders(details)
|
||||
{
|
||||
if (details.url != URL) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
countBefore++;
|
||||
|
||||
info(`onBeforeSendHeaders ${details.url}`);
|
||||
let found = false;
|
||||
let headers = [];
|
||||
for (let {name, value} of details.requestHeaders) {
|
||||
info(`Saw header ${name} '${value}'`);
|
||||
if (name == "Cookie") {
|
||||
is(value, "foopy=1", "Cookie is correct");
|
||||
headers.push({name, value: "blinky=1"});
|
||||
found = true;
|
||||
} else {
|
||||
headers.push({name, value});
|
||||
}
|
||||
}
|
||||
ok(found, "Saw cookie header");
|
||||
|
||||
return {requestHeaders: headers};
|
||||
}
|
||||
|
||||
function onResponseStarted(details)
|
||||
{
|
||||
if (details.url != URL) {
|
||||
return;
|
||||
}
|
||||
|
||||
countAfter++;
|
||||
|
||||
info(`onResponseStarted ${details.url}`);
|
||||
let found = false;
|
||||
for (let {name, value} of details.responseHeaders) {
|
||||
info(`Saw header ${name} '${value}'`);
|
||||
if (name == "Set-Cookie") {
|
||||
is(value, "dinky=1", "Cookie is correct");
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
ok(found, "Saw cookie header");
|
||||
}
|
||||
|
||||
add_task(function* filter_urls() {
|
||||
// First load the URL so that we set cookie foopy=1.
|
||||
gBrowser.selectedTab = gBrowser.addTab(URL);
|
||||
yield waitForLoad();
|
||||
gBrowser.removeCurrentTab();
|
||||
|
||||
// Now load with WebRequest set up.
|
||||
WebRequest.onBeforeSendHeaders.addListener(onBeforeSendHeaders, null, ["blocking"]);
|
||||
WebRequest.onResponseStarted.addListener(onResponseStarted, null);
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab(URL);
|
||||
|
||||
yield waitForLoad();
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
|
||||
WebRequest.onBeforeSendHeaders.removeListener(onBeforeSendHeaders);
|
||||
WebRequest.onResponseStarted.removeListener(onResponseStarted);
|
||||
|
||||
is(countBefore, 1, "onBeforeSendHeaders hit once");
|
||||
is(countAfter, 1, "onResponseStarted hit once");
|
||||
});
|
||||
|
||||
function waitForLoad(browser = gBrowser.selectedBrowser) {
|
||||
return new Promise(resolve => {
|
||||
browser.addEventListener("load", function listener() {
|
||||
browser.removeEventListener("load", listener, true);
|
||||
resolve();
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
var { interfaces: Ci, classes: Cc, utils: Cu, results: Cr } = Components;
|
||||
|
||||
var {WebRequest} = Cu.import("resource://gre/modules/WebRequest.jsm", {});
|
||||
var {MatchPattern} = Cu.import("resource://gre/modules/MatchPattern.jsm", {});
|
||||
|
||||
const BASE = "http://example.com/browser/toolkit/modules/tests/browser";
|
||||
const URL = BASE + "/file_WebRequest_page2.html";
|
||||
|
||||
var requested = [];
|
||||
|
||||
function onBeforeRequest(details)
|
||||
{
|
||||
info(`onBeforeRequest ${details.url}`);
|
||||
if (details.url.startsWith(BASE)) {
|
||||
requested.push(details.url);
|
||||
}
|
||||
}
|
||||
|
||||
var sendHeaders = [];
|
||||
|
||||
function onBeforeSendHeaders(details)
|
||||
{
|
||||
info(`onBeforeSendHeaders ${details.url}`);
|
||||
if (details.url.startsWith(BASE)) {
|
||||
sendHeaders.push(details.url);
|
||||
}
|
||||
}
|
||||
|
||||
var completed = [];
|
||||
|
||||
function onResponseStarted(details)
|
||||
{
|
||||
if (details.url.startsWith(BASE)) {
|
||||
completed.push(details.url);
|
||||
}
|
||||
}
|
||||
|
||||
const expected_urls = [BASE + "/file_style_good.css",
|
||||
BASE + "/file_style_bad.css",
|
||||
BASE + "/file_style_redirect.css"];
|
||||
|
||||
function removeDupes(list)
|
||||
{
|
||||
let j = 0;
|
||||
for (let i = 1; i < list.length; i++) {
|
||||
if (list[i] != list[j]) {
|
||||
j++;
|
||||
if (i != j) {
|
||||
list[j] = list[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
list.length = j + 1;
|
||||
}
|
||||
|
||||
function compareLists(list1, list2, kind)
|
||||
{
|
||||
list1.sort();
|
||||
removeDupes(list1);
|
||||
list2.sort();
|
||||
removeDupes(list2);
|
||||
is(String(list1), String(list2), `${kind} URLs correct`);
|
||||
}
|
||||
|
||||
add_task(function* filter_urls() {
|
||||
let filter = {urls: new MatchPattern("*://*/*_style_*")};
|
||||
|
||||
WebRequest.onBeforeRequest.addListener(onBeforeRequest, filter, ["blocking"]);
|
||||
WebRequest.onBeforeSendHeaders.addListener(onBeforeSendHeaders, filter, ["blocking"]);
|
||||
WebRequest.onResponseStarted.addListener(onResponseStarted, filter);
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab(URL);
|
||||
|
||||
yield waitForLoad();
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
|
||||
compareLists(requested, expected_urls, "requested");
|
||||
compareLists(sendHeaders, expected_urls, "sendHeaders");
|
||||
compareLists(completed, expected_urls, "completed");
|
||||
|
||||
WebRequest.onBeforeRequest.removeListener(onBeforeRequest);
|
||||
WebRequest.onBeforeSendHeaders.removeListener(onBeforeSendHeaders);
|
||||
WebRequest.onResponseStarted.removeListener(onResponseStarted);
|
||||
});
|
||||
|
||||
add_task(function* filter_types() {
|
||||
let filter = {types: ["stylesheet"]};
|
||||
|
||||
WebRequest.onBeforeRequest.addListener(onBeforeRequest, filter, ["blocking"]);
|
||||
WebRequest.onBeforeSendHeaders.addListener(onBeforeSendHeaders, filter, ["blocking"]);
|
||||
WebRequest.onResponseStarted.addListener(onResponseStarted, filter);
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab(URL);
|
||||
|
||||
yield waitForLoad();
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
|
||||
compareLists(requested, expected_urls, "requested");
|
||||
compareLists(sendHeaders, expected_urls, "sendHeaders");
|
||||
compareLists(completed, expected_urls, "completed");
|
||||
|
||||
WebRequest.onBeforeRequest.removeListener(onBeforeRequest);
|
||||
WebRequest.onBeforeSendHeaders.removeListener(onBeforeSendHeaders);
|
||||
WebRequest.onResponseStarted.removeListener(onResponseStarted);
|
||||
});
|
||||
|
||||
function waitForLoad(browser = gBrowser.selectedBrowser) {
|
||||
return new Promise(resolve => {
|
||||
browser.addEventListener("load", function listener() {
|
||||
browser.removeEventListener("load", listener, true);
|
||||
resolve();
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<body>
|
||||
<p>Page</p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,824 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Childe Roland</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>"Childe Roland to the Dark Tower Came"</h1><h5>Robert Browning</h5>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>I.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>My first thought was, he lied in every word,
|
||||
<dl>
|
||||
<dd>That hoary cripple, with malicious eye</dd>
|
||||
<dd>Askance to watch the working of his lie</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>On mine, and mouth scarce able to afford</dd>
|
||||
<dd>Suppression of the glee that pursed and scored
|
||||
<dl>
|
||||
<dd>Its edge, at one more victim gained thereby.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>II.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>What else should he be set for, with his staff?
|
||||
<dl>
|
||||
<dd>What, save to waylay with his lies, ensnare</dd>
|
||||
<dd>All travellers who might find him posted there,</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>And ask the road? I guessed what skull-like laugh</dd>
|
||||
<dd>Would break, what crutch 'gin write my epitaph
|
||||
<dl>
|
||||
<dd>For pastime in the dusty thoroughfare,</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>III.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>If at his counsel I should turn aside
|
||||
<dl>
|
||||
<dd>Into that ominous tract which, all agree,</dd>
|
||||
<dd>Hides the Dark Tower. Yet acquiescingly</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>I did turn as he pointed: neither pride</dd>
|
||||
<dd>Nor hope rekindling at the end descried,
|
||||
<dl>
|
||||
<dd>So much as gladness that some end might be.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>IV.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>For, what with my whole world-wide wandering,
|
||||
<dl>
|
||||
<dd>What with my search drawn out thro' years, my hope</dd>
|
||||
<dd>Dwindled into a ghost not fit to cope</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>With that obstreperous joy success would bring,</dd>
|
||||
<dd>I hardly tried now to rebuke the spring
|
||||
<dl>
|
||||
<dd>My heart made, finding failure in its scope.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>V.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>As when a sick man very near to death
|
||||
<dl>
|
||||
<dd>Seems dead indeed, and feels begin and end</dd>
|
||||
<dd>The tears and takes the farewell of each friend,</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>And hears one bid the other go, draw breath</dd>
|
||||
<dd>Freelier outside ("since all is o'er," he saith,
|
||||
<dl>
|
||||
<dd>"And the blow fallen no grieving can amend;")</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>VI.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>While some discuss if near the other graves
|
||||
<dl>
|
||||
<dd>Be room enough for this, and when a day</dd>
|
||||
<dd>Suits best for carrying the corpse away,</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>With care about the banners, scarves and staves:</dd>
|
||||
<dd>And still the man hears all, and only craves
|
||||
<dl>
|
||||
<dd>He may not shame such tender love and stay.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>VII.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>Thus, I had so long suffered in this quest,
|
||||
<dl>
|
||||
<dd>Heard failure prophesied so oft, been writ</dd>
|
||||
<dd>So many times among "The Band" - to wit,</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>The knights who to the Dark Tower's search addressed</dd>
|
||||
<dd>Their steps - that just to fail as they, seemed best,
|
||||
<dl>
|
||||
<dd>And all the doubt was now—should I be fit?</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>VIII.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>So, quiet as despair, I turned from him,
|
||||
<dl>
|
||||
<dd>That hateful cripple, out of his highway</dd>
|
||||
<dd>Into the path he pointed. All the day</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>Had been a dreary one at best, and dim</dd>
|
||||
<dd>Was settling to its close, yet shot one grim
|
||||
<dl>
|
||||
<dd>Red leer to see the plain catch its estray.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>IX.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>For mark! no sooner was I fairly found
|
||||
<dl>
|
||||
<dd>Pledged to the plain, after a pace or two,</dd>
|
||||
<dd>Than, pausing to throw backward a last view</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>O'er the safe road, 'twas gone; grey plain all round:</dd>
|
||||
<dd>Nothing but plain to the horizon's bound.
|
||||
<dl>
|
||||
<dd>I might go on; nought else remained to do.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>X.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>So, on I went. I think I never saw
|
||||
<dl>
|
||||
<dd>Such starved ignoble nature; nothing throve:</dd>
|
||||
<dd>For flowers - as well expect a cedar grove!</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>But cockle, spurge, according to their law</dd>
|
||||
<dd>Might propagate their kind, with none to awe,
|
||||
<dl>
|
||||
<dd>You'd think; a burr had been a treasure trove.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>XI.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>No! penury, inertness and grimace,
|
||||
<dl>
|
||||
<dd>In some strange sort, were the land's portion. "See</dd>
|
||||
<dd>Or shut your eyes," said Nature peevishly,</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>"It nothing skills: I cannot help my case:</dd>
|
||||
<dd>'Tis the Last Judgment's fire must cure this place,
|
||||
<dl>
|
||||
<dd>Calcine its clods and set my prisoners free."</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>XII.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>If there pushed any ragged thistle-stalk
|
||||
<dl>
|
||||
<dd>Above its mates, the head was chopped; the bents</dd>
|
||||
<dd>Were jealous else. What made those holes and rents</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>In the dock's harsh swarth leaves, bruised as to baulk</dd>
|
||||
<dd>All hope of greenness? 'tis a brute must walk
|
||||
<dl>
|
||||
<dd>Pashing their life out, with a brute's intents.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>XIII.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>As for the grass, it grew as scant as hair
|
||||
<dl>
|
||||
<dd>In leprosy; thin dry blades pricked the mud</dd>
|
||||
<dd>Which underneath looked kneaded up with blood.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>One stiff blind horse, his every bone a-stare,</dd>
|
||||
<dd>Stood stupefied, however he came there:
|
||||
<dl>
|
||||
<dd>Thrust out past service from the devil's stud!</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>XIV.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>Alive? he might be dead for aught I know,
|
||||
<dl>
|
||||
<dd>With that red gaunt and colloped neck a-strain,</dd>
|
||||
<dd>And shut eyes underneath the rusty mane;</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>Seldom went such grotesqueness with such woe;</dd>
|
||||
<dd>I never saw a brute I hated so;
|
||||
<dl>
|
||||
<dd>He must be wicked to deserve such pain.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>XV.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>I shut my eyes and turned them on my heart.
|
||||
<dl>
|
||||
<dd>As a man calls for wine before he fights,</dd>
|
||||
<dd>I asked one draught of earlier, happier sights,</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>Ere fitly I could hope to play my part.</dd>
|
||||
<dd>Think first, fight afterwards - the soldier's art:
|
||||
<dl>
|
||||
<dd>One taste of the old time sets all to rights.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>XVI.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>Not it! I fancied Cuthbert's reddening face
|
||||
<dl>
|
||||
<dd>Beneath its garniture of curly gold,</dd>
|
||||
<dd>Dear fellow, till I almost felt him fold</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>An arm in mine to fix me to the place</dd>
|
||||
<dd>That way he used. Alas, one night's disgrace!
|
||||
<dl>
|
||||
<dd>Out went my heart's new fire and left it cold.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>XVII.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>Giles then, the soul of honour - there he stands
|
||||
<dl>
|
||||
<dd>Frank as ten years ago when knighted first.</dd>
|
||||
<dd>What honest men should dare (he said) he durst.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>Good - but the scene shifts - faugh! what hangman hands</dd>
|
||||
<dd>Pin to his breast a parchment? His own bands
|
||||
<dl>
|
||||
<dd>Read it. Poor traitor, spit upon and curst!</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>XVIII.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>Better this present than a past like that;
|
||||
<dl>
|
||||
<dd>Back therefore to my darkening path again!</dd>
|
||||
<dd>No sound, no sight as far as eye could strain.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>Will the night send a howlet or a bat?</dd>
|
||||
<dd>I asked: when something on the dismal flat
|
||||
<dl>
|
||||
<dd>Came to arrest my thoughts and change their train.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>XIX.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>A sudden little river crossed my path
|
||||
<dl>
|
||||
<dd>As unexpected as a serpent comes.</dd>
|
||||
<dd>No sluggish tide congenial to the glooms;</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>This, as it frothed by, might have been a bath</dd>
|
||||
<dd>For the fiend's glowing hoof - to see the wrath
|
||||
<dl>
|
||||
<dd>Of its black eddy bespate with flakes and spumes.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>XX.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>So petty yet so spiteful! All along
|
||||
<dl>
|
||||
<dd>Low scrubby alders kneeled down over it;</dd>
|
||||
<dd>Drenched willows flung them headlong in a fit</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>Of mute despair, a suicidal throng:</dd>
|
||||
<dd>The river which had done them all the wrong,
|
||||
<dl>
|
||||
<dd>Whate'er that was, rolled by, deterred no whit.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>XXI.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>Which, while I forded, - good saints, how I feared
|
||||
<dl>
|
||||
<dd>To set my foot upon a dead man's cheek,</dd>
|
||||
<dd>Each step, or feel the spear I thrust to seek</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>For hollows, tangled in his hair or beard!</dd>
|
||||
<dd>—It may have been a water-rat I speared,
|
||||
<dl>
|
||||
<dd>But, ugh! it sounded like a baby's shriek.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>XXII.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>Glad was I when I reached the other bank.
|
||||
<dl>
|
||||
<dd>Now for a better country. Vain presage!</dd>
|
||||
<dd>Who were the strugglers, what war did they wage,</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>Whose savage trample thus could pad the dank</dd>
|
||||
<dd>Soil to a plash? Toads in a poisoned tank,
|
||||
<dl>
|
||||
<dd>Or wild cats in a red-hot iron cage—</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>XXIII.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>The fight must so have seemed in that fell cirque.
|
||||
<dl>
|
||||
<dd>What penned them there, with all the plain to choose?</dd>
|
||||
<dd>No foot-print leading to that horrid mews,</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>None out of it. Mad brewage set to work</dd>
|
||||
<dd>Their brains, no doubt, like galley-slaves the Turk
|
||||
<dl>
|
||||
<dd>Pits for his pastime, Christians against Jews.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>XXIV.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>And more than that - a furlong on - why, there!
|
||||
<dl>
|
||||
<dd>What bad use was that engine for, that wheel,</dd>
|
||||
<dd>Or brake, not wheel - that harrow fit to reel</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>Men's bodies out like silk? with all the air</dd>
|
||||
<dd>Of Tophet's tool, on earth left unaware,
|
||||
<dl>
|
||||
<dd>Or brought to sharpen its rusty teeth of steel.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>XXV.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>Then came a bit of stubbed ground, once a wood,
|
||||
<dl>
|
||||
<dd>Next a marsh, it would seem, and now mere earth</dd>
|
||||
<dd>Desperate and done with; (so a fool finds mirth,</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>Makes a thing and then mars it, till his mood</dd>
|
||||
<dd>Changes and off he goes!) within a rood—
|
||||
<dl>
|
||||
<dd>Bog, clay and rubble, sand and stark black dearth.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>XXVI.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>Now blotches rankling, coloured gay and grim,
|
||||
<dl>
|
||||
<dd>Now patches where some leanness of the soil's</dd>
|
||||
<dd>Broke into moss or substances like boils;</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>Then came some palsied oak, a cleft in him</dd>
|
||||
<dd>Like a distorted mouth that splits its rim
|
||||
<dl>
|
||||
<dd>Gaping at death, and dies while it recoils.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>XXVII.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>And just as far as ever from the end!
|
||||
<dl>
|
||||
<dd>Nought in the distance but the evening, nought</dd>
|
||||
<dd>To point my footstep further! At the thought,</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>A great black bird, Apollyon's bosom-friend,</dd>
|
||||
<dd>Sailed past, nor beat his wide wing dragon-penned
|
||||
<dl>
|
||||
<dd>That brushed my cap—perchance the guide I sought.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>XXVIII.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>For, looking up, aware I somehow grew,
|
||||
<dl>
|
||||
<dd>'Spite of the dusk, the plain had given place</dd>
|
||||
<dd>All round to mountains - with such name to grace</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>Mere ugly heights and heaps now stolen in view.</dd>
|
||||
<dd>How thus they had surprised me, - solve it, you!
|
||||
<dl>
|
||||
<dd>How to get from them was no clearer case.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>XXIX.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>Yet half I seemed to recognise some trick
|
||||
<dl>
|
||||
<dd>Of mischief happened to me, God knows when—</dd>
|
||||
<dd>In a bad dream perhaps. Here ended, then,</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>Progress this way. When, in the very nick</dd>
|
||||
<dd>Of giving up, one time more, came a click
|
||||
<dl>
|
||||
<dd>As when a trap shuts - you're inside the den!</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>XXX.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>Burningly it came on me all at once,
|
||||
<dl>
|
||||
<dd>This was the place! those two hills on the right,</dd>
|
||||
<dd>Crouched like two bulls locked horn in horn in fight;</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>While to the left, a tall scalped mountain... Dunce,</dd>
|
||||
<dd>Dotard, a-dozing at the very nonce,
|
||||
<dl>
|
||||
<dd>After a life spent training for the sight!</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>XXXI.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>What in the midst lay but the Tower itself?
|
||||
<dl>
|
||||
<dd>The round squat turret, blind as the fool's heart</dd>
|
||||
<dd>Built of brown stone, without a counterpart</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>In the whole world. The tempest's mocking elf</dd>
|
||||
<dd>Points to the shipman thus the unseen shelf
|
||||
<dl>
|
||||
<dd>He strikes on, only when the timbers start.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>XXXII.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>Not see? because of night perhaps? - why, day
|
||||
<dl>
|
||||
<dd>Came back again for that! before it left,</dd>
|
||||
<dd>The dying sunset kindled through a cleft:</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>The hills, like giants at a hunting, lay</dd>
|
||||
<dd>Chin upon hand, to see the game at bay,—
|
||||
<dl>
|
||||
<dd>"Now stab and end the creature - to the heft!"</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>XXXIII.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>Not hear? when noise was everywhere! it tolled
|
||||
<dl>
|
||||
<dd>Increasing like a bell. Names in my ears</dd>
|
||||
<dd>Of all the lost adventurers my peers,—</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>How such a one was strong, and such was bold,</dd>
|
||||
<dd>And such was fortunate, yet each of old
|
||||
<dl>
|
||||
<dd>Lost, lost! one moment knelled the woe of years.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>
|
||||
<dl>
|
||||
<dd>XXXIV.</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>There they stood, ranged along the hillsides, met
|
||||
<dl>
|
||||
<dd>To view the last of me, a living frame</dd>
|
||||
<dd>For one more picture! in a sheet of flame</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dd>I saw them and I knew them all. And yet</dd>
|
||||
<dd>Dauntless the slug-horn to my lips I set,
|
||||
<dl>
|
||||
<dd>And blew "<i>Childe Roland to the Dark Tower came.</i>"</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<iframe src="file_WebNavigation_page2.html" width="200" height="200"></iframe>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
|
||||
<html>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
|
||||
<html>
|
||||
<body>
|
||||
|
||||
<a id="elt" href="file_WebNavigation_page3.html#ref">click me</a>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="file_style_good.css">
|
||||
<link rel="stylesheet" href="file_style_bad.css">
|
||||
<link rel="stylesheet" href="file_style_redirect.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="test">Sample text</div>
|
||||
|
||||
<img id="img_good" src="file_image_good.png">
|
||||
<img id="img_bad" src="file_image_bad.png">
|
||||
<img id="img_redirect" src="file_image_redirect.png">
|
||||
|
||||
<script src="file_script_good.js"></script>
|
||||
<script src="file_script_bad.js"></script>
|
||||
<script src="file_script_redirect.js"></script>
|
||||
|
||||
<script src="file_script_xhr.js"></script>
|
||||
|
||||
<script src="nonexistent_script_url.js"></script>
|
||||
|
||||
<iframe src="file_WebRequest_page2.html" width="200" height="200"></iframe>
|
||||
<iframe src="WebRequest_redirection.sjs" width="200" height="50"></iframe>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="file_style_good.css">
|
||||
<link rel="stylesheet" href="file_style_bad.css">
|
||||
<link rel="stylesheet" href="file_style_redirect.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="test">Sample text</div>
|
||||
|
||||
<img id="img_good" src="file_image_good.png">
|
||||
<img id="img_bad" src="file_image_bad.png">
|
||||
<img id="img_redirect" src="file_image_redirect.png">
|
||||
|
||||
<script src="file_script_good.js"></script>
|
||||
<script src="file_script_bad.js"></script>
|
||||
<script src="file_script_redirect.js"></script>
|
||||
|
||||
<script src="nonexistent_script_url.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 5.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 580 B |
Binary file not shown.
|
Before Width: | Height: | Size: 5.3 KiB |
|
|
@ -1 +0,0 @@
|
|||
window.failure = true;
|
||||
|
|
@ -1 +0,0 @@
|
|||
window.success = window.success ? window.success + 1 : 1;
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
window.failure = true;
|
||||
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
var request = new XMLHttpRequest();
|
||||
request.open("get", "http://example.com/browser/toolkit/modules/tests/browser/xhr_resource", false);
|
||||
request.send();
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
#test {
|
||||
color: green !important;
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
#test {
|
||||
color: red;
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
#test {
|
||||
color: green !important;
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
function removeDupes(list)
|
||||
{
|
||||
let j = 0;
|
||||
for (let i = 1; i < list.length; i++) {
|
||||
if (list[i] != list[j]) {
|
||||
j++;
|
||||
if (i != j) {
|
||||
list[j] = list[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
list.length = j + 1;
|
||||
}
|
||||
|
||||
function compareLists(list1, list2, kind)
|
||||
{
|
||||
list1.sort();
|
||||
removeDupes(list1);
|
||||
list2.sort();
|
||||
removeDupes(list2);
|
||||
is(String(list1), String(list2), `${kind} URLs correct`);
|
||||
}
|
||||
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test Title</title>
|
||||
<meta property="description" content="A very simple test page">
|
||||
</head>
|
||||
<body>
|
||||
Llama.
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test Titles</title>
|
||||
<meta property="description" content="A very simple test page" />
|
||||
<meta property="og:title" content="Title" />
|
||||
</head>
|
||||
<body>
|
||||
Llama.
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta property="description" content="A very simple test page" />
|
||||
<meta property="og:title" content="Title" />
|
||||
</head>
|
||||
<body>
|
||||
Llama.
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
addMessageListener("Ping", function(message) {
|
||||
sendAsyncMessage("Pong", {
|
||||
str: message.data.str,
|
||||
counter: message.data.counter + 1
|
||||
});
|
||||
});
|
||||
|
||||
addMessageListener("Ping2", function(message) {
|
||||
sendAsyncMessage("Pong2", message.data);
|
||||
});
|
||||
|
||||
function neverCalled() {
|
||||
sendAsyncMessage("Pong3");
|
||||
}
|
||||
addMessageListener("Pong3", neverCalled);
|
||||
removeMessageListener("Pong3", neverCalled);
|
||||
|
||||
function testData(data) {
|
||||
var response = {
|
||||
result: true,
|
||||
status: "All data correctly received"
|
||||
}
|
||||
|
||||
function compare(prop, expected) {
|
||||
if (uneval(data[prop]) == uneval(expected))
|
||||
return;
|
||||
if (response.result)
|
||||
response.status = "";
|
||||
response.result = false;
|
||||
response.status += "Property " + prop + " should have been " + expected + " but was " + data[prop] + "\n";
|
||||
}
|
||||
|
||||
compare("integer", 45);
|
||||
compare("real", 45.78);
|
||||
compare("str", "foobar");
|
||||
compare("array", [1, 2, 3, 5, 27]);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
addMessageListener("SendData", function(message) {
|
||||
sendAsyncMessage("ReceivedData", testData(message.data));
|
||||
});
|
||||
|
||||
addMessageListener("SendData2", function(message) {
|
||||
sendAsyncMessage("ReceivedData2", testData(message.data.data));
|
||||
});
|
||||
|
||||
var cookie = "nom";
|
||||
addMessageListener("SetCookie", function(message) {
|
||||
cookie = message.data.value;
|
||||
});
|
||||
|
||||
addMessageListener("GetCookie", function(message) {
|
||||
sendAsyncMessage("Cookie", { value: cookie });
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"../../../../testing/mochitest/chrome.eslintrc.js"
|
||||
]
|
||||
};
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
[DEFAULT]
|
||||
|
||||
[test_bug544442_checkCert.xul]
|
||||
|
|
@ -1,155 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/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="Test CertUtils.jsm checkCert - bug 340198 and bug 544442"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="testStart();">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cr = Components.results;
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
Components.utils.import("resource://gre/modules/CertUtils.jsm");
|
||||
|
||||
function testStart() {
|
||||
ok(true, "Entering testStart");
|
||||
|
||||
var request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
|
||||
createInstance(Ci.nsIXMLHttpRequest);
|
||||
request.open("GET", "https://example.com/", true);
|
||||
request.channel.notificationCallbacks = new BadCertHandler(true);
|
||||
request.onerror = function(event) { testXHRError(event); };
|
||||
request.onload = function(event) { testXHRLoad(event); };
|
||||
request.send(null);
|
||||
}
|
||||
|
||||
function testXHRError(aEvent) {
|
||||
ok(true, "Entering testXHRError - something went wrong");
|
||||
|
||||
var request = aEvent.target;
|
||||
var status = 0;
|
||||
try {
|
||||
status = request.status;
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
|
||||
if (status == 0)
|
||||
status = request.channel.QueryInterface(Ci.nsIRequest).status;
|
||||
|
||||
ok(false, "XHR onerror called: " + status);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function getCheckCertResult(aChannel, aAllowNonBuiltIn, aCerts) {
|
||||
try {
|
||||
checkCert(aChannel, aAllowNonBuiltIn, aCerts);
|
||||
}
|
||||
catch (e) {
|
||||
return e.result;
|
||||
}
|
||||
return Cr.NS_OK;
|
||||
}
|
||||
|
||||
function testXHRLoad(aEvent) {
|
||||
ok(true, "Entering testXHRLoad");
|
||||
|
||||
var channel = aEvent.target.channel;
|
||||
|
||||
var certs = null;
|
||||
is(getCheckCertResult(channel, false, certs), Cr.NS_ERROR_ABORT,
|
||||
"checkCert should throw NS_ERROR_ABORT when the certificate attributes " +
|
||||
"array passed to checkCert is null and the certificate is not builtin");
|
||||
|
||||
is(getCheckCertResult(channel, true, certs), Cr.NS_OK,
|
||||
"checkCert should not throw when the certificate attributes array " +
|
||||
"passed to checkCert is null and builtin certificates aren't enforced");
|
||||
|
||||
certs = [ { invalidAttribute: "Invalid attribute" } ];
|
||||
is(getCheckCertResult(channel, false, certs), Cr.NS_ERROR_ILLEGAL_VALUE,
|
||||
"checkCert should throw NS_ERROR_ILLEGAL_VALUE when the certificate " +
|
||||
"attributes array passed to checkCert has an element that has an " +
|
||||
"attribute that does not exist on the certificate");
|
||||
|
||||
certs = [ { issuerName: "Incorrect issuerName" } ];
|
||||
is(getCheckCertResult(channel, false, certs), Cr.NS_ERROR_ILLEGAL_VALUE,
|
||||
"checkCert should throw NS_ERROR_ILLEGAL_VALUE when the certificate " +
|
||||
"attributes array passed to checkCert has an element that has an " +
|
||||
"issuerName that is not the same as the certificate's");
|
||||
|
||||
var cert = channel.securityInfo.QueryInterface(Ci.nsISSLStatusProvider).
|
||||
SSLStatus.QueryInterface(Ci.nsISSLStatus).serverCert;
|
||||
|
||||
certs = [ { issuerName: cert.issuerName,
|
||||
commonName: cert.commonName } ];
|
||||
is(getCheckCertResult(channel, false, certs), Cr.NS_ERROR_ABORT,
|
||||
"checkCert should throw NS_ERROR_ABORT when the certificate attributes " +
|
||||
"array passed to checkCert has a single element that has the same " +
|
||||
"issuerName and commonName as the certificate's and the certificate is " +
|
||||
"not builtin");
|
||||
|
||||
is(getCheckCertResult(channel, true, certs), Cr.NS_OK,
|
||||
"checkCert should not throw when the certificate attributes array " +
|
||||
"passed to checkCert has a single element that has the same issuerName " +
|
||||
"and commonName as the certificate's and and builtin certificates " +
|
||||
"aren't enforced");
|
||||
|
||||
certs = [ { issuerName: "Incorrect issuerName",
|
||||
invalidAttribute: "Invalid attribute" },
|
||||
{ issuerName: cert.issuerName,
|
||||
commonName: "Invalid Common Name" },
|
||||
{ issuerName: cert.issuerName,
|
||||
commonName: cert.commonName } ];
|
||||
is(getCheckCertResult(channel, false, certs), Cr.NS_ERROR_ABORT,
|
||||
"checkCert should throw NS_ERROR_ABORT when the certificate attributes " +
|
||||
"array passed to checkCert has an element that has the same issuerName " +
|
||||
"and commonName as the certificate's and the certificate is not builtin");
|
||||
|
||||
is(getCheckCertResult(channel, true, certs), Cr.NS_OK,
|
||||
"checkCert should not throw when the certificate attributes array " +
|
||||
"passed to checkCert has an element that has the same issuerName and " +
|
||||
"commonName as the certificate's and builtin certificates aren't enforced");
|
||||
|
||||
var mockChannel = { originalURI: Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService).
|
||||
newURI("http://example.com/", null, null) };
|
||||
|
||||
certs = [ ];
|
||||
is(getCheckCertResult(mockChannel, false, certs), Cr.NS_ERROR_UNEXPECTED,
|
||||
"checkCert should throw NS_ERROR_UNEXPECTED when the certificate " +
|
||||
"attributes array passed to checkCert is not null and the channel's " +
|
||||
"originalURI is not https");
|
||||
|
||||
certs = null;
|
||||
is(getCheckCertResult(mockChannel, false, certs), Cr.NS_OK,
|
||||
"checkCert should not throw when the certificate attributes object " +
|
||||
"passed to checkCert is null and the the channel's originalURI is not " +
|
||||
"https");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test"></pre>
|
||||
</body>
|
||||
</window>
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"../../../../testing/mochitest/mochitest.eslintrc.js"
|
||||
]
|
||||
};
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
[DEFAULT]
|
||||
|
||||
[test_spatial_navigation.html]
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=698437
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 698437</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 698437 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function Test() {
|
||||
if (!SpecialPowers.getBoolPref("snav.enabled")) {
|
||||
todo(false, "Enable spatial navigiation on this platform.");
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var center = document.getElementById("center");
|
||||
var right = document.getElementById("right");
|
||||
var left = document.getElementById("left");
|
||||
var top = document.getElementById("top");
|
||||
var bottom = document.getElementById("bottom");
|
||||
|
||||
console.log(top);
|
||||
console.log(bottom);
|
||||
console.log(center);
|
||||
console.log(left);
|
||||
console.log(right);
|
||||
|
||||
center.focus();
|
||||
is(center.id, document.activeElement.id, "How did we call focus on center and it did" +
|
||||
" not become the active element?");
|
||||
|
||||
synthesizeKey("VK_UP", { });
|
||||
is(document.activeElement.id, top.id,
|
||||
"Spatial navigation up key is not handled correctly.");
|
||||
|
||||
center.focus();
|
||||
synthesizeKey("VK_DOWN", { });
|
||||
is(document.activeElement.id, bottom.id,
|
||||
"Spatial navigation down key is not handled correctly.");
|
||||
|
||||
center.focus();
|
||||
synthesizeKey("VK_RIGHT", { });
|
||||
is(document.activeElement.id, right.id,
|
||||
"Spatial navigation right key is not handled correctly.");
|
||||
|
||||
center.focus();
|
||||
synthesizeKey("VK_LEFT", { });
|
||||
is(document.activeElement.id, left.id,
|
||||
"Spatial navigation left key is not handled correctly.");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="Test();">
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=698437">Mozilla Bug 698437</a>
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
<button id="lefttop">1</button><button id="top">2</button><button id="righttop">3</button><br>
|
||||
<button id="left">4</button><button id="center">5</button><button id="right">6</button><br>
|
||||
<button id="leftbottom">7</button><button id="bottom">8</button><button id="rightbottom">9</button><br>
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"../../../../testing/xpcshell/xpcshell.eslintrc.js"
|
||||
]
|
||||
};
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/*
|
||||
* Internal module used to test the generation of Integration.jsm getters.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
"TestIntegration",
|
||||
];
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
this.TestIntegration = {
|
||||
value: "value",
|
||||
|
||||
get valueFromThis() {
|
||||
return this.value;
|
||||
},
|
||||
|
||||
get property() {
|
||||
return this._property;
|
||||
},
|
||||
|
||||
set property(value) {
|
||||
this._property = value;
|
||||
},
|
||||
|
||||
method(argument) {
|
||||
this.methodArgument = argument;
|
||||
return "method" + argument;
|
||||
},
|
||||
|
||||
asyncMethod: Task.async(function* (argument) {
|
||||
this.asyncMethodArgument = argument;
|
||||
return "asyncMethod" + argument;
|
||||
}),
|
||||
};
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,28 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Boolean</key>
|
||||
<false/>
|
||||
<key>Array</key>
|
||||
<array>
|
||||
<string>abc</string>
|
||||
<string>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</string>
|
||||
<string>אאא</string>
|
||||
<string>אאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאאא</string>
|
||||
<string>𐀀𐀀𐀀</string>
|
||||
<date>2011-12-31T11:15:23Z</date>
|
||||
<data>MjAxMS0xMi0zMVQxMToxNTozM1o=</data>
|
||||
<dict>
|
||||
<key>Negative Number</key>
|
||||
<integer>-400</integer>
|
||||
<key>Real Number</key>
|
||||
<real>2.71828183</real>
|
||||
<key>Big Int</key>
|
||||
<integer>9007199254740993</integer>
|
||||
<key>Negative Big Int</key>
|
||||
<integer>-9007199254740993</integer>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Components.utils.import("resource://gre/modules/BinarySearch.jsm");
|
||||
|
||||
function run_test() {
|
||||
// empty array
|
||||
ok([], 1, false, 0);
|
||||
|
||||
// one-element array
|
||||
ok([2], 2, true, 0);
|
||||
ok([2], 1, false, 0);
|
||||
ok([2], 3, false, 1);
|
||||
|
||||
// two-element array
|
||||
ok([2, 4], 2, true, 0);
|
||||
ok([2, 4], 4, true, 1);
|
||||
ok([2, 4], 1, false, 0);
|
||||
ok([2, 4], 3, false, 1);
|
||||
ok([2, 4], 5, false, 2);
|
||||
|
||||
// three-element array
|
||||
ok([2, 4, 6], 2, true, 0);
|
||||
ok([2, 4, 6], 4, true, 1);
|
||||
ok([2, 4, 6], 6, true, 2);
|
||||
ok([2, 4, 6], 1, false, 0);
|
||||
ok([2, 4, 6], 3, false, 1);
|
||||
ok([2, 4, 6], 5, false, 2);
|
||||
ok([2, 4, 6], 7, false, 3);
|
||||
|
||||
// duplicates
|
||||
ok([2, 2], 2, true, 0);
|
||||
ok([2, 2], 1, false, 0);
|
||||
ok([2, 2], 3, false, 2);
|
||||
|
||||
// duplicates on the left
|
||||
ok([2, 2, 4], 2, true, 1);
|
||||
ok([2, 2, 4], 4, true, 2);
|
||||
ok([2, 2, 4], 1, false, 0);
|
||||
ok([2, 2, 4], 3, false, 2);
|
||||
ok([2, 2, 4], 5, false, 3);
|
||||
|
||||
// duplicates on the right
|
||||
ok([2, 4, 4], 2, true, 0);
|
||||
ok([2, 4, 4], 4, true, 1);
|
||||
ok([2, 4, 4], 1, false, 0);
|
||||
ok([2, 4, 4], 3, false, 1);
|
||||
ok([2, 4, 4], 5, false, 3);
|
||||
|
||||
// duplicates in the middle
|
||||
ok([2, 4, 4, 6], 2, true, 0);
|
||||
ok([2, 4, 4, 6], 4, true, 1);
|
||||
ok([2, 4, 4, 6], 6, true, 3);
|
||||
ok([2, 4, 4, 6], 1, false, 0);
|
||||
ok([2, 4, 4, 6], 3, false, 1);
|
||||
ok([2, 4, 4, 6], 5, false, 3);
|
||||
ok([2, 4, 4, 6], 7, false, 4);
|
||||
|
||||
// duplicates all around
|
||||
ok([2, 2, 4, 4, 6, 6], 2, true, 0);
|
||||
ok([2, 2, 4, 4, 6, 6], 4, true, 2);
|
||||
ok([2, 2, 4, 4, 6, 6], 6, true, 4);
|
||||
ok([2, 2, 4, 4, 6, 6], 1, false, 0);
|
||||
ok([2, 2, 4, 4, 6, 6], 3, false, 2);
|
||||
ok([2, 2, 4, 4, 6, 6], 5, false, 4);
|
||||
ok([2, 2, 4, 4, 6, 6], 7, false, 6);
|
||||
}
|
||||
|
||||
function ok(array, target, expectedFound, expectedIdx) {
|
||||
let [found, idx] = BinarySearch.search(cmp, array, target);
|
||||
do_check_eq(found, expectedFound);
|
||||
do_check_eq(idx, expectedIdx);
|
||||
|
||||
idx = expectedFound ? expectedIdx : -1;
|
||||
do_check_eq(BinarySearch.indexOf(cmp, array, target), idx);
|
||||
do_check_eq(BinarySearch.insertionIndexOf(cmp, array, target), expectedIdx);
|
||||
}
|
||||
|
||||
function cmp(num1, num2) {
|
||||
return num1 - num2;
|
||||
}
|
||||
|
|
@ -1,146 +0,0 @@
|
|||
const { CanonicalJSON } = Components.utils.import("resource://gre/modules/CanonicalJSON.jsm");
|
||||
|
||||
function stringRepresentation(obj) {
|
||||
const clone = JSON.parse(JSON.stringify(obj));
|
||||
return JSON.stringify(clone);
|
||||
}
|
||||
|
||||
add_task(function* test_canonicalJSON_should_preserve_array_order() {
|
||||
const input = ['one', 'two', 'three'];
|
||||
// No sorting should be done on arrays.
|
||||
do_check_eq(CanonicalJSON.stringify(input), '["one","two","three"]');
|
||||
});
|
||||
|
||||
add_task(function* test_canonicalJSON_orders_object_keys() {
|
||||
const input = [{
|
||||
b: ['two', 'three'],
|
||||
a: ['zero', 'one']
|
||||
}];
|
||||
do_check_eq(
|
||||
CanonicalJSON.stringify(input),
|
||||
'[{"a":["zero","one"],"b":["two","three"]}]'
|
||||
);
|
||||
});
|
||||
|
||||
add_task(function* test_canonicalJSON_orders_nested_object_keys() {
|
||||
const input = [{
|
||||
b: {d: 'd', c: 'c'},
|
||||
a: {b: 'b', a: 'a'}
|
||||
}];
|
||||
do_check_eq(
|
||||
CanonicalJSON.stringify(input),
|
||||
'[{"a":{"a":"a","b":"b"},"b":{"c":"c","d":"d"}}]'
|
||||
);
|
||||
});
|
||||
|
||||
add_task(function* test_canonicalJSON_escapes_unicode_values() {
|
||||
do_check_eq(
|
||||
CanonicalJSON.stringify([{key: '✓'}]),
|
||||
'[{"key":"\\u2713"}]'
|
||||
);
|
||||
// Unicode codepoints should be output in lowercase.
|
||||
do_check_eq(
|
||||
CanonicalJSON.stringify([{key: 'é'}]),
|
||||
'[{"key":"\\u00e9"}]'
|
||||
);
|
||||
});
|
||||
|
||||
add_task(function* test_canonicalJSON_escapes_unicode_object_keys() {
|
||||
do_check_eq(
|
||||
CanonicalJSON.stringify([{'é': 'check'}]),
|
||||
'[{"\\u00e9":"check"}]'
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_canonicalJSON_does_not_alter_input() {
|
||||
const records = [
|
||||
{'foo': 'bar', 'last_modified': '12345', 'id': '1'},
|
||||
{'bar': 'baz', 'last_modified': '45678', 'id': '2'}
|
||||
];
|
||||
const serializedJSON = JSON.stringify(records);
|
||||
CanonicalJSON.stringify(records);
|
||||
do_check_eq(JSON.stringify(records), serializedJSON);
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_canonicalJSON_preserves_data() {
|
||||
const records = [
|
||||
{'foo': 'bar', 'last_modified': '12345', 'id': '1'},
|
||||
{'bar': 'baz', 'last_modified': '45678', 'id': '2'},
|
||||
]
|
||||
const serialized = CanonicalJSON.stringify(records);
|
||||
const expected = '[{"foo":"bar","id":"1","last_modified":"12345"},' +
|
||||
'{"bar":"baz","id":"2","last_modified":"45678"}]';
|
||||
do_check_eq(CanonicalJSON.stringify(records), expected);
|
||||
});
|
||||
|
||||
add_task(function* test_canonicalJSON_does_not_add_space_separators() {
|
||||
const records = [
|
||||
{'foo': 'bar', 'last_modified': '12345', 'id': '1'},
|
||||
{'bar': 'baz', 'last_modified': '45678', 'id': '2'},
|
||||
]
|
||||
const serialized = CanonicalJSON.stringify(records);
|
||||
do_check_false(serialized.includes(" "));
|
||||
});
|
||||
|
||||
add_task(function* test_canonicalJSON_serializes_empty_object() {
|
||||
do_check_eq(CanonicalJSON.stringify({}), "{}");
|
||||
});
|
||||
|
||||
add_task(function* test_canonicalJSON_serializes_empty_array() {
|
||||
do_check_eq(CanonicalJSON.stringify([]), "[]");
|
||||
});
|
||||
|
||||
add_task(function* test_canonicalJSON_serializes_NaN() {
|
||||
do_check_eq(CanonicalJSON.stringify(NaN), "null");
|
||||
});
|
||||
|
||||
add_task(function* test_canonicalJSON_serializes_inf() {
|
||||
// This isn't part of the JSON standard.
|
||||
do_check_eq(CanonicalJSON.stringify(Infinity), "null");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_canonicalJSON_serializes_empty_string() {
|
||||
do_check_eq(CanonicalJSON.stringify(""), '""');
|
||||
});
|
||||
|
||||
add_task(function* test_canonicalJSON_escapes_backslashes() {
|
||||
do_check_eq(CanonicalJSON.stringify("This\\and this"), '"This\\\\and this"');
|
||||
});
|
||||
|
||||
add_task(function* test_canonicalJSON_handles_signed_zeros() {
|
||||
// do_check_eq doesn't support comparison of -0 and 0 properly.
|
||||
do_check_true(CanonicalJSON.stringify(-0) === '-0');
|
||||
do_check_true(CanonicalJSON.stringify(0) === '0');
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_canonicalJSON_with_deeply_nested_dicts() {
|
||||
const records = [{
|
||||
'a': {
|
||||
'b': 'b',
|
||||
'a': 'a',
|
||||
'c': {
|
||||
'b': 'b',
|
||||
'a': 'a',
|
||||
'c': ['b', 'a', 'c'],
|
||||
'd': {'b': 'b', 'a': 'a'},
|
||||
'id': '1',
|
||||
'e': 1,
|
||||
'f': [2, 3, 1],
|
||||
'g': {2: 2, 3: 3, 1: {
|
||||
'b': 'b', 'a': 'a', 'c': 'c'}}}},
|
||||
'id': '1'}]
|
||||
const expected =
|
||||
'[{"a":{"a":"a","b":"b","c":{"a":"a","b":"b","c":["b","a","c"],' +
|
||||
'"d":{"a":"a","b":"b"},"e":1,"f":[2,3,1],"g":{' +
|
||||
'"1":{"a":"a","b":"b","c":"c"},"2":2,"3":3},"id":"1"}},"id":"1"}]';
|
||||
|
||||
do_check_eq(CanonicalJSON.stringify(records), expected);
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/Color.jsm");
|
||||
|
||||
function run_test() {
|
||||
testRelativeLuminance();
|
||||
testIsBright();
|
||||
testContrastRatio();
|
||||
testIsContrastRatioAcceptable();
|
||||
}
|
||||
|
||||
function testRelativeLuminance() {
|
||||
let c = new Color(0, 0, 0);
|
||||
Assert.equal(c.relativeLuminance, 0, "Black is not illuminating");
|
||||
|
||||
c = new Color(255, 255, 255);
|
||||
Assert.equal(c.relativeLuminance, 1, "White is quite the luminant one");
|
||||
|
||||
c = new Color(142, 42, 142);
|
||||
Assert.equal(c.relativeLuminance, 0.25263952353998204,
|
||||
"This purple is not that luminant");
|
||||
}
|
||||
|
||||
function testIsBright() {
|
||||
let c = new Color(0, 0, 0);
|
||||
Assert.equal(c.isBright, 0, "Black is bright");
|
||||
|
||||
c = new Color(255, 255, 255);
|
||||
Assert.equal(c.isBright, 1, "White is bright");
|
||||
}
|
||||
|
||||
function testContrastRatio() {
|
||||
let c = new Color(0, 0, 0);
|
||||
let c2 = new Color(255, 255, 255);
|
||||
Assert.equal(c.contrastRatio(c2), 21, "Contrast between black and white is max");
|
||||
Assert.equal(c.contrastRatio(c), 1, "Contrast between equals is min");
|
||||
|
||||
let c3 = new Color(142, 42, 142);
|
||||
Assert.equal(c.contrastRatio(c3), 6.05279047079964, "Contrast between black and purple");
|
||||
Assert.equal(c2.contrastRatio(c3), 3.469474137806338, "Contrast between white and purple");
|
||||
}
|
||||
|
||||
function testIsContrastRatioAcceptable() {
|
||||
// Let's assert what browser.js is doing for window frames.
|
||||
let c = new Color(...[55, 156, 152]);
|
||||
let c2 = new Color(0, 0, 0);
|
||||
Assert.equal(c.r, 55, "Reds should match");
|
||||
Assert.equal(c.g, 156, "Greens should match");
|
||||
Assert.equal(c.b, 152, "Blues should match");
|
||||
Assert.ok(c.isContrastRatioAcceptable(c2), "The blue is high contrast enough");
|
||||
c = new Color(...[35, 65, 100]);
|
||||
Assert.ok(!c.isContrastRatioAcceptable(c2), "The blue is not high contrast enough");
|
||||
}
|
||||
|
|
@ -1,390 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* This file tests the DeferredTask.jsm module.
|
||||
*/
|
||||
|
||||
// Globals
|
||||
|
||||
var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask",
|
||||
"resource://gre/modules/DeferredTask.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
|
||||
/**
|
||||
* Due to the nature of this module, most of the tests are time-dependent. All
|
||||
* the timeouts are designed to occur at multiples of this granularity value,
|
||||
* in milliseconds, that should be high enough to prevent intermittent failures,
|
||||
* but low enough to prevent an excessive overall test execution time.
|
||||
*/
|
||||
const T = 100;
|
||||
|
||||
/**
|
||||
* Waits for the specified timeout before resolving the returned promise.
|
||||
*/
|
||||
function promiseTimeout(aTimeoutMs)
|
||||
{
|
||||
let deferred = Promise.defer();
|
||||
do_timeout(aTimeoutMs, deferred.resolve);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
// Tests
|
||||
|
||||
/**
|
||||
* Creates a simple DeferredTask and executes it once.
|
||||
*/
|
||||
add_test(function test_arm_simple()
|
||||
{
|
||||
new DeferredTask(run_next_test, 10).arm();
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that the delay set for the task is respected.
|
||||
*/
|
||||
add_test(function test_arm_delay_respected()
|
||||
{
|
||||
let executed1 = false;
|
||||
let executed2 = false;
|
||||
|
||||
new DeferredTask(function () {
|
||||
executed1 = true;
|
||||
do_check_false(executed2);
|
||||
}, 1*T).arm();
|
||||
|
||||
new DeferredTask(function () {
|
||||
executed2 = true;
|
||||
do_check_true(executed1);
|
||||
run_next_test();
|
||||
}, 2*T).arm();
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that calling "arm" again does not introduce further delay.
|
||||
*/
|
||||
add_test(function test_arm_delay_notrestarted()
|
||||
{
|
||||
let executed = false;
|
||||
|
||||
// Create a task that will run later.
|
||||
let deferredTask = new DeferredTask(() => { executed = true; }, 4*T);
|
||||
deferredTask.arm();
|
||||
|
||||
// Before the task starts, call "arm" again.
|
||||
do_timeout(2*T, () => deferredTask.arm());
|
||||
|
||||
// The "arm" call should not have introduced further delays.
|
||||
do_timeout(5*T, function () {
|
||||
do_check_true(executed);
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that a task runs only once when armed multiple times synchronously.
|
||||
*/
|
||||
add_test(function test_arm_coalesced()
|
||||
{
|
||||
let executed = false;
|
||||
|
||||
let deferredTask = new DeferredTask(function () {
|
||||
do_check_false(executed);
|
||||
executed = true;
|
||||
run_next_test();
|
||||
}, 50);
|
||||
|
||||
deferredTask.arm();
|
||||
deferredTask.arm();
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that a task runs only once when armed multiple times synchronously,
|
||||
* even when it has been created with a delay of zero milliseconds.
|
||||
*/
|
||||
add_test(function test_arm_coalesced_nodelay()
|
||||
{
|
||||
let executed = false;
|
||||
|
||||
let deferredTask = new DeferredTask(function () {
|
||||
do_check_false(executed);
|
||||
executed = true;
|
||||
run_next_test();
|
||||
}, 0);
|
||||
|
||||
deferredTask.arm();
|
||||
deferredTask.arm();
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that a task can be armed again while running.
|
||||
*/
|
||||
add_test(function test_arm_recursive()
|
||||
{
|
||||
let executed = false;
|
||||
|
||||
let deferredTask = new DeferredTask(function () {
|
||||
if (!executed) {
|
||||
executed = true;
|
||||
deferredTask.arm();
|
||||
} else {
|
||||
run_next_test();
|
||||
}
|
||||
}, 50);
|
||||
|
||||
deferredTask.arm();
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that calling "arm" while an asynchronous task is running waits until
|
||||
* the task is finished before restarting the delay.
|
||||
*/
|
||||
add_test(function test_arm_async()
|
||||
{
|
||||
let finishedExecution = false;
|
||||
let finishedExecutionAgain = false;
|
||||
|
||||
// Create a task that will run later.
|
||||
let deferredTask = new DeferredTask(function* () {
|
||||
yield promiseTimeout(4*T);
|
||||
if (!finishedExecution) {
|
||||
finishedExecution = true;
|
||||
} else if (!finishedExecutionAgain) {
|
||||
finishedExecutionAgain = true;
|
||||
}
|
||||
}, 2*T);
|
||||
deferredTask.arm();
|
||||
|
||||
// While the task is running, call "arm" again. This will result in a wait
|
||||
// of 2*T until the task finishes, then another 2*T for the normal task delay
|
||||
// specified on construction.
|
||||
do_timeout(4*T, function () {
|
||||
do_check_true(deferredTask.isRunning);
|
||||
do_check_false(finishedExecution);
|
||||
deferredTask.arm();
|
||||
});
|
||||
|
||||
// This will fail in case the task was started without waiting 2*T after it
|
||||
// has finished.
|
||||
do_timeout(7*T, function () {
|
||||
do_check_false(deferredTask.isRunning);
|
||||
do_check_true(finishedExecution);
|
||||
});
|
||||
|
||||
// This is in the middle of the second execution.
|
||||
do_timeout(10*T, function () {
|
||||
do_check_true(deferredTask.isRunning);
|
||||
do_check_false(finishedExecutionAgain);
|
||||
});
|
||||
|
||||
// Wait enough time to verify that the task was executed as expected.
|
||||
do_timeout(13*T, function () {
|
||||
do_check_false(deferredTask.isRunning);
|
||||
do_check_true(finishedExecutionAgain);
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that an armed task can be disarmed.
|
||||
*/
|
||||
add_test(function test_disarm()
|
||||
{
|
||||
// Create a task that will run later.
|
||||
let deferredTask = new DeferredTask(function () {
|
||||
do_throw("This task should not run.");
|
||||
}, 2*T);
|
||||
deferredTask.arm();
|
||||
|
||||
// Disable execution later, but before the task starts.
|
||||
do_timeout(1*T, () => deferredTask.disarm());
|
||||
|
||||
// Wait enough time to verify that the task did not run.
|
||||
do_timeout(3*T, run_next_test);
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that calling "disarm" allows the delay to be restarted.
|
||||
*/
|
||||
add_test(function test_disarm_delay_restarted()
|
||||
{
|
||||
let executed = false;
|
||||
|
||||
let deferredTask = new DeferredTask(() => { executed = true; }, 4*T);
|
||||
deferredTask.arm();
|
||||
|
||||
do_timeout(2*T, function () {
|
||||
deferredTask.disarm();
|
||||
deferredTask.arm();
|
||||
});
|
||||
|
||||
do_timeout(5*T, function () {
|
||||
do_check_false(executed);
|
||||
});
|
||||
|
||||
do_timeout(7*T, function () {
|
||||
do_check_true(executed);
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that calling "disarm" while an asynchronous task is running does not
|
||||
* prevent the task to finish.
|
||||
*/
|
||||
add_test(function test_disarm_async()
|
||||
{
|
||||
let finishedExecution = false;
|
||||
|
||||
let deferredTask = new DeferredTask(function* () {
|
||||
deferredTask.arm();
|
||||
yield promiseTimeout(2*T);
|
||||
finishedExecution = true;
|
||||
}, 1*T);
|
||||
deferredTask.arm();
|
||||
|
||||
do_timeout(2*T, function () {
|
||||
do_check_true(deferredTask.isRunning);
|
||||
do_check_true(deferredTask.isArmed);
|
||||
do_check_false(finishedExecution);
|
||||
deferredTask.disarm();
|
||||
});
|
||||
|
||||
do_timeout(4*T, function () {
|
||||
do_check_false(deferredTask.isRunning);
|
||||
do_check_false(deferredTask.isArmed);
|
||||
do_check_true(finishedExecution);
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that calling "arm" immediately followed by "disarm" while an
|
||||
* asynchronous task is running does not cause it to run again.
|
||||
*/
|
||||
add_test(function test_disarm_immediate_async()
|
||||
{
|
||||
let executed = false;
|
||||
|
||||
let deferredTask = new DeferredTask(function* () {
|
||||
do_check_false(executed);
|
||||
executed = true;
|
||||
yield promiseTimeout(2*T);
|
||||
}, 1*T);
|
||||
deferredTask.arm();
|
||||
|
||||
do_timeout(2*T, function () {
|
||||
do_check_true(deferredTask.isRunning);
|
||||
do_check_false(deferredTask.isArmed);
|
||||
deferredTask.arm();
|
||||
deferredTask.disarm();
|
||||
});
|
||||
|
||||
do_timeout(4*T, function () {
|
||||
do_check_true(executed);
|
||||
do_check_false(deferredTask.isRunning);
|
||||
do_check_false(deferredTask.isArmed);
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks the isArmed and isRunning properties with a synchronous task.
|
||||
*/
|
||||
add_test(function test_isArmed_isRunning()
|
||||
{
|
||||
let deferredTask = new DeferredTask(function () {
|
||||
do_check_true(deferredTask.isRunning);
|
||||
do_check_false(deferredTask.isArmed);
|
||||
deferredTask.arm();
|
||||
do_check_true(deferredTask.isArmed);
|
||||
deferredTask.disarm();
|
||||
do_check_false(deferredTask.isArmed);
|
||||
run_next_test();
|
||||
}, 50);
|
||||
|
||||
do_check_false(deferredTask.isArmed);
|
||||
deferredTask.arm();
|
||||
do_check_true(deferredTask.isArmed);
|
||||
do_check_false(deferredTask.isRunning);
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that the "finalize" method executes a synchronous task.
|
||||
*/
|
||||
add_test(function test_finalize()
|
||||
{
|
||||
let executed = false;
|
||||
let timePassed = false;
|
||||
|
||||
let deferredTask = new DeferredTask(function () {
|
||||
do_check_false(timePassed);
|
||||
executed = true;
|
||||
}, 2*T);
|
||||
deferredTask.arm();
|
||||
|
||||
do_timeout(1*T, () => { timePassed = true; });
|
||||
|
||||
// This should trigger the immediate execution of the task.
|
||||
deferredTask.finalize().then(function () {
|
||||
do_check_true(executed);
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that the "finalize" method executes the task again from start to
|
||||
* finish in case it is already running.
|
||||
*/
|
||||
add_test(function test_finalize_executes_entirely()
|
||||
{
|
||||
let executed = false;
|
||||
let executedAgain = false;
|
||||
let timePassed = false;
|
||||
|
||||
let deferredTask = new DeferredTask(function* () {
|
||||
// The first time, we arm the timer again and set up the finalization.
|
||||
if (!executed) {
|
||||
deferredTask.arm();
|
||||
do_check_true(deferredTask.isArmed);
|
||||
do_check_true(deferredTask.isRunning);
|
||||
|
||||
deferredTask.finalize().then(function () {
|
||||
// When we reach this point, the task must be finished.
|
||||
do_check_true(executedAgain);
|
||||
do_check_false(timePassed);
|
||||
do_check_false(deferredTask.isArmed);
|
||||
do_check_false(deferredTask.isRunning);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// The second execution triggered by the finalization waits 1*T for the
|
||||
// current task to finish (see the timeout below), but then it must not
|
||||
// wait for the 2*T specified on construction as normal task delay. The
|
||||
// second execution will finish after the timeout below has passed again,
|
||||
// for a total of 2*T of wait time.
|
||||
do_timeout(3*T, () => { timePassed = true; });
|
||||
}
|
||||
|
||||
yield promiseTimeout(1*T);
|
||||
|
||||
// Just before finishing, indicate if we completed the second execution.
|
||||
if (executed) {
|
||||
do_check_true(deferredTask.isRunning);
|
||||
executedAgain = true;
|
||||
} else {
|
||||
executed = true;
|
||||
}
|
||||
}, 2*T);
|
||||
|
||||
deferredTask.arm();
|
||||
});
|
||||
|
|
@ -1,226 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Components.utils.import("resource://gre/modules/FileUtils.jsm");
|
||||
|
||||
function do_check_throws(f, result, stack) {
|
||||
if (!stack)
|
||||
stack = Components.stack.caller;
|
||||
|
||||
try {
|
||||
f();
|
||||
} catch (exc) {
|
||||
if (exc.result == result)
|
||||
return;
|
||||
do_throw("expected result " + result + ", caught " + exc, stack);
|
||||
}
|
||||
do_throw("expected result " + result + ", none thrown", stack);
|
||||
}
|
||||
|
||||
const gProfD = do_get_profile();
|
||||
|
||||
add_test(function test_getFile() {
|
||||
let file = FileUtils.getFile("ProfD", ["foobar"]);
|
||||
do_check_true(file instanceof Components.interfaces.nsIFile);
|
||||
do_check_false(file.exists());
|
||||
|
||||
let other = gProfD.clone();
|
||||
other.append("foobar");
|
||||
do_check_true(file.equals(other));
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_getFile_nonexistentDir() {
|
||||
do_check_throws(function () {
|
||||
let file = FileUtils.getFile("NonexistentD", ["foobar"]);
|
||||
}, Components.results.NS_ERROR_FAILURE);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_getFile_createDirs() {
|
||||
let file = FileUtils.getFile("ProfD", ["a", "b", "foobar"]);
|
||||
do_check_true(file instanceof Components.interfaces.nsIFile);
|
||||
do_check_false(file.exists());
|
||||
|
||||
let other = gProfD.clone();
|
||||
other.append("a");
|
||||
do_check_true(other.isDirectory());
|
||||
other.append("b");
|
||||
do_check_true(other.isDirectory());
|
||||
other.append("foobar");
|
||||
do_check_true(file.equals(other));
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_getDir() {
|
||||
let dir = FileUtils.getDir("ProfD", ["foodir"]);
|
||||
do_check_true(dir instanceof Components.interfaces.nsIFile);
|
||||
do_check_false(dir.exists());
|
||||
|
||||
let other = gProfD.clone();
|
||||
other.append("foodir");
|
||||
do_check_true(dir.equals(other));
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_getDir_nonexistentDir() {
|
||||
do_check_throws(function () {
|
||||
let file = FileUtils.getDir("NonexistentD", ["foodir"]);
|
||||
}, Components.results.NS_ERROR_FAILURE);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_getDir_shouldCreate() {
|
||||
let dir = FileUtils.getDir("ProfD", ["c", "d", "foodir"], true);
|
||||
do_check_true(dir instanceof Components.interfaces.nsIFile);
|
||||
do_check_true(dir.exists());
|
||||
|
||||
let other = gProfD.clone();
|
||||
other.append("c");
|
||||
do_check_true(other.isDirectory());
|
||||
other.append("d");
|
||||
do_check_true(other.isDirectory());
|
||||
other.append("foodir");
|
||||
do_check_true(dir.equals(other));
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
var openFileOutputStream_defaultFlags = function (aKind, aFileName) {
|
||||
let file = FileUtils.getFile("ProfD", [aFileName]);
|
||||
let fos;
|
||||
do_check_true(aKind == "atomic" || aKind == "safe" || aKind == "");
|
||||
if (aKind == "atomic") {
|
||||
fos = FileUtils.openAtomicFileOutputStream(file);
|
||||
} else if (aKind == "safe") {
|
||||
fos = FileUtils.openSafeFileOutputStream(file);
|
||||
} else {
|
||||
fos = FileUtils.openFileOutputStream(file);
|
||||
}
|
||||
do_check_true(fos instanceof Components.interfaces.nsIFileOutputStream);
|
||||
if (aKind == "atomic" || aKind == "safe") {
|
||||
do_check_true(fos instanceof Components.interfaces.nsISafeOutputStream);
|
||||
}
|
||||
|
||||
// FileUtils.openFileOutputStream or FileUtils.openAtomicFileOutputStream()
|
||||
// or FileUtils.openSafeFileOutputStream() opens the stream with DEFER_OPEN
|
||||
// which means the file will not be open until we write to it.
|
||||
do_check_false(file.exists());
|
||||
|
||||
let data = "test_default_flags";
|
||||
fos.write(data, data.length);
|
||||
do_check_true(file.exists());
|
||||
|
||||
// No nsIXULRuntime in xpcshell, so use this trick to determine whether we're
|
||||
// on Windows.
|
||||
if ("@mozilla.org/windows-registry-key;1" in Components.classes) {
|
||||
do_check_eq(file.permissions, 0o666);
|
||||
} else {
|
||||
do_check_eq(file.permissions, FileUtils.PERMS_FILE);
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
};
|
||||
|
||||
var openFileOutputStream_modeFlags = function(aKind, aFileName) {
|
||||
let file = FileUtils.getFile("ProfD", [aFileName]);
|
||||
let fos;
|
||||
do_check_true(aKind == "atomic" || aKind == "safe" || aKind == "");
|
||||
if (aKind == "atomic") {
|
||||
fos = FileUtils.openAtomicFileOutputStream(file, FileUtils.MODE_WRONLY);
|
||||
} else if (aKind == "safe") {
|
||||
fos = FileUtils.openSafeFileOutputStream(file, FileUtils.MODE_WRONLY);
|
||||
} else {
|
||||
fos = FileUtils.openFileOutputStream(file, FileUtils.MODE_WRONLY);
|
||||
}
|
||||
let data = "test_modeFlags";
|
||||
do_check_throws(function () {
|
||||
fos.write(data, data.length);
|
||||
}, Components.results.NS_ERROR_FILE_NOT_FOUND);
|
||||
do_check_false(file.exists());
|
||||
|
||||
run_next_test();
|
||||
};
|
||||
|
||||
var closeFileOutputStream = function(aKind, aFileName) {
|
||||
let file = FileUtils.getFile("ProfD", [aFileName]);
|
||||
let fos;
|
||||
do_check_true(aKind == "atomic" || aKind == "safe");
|
||||
if (aKind == "atomic") {
|
||||
fos = FileUtils.openAtomicFileOutputStream(file);
|
||||
} else if (aKind == "safe") {
|
||||
fos = FileUtils.openSafeFileOutputStream(file);
|
||||
}
|
||||
|
||||
// We can write data to the stream just fine while it's open.
|
||||
let data = "testClose";
|
||||
fos.write(data, data.length);
|
||||
|
||||
// But once we close it, we can't anymore.
|
||||
if (aKind == "atomic") {
|
||||
FileUtils.closeAtomicFileOutputStream(fos);
|
||||
} else if (aKind == "safe") {
|
||||
FileUtils.closeSafeFileOutputStream(fos);
|
||||
}
|
||||
do_check_throws(function () {
|
||||
fos.write(data, data.length);
|
||||
}, Components.results.NS_BASE_STREAM_CLOSED);
|
||||
run_next_test();
|
||||
};
|
||||
|
||||
add_test(function test_openFileOutputStream_defaultFlags() {
|
||||
openFileOutputStream_defaultFlags("", "george");
|
||||
});
|
||||
|
||||
// openFileOutputStream will uses MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE
|
||||
// as the default mode flags, but we can pass in our own if we want to.
|
||||
add_test(function test_openFileOutputStream_modeFlags() {
|
||||
openFileOutputStream_modeFlags("", "ringo");
|
||||
});
|
||||
|
||||
add_test(function test_openAtomicFileOutputStream_defaultFlags() {
|
||||
openFileOutputStream_defaultFlags("atomic", "peiyong");
|
||||
});
|
||||
|
||||
// openAtomicFileOutputStream will uses MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE
|
||||
// as the default mode flags, but we can pass in our own if we want to.
|
||||
add_test(function test_openAtomicFileOutputStream_modeFlags() {
|
||||
openFileOutputStream_modeFlags("atomic", "lin");
|
||||
});
|
||||
|
||||
add_test(function test_closeAtomicFileOutputStream() {
|
||||
closeFileOutputStream("atomic", "peiyonglin");
|
||||
});
|
||||
|
||||
add_test(function test_openSafeFileOutputStream_defaultFlags() {
|
||||
openFileOutputStream_defaultFlags("safe", "john");
|
||||
});
|
||||
|
||||
// openSafeFileOutputStream will uses MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE
|
||||
// as the default mode flags, but we can pass in our own if we want to.
|
||||
add_test(function test_openSafeFileOutputStream_modeFlags() {
|
||||
openFileOutputStream_modeFlags("safe", "paul");
|
||||
});
|
||||
|
||||
add_test(function test_closeSafeFileOutputStream() {
|
||||
closeFileOutputStream("safe", "georgee");
|
||||
});
|
||||
|
||||
add_test(function test_newFile() {
|
||||
let testfile = FileUtils.getFile("ProfD", ["test"]);
|
||||
let testpath = testfile.path;
|
||||
let file = new FileUtils.File(testpath);
|
||||
do_check_true(file instanceof Components.interfaces.nsILocalFile);
|
||||
do_check_true(file.equals(testfile));
|
||||
do_check_eq(file.path, testpath);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
|
@ -1,265 +0,0 @@
|
|||
const { interfaces: Ci, classes: Cc, utils: Cu } = Components;
|
||||
const { FinderIterator } = Cu.import("resource://gre/modules/FinderIterator.jsm", {});
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
|
||||
var gFindResults = [];
|
||||
// Stub the method that instantiates nsIFind and does all the interaction with
|
||||
// the docShell to be searched through.
|
||||
FinderIterator._iterateDocument = function* (word, window, finder) {
|
||||
for (let range of gFindResults)
|
||||
yield range;
|
||||
};
|
||||
|
||||
FinderIterator._rangeStartsInLink = fakeRange => fakeRange.startsInLink;
|
||||
|
||||
function FakeRange(textContent, startsInLink = false) {
|
||||
this.startContainer = {};
|
||||
this.startsInLink = startsInLink;
|
||||
this.toString = () => textContent;
|
||||
}
|
||||
|
||||
var gMockWindow = {
|
||||
setTimeout(cb, delay) {
|
||||
Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer)
|
||||
.initWithCallback(cb, delay, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
}
|
||||
};
|
||||
|
||||
var gMockFinder = {
|
||||
_getWindow() { return gMockWindow; }
|
||||
};
|
||||
|
||||
function prepareIterator(findText, rangeCount) {
|
||||
gFindResults = [];
|
||||
for (let i = rangeCount; --i >= 0;)
|
||||
gFindResults.push(new FakeRange(findText));
|
||||
}
|
||||
|
||||
add_task(function* test_start() {
|
||||
let findText = "test";
|
||||
let rangeCount = 300;
|
||||
prepareIterator(findText, rangeCount);
|
||||
|
||||
let count = 0;
|
||||
yield FinderIterator.start({
|
||||
caseSensitive: false,
|
||||
entireWord: false,
|
||||
finder: gMockFinder,
|
||||
listener: {
|
||||
onIteratorRangeFound(range) {
|
||||
++count;
|
||||
Assert.equal(range.toString(), findText, "Text content should match");
|
||||
}
|
||||
},
|
||||
word: findText
|
||||
});
|
||||
|
||||
Assert.equal(rangeCount, count, "Amount of ranges yielded should match!");
|
||||
Assert.ok(!FinderIterator.running, "Running state should match");
|
||||
Assert.equal(FinderIterator._previousRanges.length, rangeCount, "Ranges cache should match");
|
||||
|
||||
FinderIterator.reset();
|
||||
});
|
||||
|
||||
add_task(function* test_valid_arguments() {
|
||||
let findText = "foo";
|
||||
let rangeCount = 20;
|
||||
prepareIterator(findText, rangeCount);
|
||||
|
||||
let count = 0;
|
||||
|
||||
yield FinderIterator.start({
|
||||
caseSensitive: false,
|
||||
entireWord: false,
|
||||
finder: gMockFinder,
|
||||
listener: { onIteratorRangeFound(range) { ++count; } },
|
||||
word: findText
|
||||
});
|
||||
|
||||
let params = FinderIterator._previousParams;
|
||||
Assert.ok(!params.linksOnly, "Default for linksOnly is false");
|
||||
Assert.ok(!params.useCache, "Default for useCache is false");
|
||||
Assert.equal(params.word, findText, "Words should match");
|
||||
|
||||
count = 0;
|
||||
Assert.throws(() => FinderIterator.start({
|
||||
entireWord: false,
|
||||
listener: { onIteratorRangeFound(range) { ++count; } },
|
||||
word: findText
|
||||
}), /Missing required option 'caseSensitive'/, "Should throw when missing an argument");
|
||||
FinderIterator.reset();
|
||||
|
||||
Assert.throws(() => FinderIterator.start({
|
||||
caseSensitive: false,
|
||||
listener: { onIteratorRangeFound(range) { ++count; } },
|
||||
word: findText
|
||||
}), /Missing required option 'entireWord'/, "Should throw when missing an argument");
|
||||
FinderIterator.reset();
|
||||
|
||||
Assert.throws(() => FinderIterator.start({
|
||||
caseSensitive: false,
|
||||
entireWord: false,
|
||||
listener: { onIteratorRangeFound(range) { ++count; } },
|
||||
word: findText
|
||||
}), /Missing required option 'finder'/, "Should throw when missing an argument");
|
||||
FinderIterator.reset();
|
||||
|
||||
Assert.throws(() => FinderIterator.start({
|
||||
caseSensitive: true,
|
||||
entireWord: false,
|
||||
finder: gMockFinder,
|
||||
word: findText
|
||||
}), /Missing valid, required option 'listener'/, "Should throw when missing an argument");
|
||||
FinderIterator.reset();
|
||||
|
||||
Assert.throws(() => FinderIterator.start({
|
||||
caseSensitive: false,
|
||||
entireWord: true,
|
||||
finder: gMockFinder,
|
||||
listener: { onIteratorRangeFound(range) { ++count; } },
|
||||
}), /Missing required option 'word'/, "Should throw when missing an argument");
|
||||
FinderIterator.reset();
|
||||
|
||||
Assert.equal(count, 0, "No ranges should've been counted");
|
||||
});
|
||||
|
||||
add_task(function* test_stop() {
|
||||
let findText = "bar";
|
||||
let rangeCount = 120;
|
||||
prepareIterator(findText, rangeCount);
|
||||
|
||||
let count = 0;
|
||||
let whenDone = FinderIterator.start({
|
||||
caseSensitive: false,
|
||||
entireWord: false,
|
||||
finder: gMockFinder,
|
||||
listener: { onIteratorRangeFound(range) { ++count; } },
|
||||
word: findText
|
||||
});
|
||||
|
||||
FinderIterator.stop();
|
||||
|
||||
yield whenDone;
|
||||
|
||||
Assert.equal(count, 0, "Number of ranges should be 0");
|
||||
|
||||
FinderIterator.reset();
|
||||
});
|
||||
|
||||
add_task(function* test_reset() {
|
||||
let findText = "tik";
|
||||
let rangeCount = 142;
|
||||
prepareIterator(findText, rangeCount);
|
||||
|
||||
let count = 0;
|
||||
let whenDone = FinderIterator.start({
|
||||
caseSensitive: false,
|
||||
entireWord: false,
|
||||
finder: gMockFinder,
|
||||
listener: { onIteratorRangeFound(range) { ++count; } },
|
||||
word: findText
|
||||
});
|
||||
|
||||
Assert.ok(FinderIterator.running, "Yup, running we are");
|
||||
Assert.equal(count, 0, "Number of ranges should match 0");
|
||||
Assert.equal(FinderIterator.ranges.length, 0, "Number of ranges should match 0");
|
||||
|
||||
FinderIterator.reset();
|
||||
|
||||
Assert.ok(!FinderIterator.running, "Nope, running we are not");
|
||||
Assert.equal(FinderIterator.ranges.length, 0, "No ranges after reset");
|
||||
Assert.equal(FinderIterator._previousRanges.length, 0, "No ranges after reset");
|
||||
|
||||
yield whenDone;
|
||||
|
||||
Assert.equal(count, 0, "Number of ranges should match 0");
|
||||
});
|
||||
|
||||
add_task(function* test_parallel_starts() {
|
||||
let findText = "tak";
|
||||
let rangeCount = 2143;
|
||||
prepareIterator(findText, rangeCount);
|
||||
|
||||
// Start off the iterator.
|
||||
let count = 0;
|
||||
let whenDone = FinderIterator.start({
|
||||
caseSensitive: false,
|
||||
entireWord: false,
|
||||
finder: gMockFinder,
|
||||
listener: { onIteratorRangeFound(range) { ++count; } },
|
||||
word: findText
|
||||
});
|
||||
|
||||
yield new Promise(resolve => gMockWindow.setTimeout(resolve, 120));
|
||||
Assert.ok(FinderIterator.running, "We ought to be running here");
|
||||
|
||||
let count2 = 0;
|
||||
let whenDone2 = FinderIterator.start({
|
||||
caseSensitive: false,
|
||||
entireWord: false,
|
||||
finder: gMockFinder,
|
||||
listener: { onIteratorRangeFound(range) { ++count2; } },
|
||||
word: findText
|
||||
});
|
||||
|
||||
// Let the iterator run for a little while longer before we assert the world.
|
||||
yield new Promise(resolve => gMockWindow.setTimeout(resolve, 10));
|
||||
FinderIterator.stop();
|
||||
|
||||
Assert.ok(!FinderIterator.running, "Stop means stop");
|
||||
|
||||
yield whenDone;
|
||||
yield whenDone2;
|
||||
|
||||
Assert.greater(count, FinderIterator.kIterationSizeMax, "At least one range should've been found");
|
||||
Assert.less(count, rangeCount, "Not all ranges should've been found");
|
||||
Assert.greater(count2, FinderIterator.kIterationSizeMax, "At least one range should've been found");
|
||||
Assert.less(count2, rangeCount, "Not all ranges should've been found");
|
||||
|
||||
Assert.equal(count2, count, "The second start was later, but should have caught up");
|
||||
|
||||
FinderIterator.reset();
|
||||
});
|
||||
|
||||
add_task(function* test_allowDistance() {
|
||||
let findText = "gup";
|
||||
let rangeCount = 20;
|
||||
prepareIterator(findText, rangeCount);
|
||||
|
||||
// Start off the iterator.
|
||||
let count = 0;
|
||||
let whenDone = FinderIterator.start({
|
||||
caseSensitive: false,
|
||||
entireWord: false,
|
||||
finder: gMockFinder,
|
||||
listener: { onIteratorRangeFound(range) { ++count; } },
|
||||
word: findText
|
||||
});
|
||||
|
||||
let count2 = 0;
|
||||
let whenDone2 = FinderIterator.start({
|
||||
caseSensitive: false,
|
||||
entireWord: false,
|
||||
finder: gMockFinder,
|
||||
listener: { onIteratorRangeFound(range) { ++count2; } },
|
||||
word: "gu"
|
||||
});
|
||||
|
||||
let count3 = 0;
|
||||
let whenDone3 = FinderIterator.start({
|
||||
allowDistance: 1,
|
||||
caseSensitive: false,
|
||||
entireWord: false,
|
||||
finder: gMockFinder,
|
||||
listener: { onIteratorRangeFound(range) { ++count3; } },
|
||||
word: "gu"
|
||||
});
|
||||
|
||||
yield Promise.all([whenDone, whenDone2, whenDone3]);
|
||||
|
||||
Assert.equal(count, rangeCount, "The first iterator invocation should yield all results");
|
||||
Assert.equal(count2, 0, "The second iterator invocation should yield _no_ results");
|
||||
Assert.equal(count3, rangeCount, "The first iterator invocation should yield all results");
|
||||
|
||||
FinderIterator.reset();
|
||||
});
|
||||
|
|
@ -1,794 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
var {classes: Cc, interfaces: Ci, results: Cr, utils: Cu, manager: Cm} = Components;
|
||||
const URL_HOST = "http://localhost";
|
||||
|
||||
var GMPScope = Cu.import("resource://gre/modules/GMPInstallManager.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||
Cu.import("resource://testing-common/httpd.js");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/Preferences.jsm")
|
||||
Cu.import("resource://gre/modules/UpdateUtils.jsm");
|
||||
|
||||
var { computeHash } = Cu.import("resource://gre/modules/addons/ProductAddonChecker.jsm");
|
||||
var ProductAddonCheckerScope = Cu.import("resource://gre/modules/addons/ProductAddonChecker.jsm");
|
||||
|
||||
do_get_profile();
|
||||
|
||||
function run_test() { Cu.import("resource://gre/modules/Preferences.jsm")
|
||||
Preferences.set("media.gmp.log.dump", true);
|
||||
Preferences.set("media.gmp.log.level", 0);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the helper used for preferences works correctly
|
||||
*/
|
||||
add_task(function* test_prefs() {
|
||||
let addon1 = "addon1", addon2 = "addon2";
|
||||
|
||||
GMPScope.GMPPrefs.set(GMPScope.GMPPrefs.KEY_URL, "http://not-really-used");
|
||||
GMPScope.GMPPrefs.set(GMPScope.GMPPrefs.KEY_URL_OVERRIDE, "http://not-really-used-2");
|
||||
GMPScope.GMPPrefs.set(GMPScope.GMPPrefs.KEY_PLUGIN_LAST_UPDATE, "1", addon1);
|
||||
GMPScope.GMPPrefs.set(GMPScope.GMPPrefs.KEY_PLUGIN_VERSION, "2", addon1);
|
||||
GMPScope.GMPPrefs.set(GMPScope.GMPPrefs.KEY_PLUGIN_LAST_UPDATE, "3", addon2);
|
||||
GMPScope.GMPPrefs.set(GMPScope.GMPPrefs.KEY_PLUGIN_VERSION, "4", addon2);
|
||||
GMPScope.GMPPrefs.set(GMPScope.GMPPrefs.KEY_PLUGIN_AUTOUPDATE, false, addon2);
|
||||
GMPScope.GMPPrefs.set(GMPScope.GMPPrefs.KEY_CERT_CHECKATTRS, true);
|
||||
|
||||
do_check_eq(GMPScope.GMPPrefs.get(GMPScope.GMPPrefs.KEY_URL), "http://not-really-used");
|
||||
do_check_eq(GMPScope.GMPPrefs.get(GMPScope.GMPPrefs.KEY_URL_OVERRIDE),
|
||||
"http://not-really-used-2");
|
||||
do_check_eq(GMPScope.GMPPrefs.get(GMPScope.GMPPrefs.KEY_PLUGIN_LAST_UPDATE, "", addon1), "1");
|
||||
do_check_eq(GMPScope.GMPPrefs.get(GMPScope.GMPPrefs.KEY_PLUGIN_VERSION, "", addon1), "2");
|
||||
do_check_eq(GMPScope.GMPPrefs.get(GMPScope.GMPPrefs.KEY_PLUGIN_LAST_UPDATE, "", addon2), "3");
|
||||
do_check_eq(GMPScope.GMPPrefs.get(GMPScope.GMPPrefs.KEY_PLUGIN_VERSION, "", addon2), "4");
|
||||
do_check_eq(GMPScope.GMPPrefs.get(GMPScope.GMPPrefs.KEY_PLUGIN_AUTOUPDATE, undefined, addon2),
|
||||
false);
|
||||
do_check_true(GMPScope.GMPPrefs.get(GMPScope.GMPPrefs.KEY_CERT_CHECKATTRS));
|
||||
GMPScope.GMPPrefs.set(GMPScope.GMPPrefs.KEY_PLUGIN_AUTOUPDATE, true, addon2);
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that an uninit without a check works fine
|
||||
*/
|
||||
add_task(function* test_checkForAddons_uninitWithoutCheck() {
|
||||
let installManager = new GMPInstallManager();
|
||||
installManager.uninit();
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that an uninit without an install works fine
|
||||
*/
|
||||
add_test(function test_checkForAddons_uninitWithoutInstall() {
|
||||
overrideXHR(200, "");
|
||||
let installManager = new GMPInstallManager();
|
||||
let promise = installManager.checkForAddons();
|
||||
promise.then(res => {
|
||||
do_check_true(res.usedFallback);
|
||||
installManager.uninit();
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that no response returned rejects
|
||||
*/
|
||||
add_test(function test_checkForAddons_noResponse() {
|
||||
overrideXHR(200, "");
|
||||
let installManager = new GMPInstallManager();
|
||||
let promise = installManager.checkForAddons();
|
||||
promise.then(res => {
|
||||
do_check_true(res.usedFallback);
|
||||
installManager.uninit();
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that no addons element returned resolves with no addons
|
||||
*/
|
||||
add_task(function* test_checkForAddons_noAddonsElement() {
|
||||
overrideXHR(200, "<updates></updates>");
|
||||
let installManager = new GMPInstallManager();
|
||||
let res = yield installManager.checkForAddons();
|
||||
do_check_eq(res.gmpAddons.length, 0);
|
||||
installManager.uninit();
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that empty addons element returned resolves with no addons
|
||||
*/
|
||||
add_task(function* test_checkForAddons_emptyAddonsElement() {
|
||||
overrideXHR(200, "<updates><addons/></updates>");
|
||||
let installManager = new GMPInstallManager();
|
||||
let res = yield installManager.checkForAddons();
|
||||
do_check_eq(res.gmpAddons.length, 0);
|
||||
installManager.uninit();
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that a response with the wrong root element rejects
|
||||
*/
|
||||
add_test(function test_checkForAddons_wrongResponseXML() {
|
||||
overrideXHR(200, "<digits_of_pi>3.141592653589793....</digits_of_pi>");
|
||||
let installManager = new GMPInstallManager();
|
||||
let promise = installManager.checkForAddons();
|
||||
promise.then(res => {
|
||||
do_check_true(res.usedFallback);
|
||||
installManager.uninit();
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that a 404 error works as expected
|
||||
*/
|
||||
add_test(function test_checkForAddons_404Error() {
|
||||
overrideXHR(404, "");
|
||||
let installManager = new GMPInstallManager();
|
||||
let promise = installManager.checkForAddons();
|
||||
promise.then(res => {
|
||||
do_check_true(res.usedFallback);
|
||||
installManager.uninit();
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that a xhr abort() works as expected
|
||||
*/
|
||||
add_test(function test_checkForAddons_abort() {
|
||||
let overriddenXhr = overrideXHR(200, "", { dropRequest: true} );
|
||||
let installManager = new GMPInstallManager();
|
||||
let promise = installManager.checkForAddons();
|
||||
overriddenXhr.abort();
|
||||
promise.then(res => {
|
||||
do_check_true(res.usedFallback);
|
||||
installManager.uninit();
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that a defensive timeout works as expected
|
||||
*/
|
||||
add_test(function test_checkForAddons_timeout() {
|
||||
overrideXHR(200, "", { dropRequest: true, timeout: true });
|
||||
let installManager = new GMPInstallManager();
|
||||
let promise = installManager.checkForAddons();
|
||||
promise.then(res => {
|
||||
do_check_true(res.usedFallback);
|
||||
installManager.uninit();
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that we throw correctly in case of ssl certification error.
|
||||
*/
|
||||
add_test(function test_checkForAddons_bad_ssl() {
|
||||
//
|
||||
// Add random stuff that cause CertUtil to require https.
|
||||
//
|
||||
let PREF_KEY_URL_OVERRIDE_BACKUP =
|
||||
Preferences.get(GMPScope.GMPPrefs.KEY_URL_OVERRIDE, undefined);
|
||||
Preferences.reset(GMPScope.GMPPrefs.KEY_URL_OVERRIDE);
|
||||
|
||||
let CERTS_BRANCH_DOT_ONE = GMPScope.GMPPrefs.KEY_CERTS_BRANCH + ".1";
|
||||
let PREF_CERTS_BRANCH_DOT_ONE_BACKUP =
|
||||
Preferences.get(CERTS_BRANCH_DOT_ONE, undefined);
|
||||
Services.prefs.setCharPref(CERTS_BRANCH_DOT_ONE, "funky value");
|
||||
|
||||
|
||||
overrideXHR(200, "");
|
||||
let installManager = new GMPInstallManager();
|
||||
let promise = installManager.checkForAddons();
|
||||
promise.then(res => {
|
||||
do_check_true(res.usedFallback);
|
||||
installManager.uninit();
|
||||
if (PREF_KEY_URL_OVERRIDE_BACKUP) {
|
||||
Preferences.set(GMPScope.GMPPrefs.KEY_URL_OVERRIDE,
|
||||
PREF_KEY_URL_OVERRIDE_BACKUP);
|
||||
}
|
||||
if (PREF_CERTS_BRANCH_DOT_ONE_BACKUP) {
|
||||
Preferences.set(CERTS_BRANCH_DOT_ONE,
|
||||
PREF_CERTS_BRANCH_DOT_ONE_BACKUP);
|
||||
}
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that gettinga a funky non XML response works as expected
|
||||
*/
|
||||
add_test(function test_checkForAddons_notXML() {
|
||||
overrideXHR(200, "3.141592653589793....");
|
||||
let installManager = new GMPInstallManager();
|
||||
let promise = installManager.checkForAddons();
|
||||
|
||||
promise.then(res => {
|
||||
do_check_true(res.usedFallback);
|
||||
installManager.uninit();
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that getting a response with a single addon works as expected
|
||||
*/
|
||||
add_task(function* test_checkForAddons_singleAddon() {
|
||||
let responseXML =
|
||||
"<?xml version=\"1.0\"?>" +
|
||||
"<updates>" +
|
||||
" <addons>" +
|
||||
" <addon id=\"gmp-gmpopenh264\"" +
|
||||
" URL=\"http://127.0.0.1:8011/gmp-gmpopenh264-1.1.zip\"" +
|
||||
" hashFunction=\"sha256\"" +
|
||||
" hashValue=\"1118b90d6f645eefc2b99af17bae396636ace1e33d079c88de715177584e2aee\"" +
|
||||
" version=\"1.1\"/>" +
|
||||
" </addons>" +
|
||||
"</updates>"
|
||||
overrideXHR(200, responseXML);
|
||||
let installManager = new GMPInstallManager();
|
||||
let res = yield installManager.checkForAddons();
|
||||
do_check_eq(res.gmpAddons.length, 1);
|
||||
let gmpAddon = res.gmpAddons[0];
|
||||
do_check_eq(gmpAddon.id, "gmp-gmpopenh264");
|
||||
do_check_eq(gmpAddon.URL, "http://127.0.0.1:8011/gmp-gmpopenh264-1.1.zip");
|
||||
do_check_eq(gmpAddon.hashFunction, "sha256");
|
||||
do_check_eq(gmpAddon.hashValue, "1118b90d6f645eefc2b99af17bae396636ace1e33d079c88de715177584e2aee");
|
||||
do_check_eq(gmpAddon.version, "1.1");
|
||||
do_check_eq(gmpAddon.size, undefined);
|
||||
do_check_true(gmpAddon.isValid);
|
||||
do_check_false(gmpAddon.isInstalled);
|
||||
installManager.uninit();
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that getting a response with a single addon with the optional size
|
||||
* attribute parses as expected.
|
||||
*/
|
||||
add_task(function* test_checkForAddons_singleAddonWithSize() {
|
||||
let responseXML =
|
||||
"<?xml version=\"1.0\"?>" +
|
||||
"<updates>" +
|
||||
" <addons>" +
|
||||
" <addon id=\"openh264-plugin-no-at-symbol\"" +
|
||||
" URL=\"http://127.0.0.1:8011/gmp-gmpopenh264-1.1.zip\"" +
|
||||
" hashFunction=\"sha256\"" +
|
||||
" size=\"42\"" +
|
||||
" hashValue=\"1118b90d6f645eefc2b99af17bae396636ace1e33d079c88de715177584e2aee\"" +
|
||||
" version=\"1.1\"/>" +
|
||||
" </addons>" +
|
||||
"</updates>"
|
||||
overrideXHR(200, responseXML);
|
||||
let installManager = new GMPInstallManager();
|
||||
let res = yield installManager.checkForAddons();
|
||||
do_check_eq(res.gmpAddons.length, 1);
|
||||
let gmpAddon = res.gmpAddons[0];
|
||||
do_check_eq(gmpAddon.id, "openh264-plugin-no-at-symbol");
|
||||
do_check_eq(gmpAddon.URL, "http://127.0.0.1:8011/gmp-gmpopenh264-1.1.zip");
|
||||
do_check_eq(gmpAddon.hashFunction, "sha256");
|
||||
do_check_eq(gmpAddon.hashValue, "1118b90d6f645eefc2b99af17bae396636ace1e33d079c88de715177584e2aee");
|
||||
do_check_eq(gmpAddon.size, 42);
|
||||
do_check_eq(gmpAddon.version, "1.1");
|
||||
do_check_true(gmpAddon.isValid);
|
||||
do_check_false(gmpAddon.isInstalled);
|
||||
installManager.uninit();
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that checking for multiple addons work correctly.
|
||||
* Also tests that invalid addons work correctly.
|
||||
*/
|
||||
add_task(function* test_checkForAddons_multipleAddonNoUpdatesSomeInvalid() {
|
||||
let responseXML =
|
||||
"<?xml version=\"1.0\"?>" +
|
||||
"<updates>" +
|
||||
" <addons>" +
|
||||
// valid openh264
|
||||
" <addon id=\"gmp-gmpopenh264\"" +
|
||||
" URL=\"http://127.0.0.1:8011/gmp-gmpopenh264-1.1.zip\"" +
|
||||
" hashFunction=\"sha256\"" +
|
||||
" hashValue=\"1118b90d6f645eefc2b99af17bae396636ace1e33d079c88de715177584e2aee\"" +
|
||||
" version=\"1.1\"/>" +
|
||||
// valid not openh264
|
||||
" <addon id=\"NOT-gmp-gmpopenh264\"" +
|
||||
" URL=\"http://127.0.0.1:8011/NOT-gmp-gmpopenh264-1.1.zip\"" +
|
||||
" hashFunction=\"sha512\"" +
|
||||
" hashValue=\"141592656f645eefc2b99af17bae396636ace1e33d079c88de715177584e2aee\"" +
|
||||
" version=\"9.1\"/>" +
|
||||
// noid
|
||||
" <addon notid=\"NOT-gmp-gmpopenh264\"" +
|
||||
" URL=\"http://127.0.0.1:8011/NOT-gmp-gmpopenh264-1.1.zip\"" +
|
||||
" hashFunction=\"sha512\"" +
|
||||
" hashValue=\"141592656f645eefc2b99af17bae396636ace1e33d079c88de715177584e2aee\"" +
|
||||
" version=\"9.1\"/>" +
|
||||
// no URL
|
||||
" <addon id=\"NOT-gmp-gmpopenh264\"" +
|
||||
" notURL=\"http://127.0.0.1:8011/NOT-gmp-gmpopenh264-1.1.zip\"" +
|
||||
" hashFunction=\"sha512\"" +
|
||||
" hashValue=\"141592656f645eefc2b99af17bae396636ace1e33d079c88de715177584e2aee\"" +
|
||||
" version=\"9.1\"/>" +
|
||||
// no hash function
|
||||
" <addon id=\"NOT-gmp-gmpopenh264\"" +
|
||||
" URL=\"http://127.0.0.1:8011/NOT-gmp-gmpopenh264-1.1.zip\"" +
|
||||
" nothashFunction=\"sha512\"" +
|
||||
" hashValue=\"141592656f645eefc2b99af17bae396636ace1e33d079c88de715177584e2aee\"" +
|
||||
" version=\"9.1\"/>" +
|
||||
// no hash function
|
||||
" <addon id=\"NOT-gmp-gmpopenh264\"" +
|
||||
" URL=\"http://127.0.0.1:8011/NOT-gmp-gmpopenh264-1.1.zip\"" +
|
||||
" hashFunction=\"sha512\"" +
|
||||
" nothashValue=\"141592656f645eefc2b99af17bae396636ace1e33d079c88de715177584e2aee\"" +
|
||||
" version=\"9.1\"/>" +
|
||||
// not version
|
||||
" <addon id=\"NOT-gmp-gmpopenh264\"" +
|
||||
" URL=\"http://127.0.0.1:8011/NOT-gmp-gmpopenh264-1.1.zip\"" +
|
||||
" hashFunction=\"sha512\"" +
|
||||
" hashValue=\"141592656f645eefc2b99af17bae396636ace1e33d079c88de715177584e2aee\"" +
|
||||
" notversion=\"9.1\"/>" +
|
||||
" </addons>" +
|
||||
"</updates>"
|
||||
overrideXHR(200, responseXML);
|
||||
let installManager = new GMPInstallManager();
|
||||
let res = yield installManager.checkForAddons();
|
||||
do_check_eq(res.gmpAddons.length, 7);
|
||||
let gmpAddon = res.gmpAddons[0];
|
||||
do_check_eq(gmpAddon.id, "gmp-gmpopenh264");
|
||||
do_check_eq(gmpAddon.URL, "http://127.0.0.1:8011/gmp-gmpopenh264-1.1.zip");
|
||||
do_check_eq(gmpAddon.hashFunction, "sha256");
|
||||
do_check_eq(gmpAddon.hashValue, "1118b90d6f645eefc2b99af17bae396636ace1e33d079c88de715177584e2aee");
|
||||
do_check_eq(gmpAddon.version, "1.1");
|
||||
do_check_true(gmpAddon.isValid);
|
||||
do_check_false(gmpAddon.isInstalled);
|
||||
|
||||
gmpAddon = res.gmpAddons[1];
|
||||
do_check_eq(gmpAddon.id, "NOT-gmp-gmpopenh264");
|
||||
do_check_eq(gmpAddon.URL, "http://127.0.0.1:8011/NOT-gmp-gmpopenh264-1.1.zip");
|
||||
do_check_eq(gmpAddon.hashFunction, "sha512");
|
||||
do_check_eq(gmpAddon.hashValue, "141592656f645eefc2b99af17bae396636ace1e33d079c88de715177584e2aee");
|
||||
do_check_eq(gmpAddon.version, "9.1");
|
||||
do_check_true(gmpAddon.isValid);
|
||||
do_check_false(gmpAddon.isInstalled);
|
||||
|
||||
for (let i = 2; i < res.gmpAddons.length; i++) {
|
||||
do_check_false(res.gmpAddons[i].isValid);
|
||||
do_check_false(res.gmpAddons[i].isInstalled);
|
||||
}
|
||||
installManager.uninit();
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that checking for addons when there are also updates available
|
||||
* works as expected.
|
||||
*/
|
||||
add_task(function* test_checkForAddons_updatesWithAddons() {
|
||||
let responseXML =
|
||||
"<?xml version=\"1.0\"?>" +
|
||||
" <updates>" +
|
||||
" <update type=\"minor\" displayVersion=\"33.0a1\" appVersion=\"33.0a1\" platformVersion=\"33.0a1\" buildID=\"20140628030201\">" +
|
||||
" <patch type=\"complete\" URL=\"http://ftp.mozilla.org/pub/mozilla.org/firefox/nightly/2014/06/2014-06-28-03-02-01-mozilla-central/firefox-33.0a1.en-US.mac.complete.mar\" hashFunction=\"sha512\" hashValue=\"f3f90d71dff03ae81def80e64bba3e4569da99c9e15269f731c2b167c4fc30b3aed9f5fee81c19614120230ca333e73a5e7def1b8e45d03135b2069c26736219\" size=\"85249896\"/>" +
|
||||
" </update>" +
|
||||
" <addons>" +
|
||||
" <addon id=\"gmp-gmpopenh264\"" +
|
||||
" URL=\"http://127.0.0.1:8011/gmp-gmpopenh264-1.1.zip\"" +
|
||||
" hashFunction=\"sha256\"" +
|
||||
" hashValue=\"1118b90d6f645eefc2b99af17bae396636ace1e33d079c88de715177584e2aee\"" +
|
||||
" version=\"1.1\"/>" +
|
||||
" </addons>" +
|
||||
"</updates>"
|
||||
overrideXHR(200, responseXML);
|
||||
let installManager = new GMPInstallManager();
|
||||
let res = yield installManager.checkForAddons();
|
||||
do_check_eq(res.gmpAddons.length, 1);
|
||||
let gmpAddon = res.gmpAddons[0];
|
||||
do_check_eq(gmpAddon.id, "gmp-gmpopenh264");
|
||||
do_check_eq(gmpAddon.URL, "http://127.0.0.1:8011/gmp-gmpopenh264-1.1.zip");
|
||||
do_check_eq(gmpAddon.hashFunction, "sha256");
|
||||
do_check_eq(gmpAddon.hashValue, "1118b90d6f645eefc2b99af17bae396636ace1e33d079c88de715177584e2aee");
|
||||
do_check_eq(gmpAddon.version, "1.1");
|
||||
do_check_true(gmpAddon.isValid);
|
||||
do_check_false(gmpAddon.isInstalled);
|
||||
installManager.uninit();
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that installing found addons works as expected
|
||||
*/
|
||||
function* test_checkForAddons_installAddon(id, includeSize, wantInstallReject) {
|
||||
do_print("Running installAddon for id: " + id +
|
||||
", includeSize: " + includeSize +
|
||||
" and wantInstallReject: " + wantInstallReject);
|
||||
let httpServer = new HttpServer();
|
||||
let dir = FileUtils.getDir("TmpD", [], true);
|
||||
httpServer.registerDirectory("/", dir);
|
||||
httpServer.start(-1);
|
||||
let testserverPort = httpServer.identity.primaryPort;
|
||||
let zipFileName = "test_" + id + "_GMP.zip";
|
||||
|
||||
let zipURL = URL_HOST + ":" + testserverPort + "/" + zipFileName;
|
||||
do_print("zipURL: " + zipURL);
|
||||
|
||||
let data = "e~=0.5772156649";
|
||||
let zipFile = createNewZipFile(zipFileName, data);
|
||||
let hashFunc = "sha256";
|
||||
let expectedDigest = yield computeHash(hashFunc, zipFile.path);
|
||||
let fileSize = zipFile.fileSize;
|
||||
if (wantInstallReject) {
|
||||
fileSize = 1;
|
||||
}
|
||||
|
||||
let responseXML =
|
||||
"<?xml version=\"1.0\"?>" +
|
||||
"<updates>" +
|
||||
" <addons>" +
|
||||
" <addon id=\"" + id + "-gmp-gmpopenh264\"" +
|
||||
" URL=\"" + zipURL + "\"" +
|
||||
" hashFunction=\"" + hashFunc + "\"" +
|
||||
" hashValue=\"" + expectedDigest + "\"" +
|
||||
(includeSize ? " size=\"" + fileSize + "\"" : "") +
|
||||
" version=\"1.1\"/>" +
|
||||
" </addons>" +
|
||||
"</updates>"
|
||||
|
||||
overrideXHR(200, responseXML);
|
||||
let installManager = new GMPInstallManager();
|
||||
let res = yield installManager.checkForAddons();
|
||||
do_check_eq(res.gmpAddons.length, 1);
|
||||
let gmpAddon = res.gmpAddons[0];
|
||||
do_check_false(gmpAddon.isInstalled);
|
||||
|
||||
try {
|
||||
let extractedPaths = yield installManager.installAddon(gmpAddon);
|
||||
if (wantInstallReject) {
|
||||
do_check_true(false); // installAddon() should have thrown.
|
||||
}
|
||||
do_check_eq(extractedPaths.length, 1);
|
||||
let extractedPath = extractedPaths[0];
|
||||
|
||||
do_print("Extracted path: " + extractedPath);
|
||||
|
||||
let extractedFile = Cc["@mozilla.org/file/local;1"].
|
||||
createInstance(Ci.nsIFile);
|
||||
extractedFile.initWithPath(extractedPath);
|
||||
do_check_true(extractedFile.exists());
|
||||
let readData = readStringFromFile(extractedFile);
|
||||
do_check_eq(readData, data);
|
||||
|
||||
// Make sure the prefs are set correctly
|
||||
do_check_true(!!GMPScope.GMPPrefs.get(
|
||||
GMPScope.GMPPrefs.KEY_PLUGIN_LAST_UPDATE, "", gmpAddon.id));
|
||||
do_check_eq(GMPScope.GMPPrefs.get(GMPScope.GMPPrefs.KEY_PLUGIN_VERSION, "",
|
||||
gmpAddon.id),
|
||||
"1.1");
|
||||
do_check_eq(GMPScope.GMPPrefs.get(GMPScope.GMPPrefs.KEY_PLUGIN_ABI, "",
|
||||
gmpAddon.id),
|
||||
UpdateUtils.ABI);
|
||||
// Make sure it reports as being installed
|
||||
do_check_true(gmpAddon.isInstalled);
|
||||
|
||||
// Cleanup
|
||||
extractedFile.parent.remove(true);
|
||||
zipFile.remove(false);
|
||||
httpServer.stop(function() {});
|
||||
installManager.uninit();
|
||||
} catch (ex) {
|
||||
zipFile.remove(false);
|
||||
if (!wantInstallReject) {
|
||||
do_throw("install update should not reject " + ex.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add_task(test_checkForAddons_installAddon.bind(null, "1", true, false));
|
||||
add_task(test_checkForAddons_installAddon.bind(null, "2", false, false));
|
||||
add_task(test_checkForAddons_installAddon.bind(null, "3", true, true));
|
||||
|
||||
/**
|
||||
* Tests simpleCheckAndInstall when autoupdate is disabled for a GMP
|
||||
*/
|
||||
add_task(function* test_simpleCheckAndInstall_autoUpdateDisabled() {
|
||||
GMPScope.GMPPrefs.set(GMPScope.GMPPrefs.KEY_PLUGIN_AUTOUPDATE, false, GMPScope.OPEN_H264_ID);
|
||||
let responseXML =
|
||||
"<?xml version=\"1.0\"?>" +
|
||||
"<updates>" +
|
||||
" <addons>" +
|
||||
// valid openh264
|
||||
" <addon id=\"gmp-gmpopenh264\"" +
|
||||
" URL=\"http://127.0.0.1:8011/gmp-gmpopenh264-1.1.zip\"" +
|
||||
" hashFunction=\"sha256\"" +
|
||||
" hashValue=\"1118b90d6f645eefc2b99af17bae396636ace1e33d079c88de715177584e2aee\"" +
|
||||
" version=\"1.1\"/>" +
|
||||
" </addons>" +
|
||||
"</updates>"
|
||||
|
||||
overrideXHR(200, responseXML);
|
||||
let installManager = new GMPInstallManager();
|
||||
let result = yield installManager.simpleCheckAndInstall();
|
||||
do_check_eq(result.status, "nothing-new-to-install");
|
||||
Preferences.reset(GMPScope.GMPPrefs.KEY_UPDATE_LAST_CHECK);
|
||||
GMPScope.GMPPrefs.set(GMPScope.GMPPrefs.KEY_PLUGIN_AUTOUPDATE, true, GMPScope.OPEN_H264_ID);
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests simpleCheckAndInstall nothing to install
|
||||
*/
|
||||
add_task(function* test_simpleCheckAndInstall_nothingToInstall() {
|
||||
let responseXML =
|
||||
"<?xml version=\"1.0\"?>" +
|
||||
"<updates>" +
|
||||
"</updates>"
|
||||
|
||||
overrideXHR(200, responseXML);
|
||||
let installManager = new GMPInstallManager();
|
||||
let result = yield installManager.simpleCheckAndInstall();
|
||||
do_check_eq(result.status, "nothing-new-to-install");
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests simpleCheckAndInstall too frequent
|
||||
*/
|
||||
add_task(function* test_simpleCheckAndInstall_tooFrequent() {
|
||||
let responseXML =
|
||||
"<?xml version=\"1.0\"?>" +
|
||||
"<updates>" +
|
||||
"</updates>"
|
||||
|
||||
overrideXHR(200, responseXML);
|
||||
let installManager = new GMPInstallManager();
|
||||
let result = yield installManager.simpleCheckAndInstall();
|
||||
do_check_eq(result.status, "too-frequent-no-check");
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests that installing addons when there is no server works as expected
|
||||
*/
|
||||
add_test(function test_installAddon_noServer() {
|
||||
let dir = FileUtils.getDir("TmpD", [], true);
|
||||
let zipFileName = "test_GMP.zip";
|
||||
let zipURL = URL_HOST + ":0/" + zipFileName;
|
||||
|
||||
let data = "e~=0.5772156649";
|
||||
let zipFile = createNewZipFile(zipFileName, data);
|
||||
|
||||
let responseXML =
|
||||
"<?xml version=\"1.0\"?>" +
|
||||
"<updates>" +
|
||||
" <addons>" +
|
||||
" <addon id=\"gmp-gmpopenh264\"" +
|
||||
" URL=\"" + zipURL + "\"" +
|
||||
" hashFunction=\"sha256\"" +
|
||||
" hashValue=\"11221cbda000347b054028b527a60e578f919cb10f322ef8077d3491c6fcb474\"" +
|
||||
" version=\"1.1\"/>" +
|
||||
" </addons>" +
|
||||
"</updates>"
|
||||
|
||||
overrideXHR(200, responseXML);
|
||||
let installManager = new GMPInstallManager();
|
||||
let checkPromise = installManager.checkForAddons();
|
||||
checkPromise.then(res => {
|
||||
do_check_eq(res.gmpAddons.length, 1);
|
||||
let gmpAddon = res.gmpAddons[0];
|
||||
|
||||
GMPInstallManager.overrideLeaveDownloadedZip = true;
|
||||
let installPromise = installManager.installAddon(gmpAddon);
|
||||
installPromise.then(extractedPaths => {
|
||||
do_throw("No server for install should reject");
|
||||
}, err => {
|
||||
do_check_true(!!err);
|
||||
installManager.uninit();
|
||||
run_next_test();
|
||||
});
|
||||
}, () => {
|
||||
do_throw("check should not reject for install no server");
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns the read stream into a string
|
||||
*/
|
||||
function readStringFromInputStream(inputStream) {
|
||||
let sis = Cc["@mozilla.org/scriptableinputstream;1"].
|
||||
createInstance(Ci.nsIScriptableInputStream);
|
||||
sis.init(inputStream);
|
||||
let text = sis.read(sis.available());
|
||||
sis.close();
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a string of text from a file.
|
||||
* This function only works with ASCII text.
|
||||
*/
|
||||
function readStringFromFile(file) {
|
||||
if (!file.exists()) {
|
||||
do_print("readStringFromFile - file doesn't exist: " + file.path);
|
||||
return null;
|
||||
}
|
||||
let fis = Cc["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Ci.nsIFileInputStream);
|
||||
fis.init(file, FileUtils.MODE_RDONLY, FileUtils.PERMS_FILE, 0);
|
||||
return readStringFromInputStream(fis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bare bones XMLHttpRequest implementation for testing onprogress, onerror,
|
||||
* and onload nsIDomEventListener handleEvent.
|
||||
*/
|
||||
function makeHandler(aVal) {
|
||||
if (typeof aVal == "function")
|
||||
return { handleEvent: aVal };
|
||||
return aVal;
|
||||
}
|
||||
/**
|
||||
* Constructs a mock xhr which is used for testing different aspects
|
||||
* of responses.
|
||||
*/
|
||||
function xhr(inputStatus, inputResponse, options) {
|
||||
this.inputStatus = inputStatus;
|
||||
this.inputResponse = inputResponse;
|
||||
this.status = 0;
|
||||
this.responseXML = null;
|
||||
this._aborted = false;
|
||||
this._onabort = null;
|
||||
this._onprogress = null;
|
||||
this._onerror = null;
|
||||
this._onload = null;
|
||||
this._onloadend = null;
|
||||
this._ontimeout = null;
|
||||
this._url = null;
|
||||
this._method = null;
|
||||
this._timeout = 0;
|
||||
this._notified = false;
|
||||
this._options = options || {};
|
||||
}
|
||||
xhr.prototype = {
|
||||
overrideMimeType: function(aMimetype) { },
|
||||
setRequestHeader: function(aHeader, aValue) { },
|
||||
status: null,
|
||||
channel: { set notificationCallbacks(aVal) { } },
|
||||
open: function(aMethod, aUrl) {
|
||||
this.channel.originalURI = Services.io.newURI(aUrl, null, null);
|
||||
this._method = aMethod; this._url = aUrl;
|
||||
},
|
||||
abort: function() {
|
||||
this._dropRequest = true;
|
||||
this._notify(["abort", "loadend"]);
|
||||
},
|
||||
responseXML: null,
|
||||
responseText: null,
|
||||
send: function(aBody) {
|
||||
do_execute_soon(function() {
|
||||
try {
|
||||
if (this._options.dropRequest) {
|
||||
if (this._timeout > 0 && this._options.timeout) {
|
||||
this._notify(["timeout", "loadend"]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.status = this.inputStatus;
|
||||
this.responseText = this.inputResponse;
|
||||
try {
|
||||
let parser = Cc["@mozilla.org/xmlextras/domparser;1"].
|
||||
createInstance(Ci.nsIDOMParser);
|
||||
this.responseXML = parser.parseFromString(this.inputResponse,
|
||||
"application/xml");
|
||||
} catch (e) {
|
||||
this.responseXML = null;
|
||||
}
|
||||
if (this.inputStatus === 200) {
|
||||
this._notify(["load", "loadend"]);
|
||||
} else {
|
||||
this._notify(["error", "loadend"]);
|
||||
}
|
||||
} catch (ex) {
|
||||
do_throw(ex);
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
set onabort(aValue) { this._onabort = makeHandler(aValue); },
|
||||
get onabort() { return this._onabort; },
|
||||
set onprogress(aValue) { this._onprogress = makeHandler(aValue); },
|
||||
get onprogress() { return this._onprogress; },
|
||||
set onerror(aValue) { this._onerror = makeHandler(aValue); },
|
||||
get onerror() { return this._onerror; },
|
||||
set onload(aValue) { this._onload = makeHandler(aValue); },
|
||||
get onload() { return this._onload; },
|
||||
set onloadend(aValue) { this._onloadend = makeHandler(aValue); },
|
||||
get onloadend() { return this._onloadend; },
|
||||
set ontimeout(aValue) { this._ontimeout = makeHandler(aValue); },
|
||||
get ontimeout() { return this._ontimeout; },
|
||||
set timeout(aValue) { this._timeout = aValue; },
|
||||
_notify: function(events) {
|
||||
if (this._notified) {
|
||||
return;
|
||||
}
|
||||
this._notified = true;
|
||||
for (let item of events) {
|
||||
let k = "on" + item;
|
||||
if (this[k]) {
|
||||
do_print("Notifying " + item);
|
||||
let e = {
|
||||
target: this,
|
||||
type: item,
|
||||
};
|
||||
this[k](e);
|
||||
} else {
|
||||
do_print("Notifying " + item + ", but there are no listeners");
|
||||
}
|
||||
}
|
||||
},
|
||||
addEventListener: function(aEvent, aValue, aCapturing) {
|
||||
eval("this._on" + aEvent + " = aValue");
|
||||
},
|
||||
flags: Ci.nsIClassInfo.SINGLETON,
|
||||
getScriptableHelper: () => null,
|
||||
getInterfaces: function(aCount) {
|
||||
let interfaces = [Ci.nsISupports];
|
||||
aCount.value = interfaces.length;
|
||||
return interfaces;
|
||||
},
|
||||
classDescription: "XMLHttpRequest",
|
||||
contractID: "@mozilla.org/xmlextras/xmlhttprequest;1",
|
||||
classID: Components.ID("{c9b37f43-4278-4304-a5e0-600991ab08cb}"),
|
||||
createInstance: function(aOuter, aIID) {
|
||||
if (aOuter == null)
|
||||
return this.QueryInterface(aIID);
|
||||
throw Cr.NS_ERROR_NO_AGGREGATION;
|
||||
},
|
||||
QueryInterface: function(aIID) {
|
||||
if (aIID.equals(Ci.nsIClassInfo) ||
|
||||
aIID.equals(Ci.nsISupports))
|
||||
return this;
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
get wrappedJSObject() { return this; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper used to overrideXHR requests (no matter to what URL) with the
|
||||
* specified status and response.
|
||||
* @param status The status you want to get back when an XHR request is made
|
||||
* @param response The response you want to get back when an XHR request is made
|
||||
*/
|
||||
function overrideXHR(status, response, options) {
|
||||
overrideXHR.myxhr = new xhr(status, response, options);
|
||||
ProductAddonCheckerScope.CreateXHR = function() {
|
||||
return overrideXHR.myxhr;
|
||||
};
|
||||
return overrideXHR.myxhr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new zip file containing a file with the specified data
|
||||
* @param zipName The name of the zip file
|
||||
* @param data The data to go inside the zip for the filename entry1.info
|
||||
*/
|
||||
function createNewZipFile(zipName, data) {
|
||||
// Create a zip file which will be used for extracting
|
||||
let stream = Cc["@mozilla.org/io/string-input-stream;1"].
|
||||
createInstance(Ci.nsIStringInputStream);
|
||||
stream.setData(data, data.length);
|
||||
let zipWriter = Cc["@mozilla.org/zipwriter;1"].
|
||||
createInstance(Components.interfaces.nsIZipWriter);
|
||||
let zipFile = FileUtils.getFile("TmpD", [zipName]);
|
||||
if (zipFile.exists()) {
|
||||
zipFile.remove(false);
|
||||
}
|
||||
// From prio.h
|
||||
const PR_RDWR = 0x04;
|
||||
const PR_CREATE_FILE = 0x08;
|
||||
const PR_TRUNCATE = 0x20;
|
||||
zipWriter.open(zipFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE);
|
||||
zipWriter.addEntryStream("entry1.info", Date.now(),
|
||||
Ci.nsIZipWriter.COMPRESSION_BEST, stream, false);
|
||||
zipWriter.close();
|
||||
stream.close();
|
||||
do_print("zip file created on disk at: " + zipFile.path);
|
||||
return zipFile;
|
||||
}
|
||||
|
|
@ -1,257 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Http.jsm");
|
||||
Components.utils.import("resource://testing-common/httpd.js");
|
||||
|
||||
const BinaryInputStream = Components.Constructor("@mozilla.org/binaryinputstream;1",
|
||||
"nsIBinaryInputStream", "setInputStream");
|
||||
|
||||
var server;
|
||||
|
||||
const kDefaultServerPort = 9000;
|
||||
const kSuccessPath = "/success";
|
||||
const kBaseUrl = "http://localhost:" + kDefaultServerPort;
|
||||
const kSuccessUrl = kBaseUrl + kSuccessPath;
|
||||
|
||||
const kPostPath = "/post";
|
||||
const kPostUrl = kBaseUrl + kPostPath;
|
||||
const kPostDataSent = [["foo", "bar"], ["complex", "!*()@"]];
|
||||
const kPostDataReceived = "foo=bar&complex=%21%2A%28%29%40";
|
||||
const kPostMimeTypeReceived = "application/x-www-form-urlencoded; charset=utf-8";
|
||||
|
||||
const kJsonPostPath = "/json_post";
|
||||
const kJsonPostUrl = kBaseUrl + kJsonPostPath;
|
||||
const kJsonPostData = JSON.stringify(kPostDataSent);
|
||||
const kJsonPostMimeType = "application/json";
|
||||
|
||||
const kPutPath = "/put";
|
||||
const kPutUrl = kBaseUrl + kPutPath;
|
||||
const kPutDataSent = [["P", "NP"]];
|
||||
const kPutDataReceived = "P=NP";
|
||||
|
||||
const kGetPath = "/get";
|
||||
const kGetUrl = kBaseUrl + kGetPath;
|
||||
|
||||
function successResult(aRequest, aResponse) {
|
||||
aResponse.setStatusLine(null, 200, "OK");
|
||||
aResponse.setHeader("Content-Type", "application/json");
|
||||
aResponse.write("Success!");
|
||||
}
|
||||
|
||||
function getDataChecker(aExpectedMethod, aExpectedData, aExpectedMimeType = null) {
|
||||
return function(aRequest, aResponse) {
|
||||
let body = new BinaryInputStream(aRequest.bodyInputStream);
|
||||
let bytes = [];
|
||||
let avail;
|
||||
while ((avail = body.available()) > 0)
|
||||
Array.prototype.push.apply(bytes, body.readByteArray(avail));
|
||||
|
||||
do_check_eq(aRequest.method, aExpectedMethod);
|
||||
|
||||
// Checking if the Content-Type is as expected.
|
||||
if (aExpectedMimeType) {
|
||||
let contentType = aRequest.getHeader("Content-Type");
|
||||
do_check_eq(contentType, aExpectedMimeType);
|
||||
}
|
||||
|
||||
var data = String.fromCharCode.apply(null, bytes);
|
||||
|
||||
do_check_eq(data, aExpectedData);
|
||||
|
||||
aResponse.setStatusLine(null, 200, "OK");
|
||||
aResponse.setHeader("Content-Type", "application/json");
|
||||
aResponse.write("Success!");
|
||||
}
|
||||
}
|
||||
|
||||
add_test(function test_successCallback() {
|
||||
do_test_pending();
|
||||
let options = {
|
||||
onLoad: function(aResponse) {
|
||||
do_check_eq(aResponse, "Success!");
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
},
|
||||
onError: function(e) {
|
||||
do_check_true(false);
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}
|
||||
}
|
||||
httpRequest(kSuccessUrl, options);
|
||||
});
|
||||
|
||||
add_test(function test_errorCallback() {
|
||||
do_test_pending();
|
||||
let options = {
|
||||
onSuccess: function(aResponse) {
|
||||
do_check_true(false);
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
},
|
||||
onError: function(e, aResponse) {
|
||||
do_check_eq(e, "404 - Not Found");
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}
|
||||
}
|
||||
httpRequest(kBaseUrl + "/failure", options);
|
||||
});
|
||||
|
||||
add_test(function test_PostData() {
|
||||
do_test_pending();
|
||||
let options = {
|
||||
onLoad: function(aResponse) {
|
||||
do_check_eq(aResponse, "Success!");
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
},
|
||||
onError: function(e) {
|
||||
do_check_true(false);
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
},
|
||||
postData: kPostDataSent
|
||||
}
|
||||
httpRequest(kPostUrl, options);
|
||||
});
|
||||
|
||||
add_test(function test_PutData() {
|
||||
do_test_pending();
|
||||
let options = {
|
||||
method: "PUT",
|
||||
onLoad: function(aResponse) {
|
||||
do_check_eq(aResponse, "Success!");
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
},
|
||||
onError: function(e) {
|
||||
do_check_true(false);
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
},
|
||||
postData: kPutDataSent
|
||||
}
|
||||
httpRequest(kPutUrl, options);
|
||||
});
|
||||
|
||||
add_test(function test_GetData() {
|
||||
do_test_pending();
|
||||
let options = {
|
||||
onLoad: function(aResponse) {
|
||||
do_check_eq(aResponse, "Success!");
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
},
|
||||
onError: function(e) {
|
||||
do_check_true(false);
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
},
|
||||
postData: null
|
||||
}
|
||||
httpRequest(kGetUrl, options);
|
||||
});
|
||||
|
||||
add_test(function test_OptionalParameters() {
|
||||
let options = {
|
||||
onLoad: null,
|
||||
onError: null,
|
||||
logger: null
|
||||
};
|
||||
// Just make sure that nothing throws when doing this (i.e. httpRequest
|
||||
// doesn't try to access null options).
|
||||
httpRequest(kGetUrl, options);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
/**
|
||||
* Makes sure that httpRequest API allows setting a custom Content-Type header
|
||||
* for POST requests when data is a string.
|
||||
*/
|
||||
add_test(function test_CustomContentTypeOnPost() {
|
||||
do_test_pending();
|
||||
|
||||
// Preparing the request parameters.
|
||||
let options = {
|
||||
onLoad: function(aResponse) {
|
||||
do_check_eq(aResponse, "Success!");
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
},
|
||||
onError: function(e) {
|
||||
do_check_true(false);
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
},
|
||||
postData: kJsonPostData,
|
||||
// Setting a custom Content-Type header.
|
||||
headers: [['Content-Type', "application/json"]]
|
||||
}
|
||||
|
||||
// Firing the request.
|
||||
httpRequest(kJsonPostUrl, options);
|
||||
});
|
||||
|
||||
/**
|
||||
* Ensures that the httpRequest API provides a way to override the response
|
||||
* MIME type.
|
||||
*/
|
||||
add_test(function test_OverrideMimeType() {
|
||||
do_test_pending();
|
||||
|
||||
// Preparing the request parameters.
|
||||
const kMimeType = 'text/xml; charset=UTF-8';
|
||||
let options = {
|
||||
onLoad: function(aResponse, xhr) {
|
||||
do_check_eq(aResponse, "Success!");
|
||||
|
||||
// Set the expected MIME-type.
|
||||
let reportedMimeType = xhr.getResponseHeader("Content-Type");
|
||||
do_check_neq(reportedMimeType, kMimeType);
|
||||
|
||||
// responseXML should not be not null if overriding mime type succeeded.
|
||||
do_check_true(xhr.responseXML != null);
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
},
|
||||
onError: function(e) {
|
||||
do_check_true(false);
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}
|
||||
};
|
||||
|
||||
// Firing the request.
|
||||
let xhr = httpRequest(kGetUrl, options);
|
||||
|
||||
// Override the response MIME type.
|
||||
xhr.overrideMimeType(kMimeType);
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
// Set up a mock HTTP server to serve a success page.
|
||||
server = new HttpServer();
|
||||
server.registerPathHandler(kSuccessPath, successResult);
|
||||
server.registerPathHandler(kPostPath,
|
||||
getDataChecker("POST", kPostDataReceived,
|
||||
kPostMimeTypeReceived));
|
||||
server.registerPathHandler(kPutPath,
|
||||
getDataChecker("PUT", kPutDataReceived));
|
||||
server.registerPathHandler(kGetPath, getDataChecker("GET", ""));
|
||||
server.registerPathHandler(kJsonPostPath,
|
||||
getDataChecker("POST", kJsonPostData,
|
||||
kJsonPostMimeType));
|
||||
|
||||
server.start(kDefaultServerPort);
|
||||
|
||||
run_next_test();
|
||||
|
||||
// Teardown.
|
||||
do_register_cleanup(function() {
|
||||
server.stop(function() { });
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -1,238 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/*
|
||||
* Tests the Integration.jsm module.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Integration.jsm", this);
|
||||
Cu.import("resource://gre/modules/Services.jsm", this);
|
||||
Cu.import("resource://gre/modules/Task.jsm", this);
|
||||
|
||||
const TestIntegration = {
|
||||
value: "value",
|
||||
|
||||
get valueFromThis() {
|
||||
return this.value;
|
||||
},
|
||||
|
||||
get property() {
|
||||
return this._property;
|
||||
},
|
||||
|
||||
set property(value) {
|
||||
this._property = value;
|
||||
},
|
||||
|
||||
method(argument) {
|
||||
this.methodArgument = argument;
|
||||
return "method" + argument;
|
||||
},
|
||||
|
||||
asyncMethod: Task.async(function* (argument) {
|
||||
this.asyncMethodArgument = argument;
|
||||
return "asyncMethod" + argument;
|
||||
}),
|
||||
};
|
||||
|
||||
let overrideFn = base => ({
|
||||
value: "overridden-value",
|
||||
|
||||
get property() {
|
||||
return "overridden-" + base.__lookupGetter__("property").call(this);
|
||||
},
|
||||
|
||||
set property(value) {
|
||||
base.__lookupSetter__("property").call(this, "overridden-" + value);
|
||||
},
|
||||
|
||||
method() {
|
||||
return "overridden-" + base.method.apply(this, arguments);
|
||||
},
|
||||
|
||||
asyncMethod: Task.async(function* () {
|
||||
return "overridden-" + (yield base.asyncMethod.apply(this, arguments));
|
||||
}),
|
||||
});
|
||||
|
||||
let superOverrideFn = base => ({
|
||||
__proto__: base,
|
||||
|
||||
value: "overridden-value",
|
||||
|
||||
get property() {
|
||||
return "overridden-" + super.property;
|
||||
},
|
||||
|
||||
set property(value) {
|
||||
super.property = "overridden-" + value;
|
||||
},
|
||||
|
||||
method() {
|
||||
return "overridden-" + super.method(...arguments);
|
||||
},
|
||||
|
||||
asyncMethod: Task.async(function* () {
|
||||
// We cannot use the "super" keyword in methods defined using "Task.async".
|
||||
return "overridden-" + (yield base.asyncMethod.apply(this, arguments));
|
||||
}),
|
||||
});
|
||||
|
||||
/**
|
||||
* Fails the test if the results of method invocations on the combined object
|
||||
* don't match the expected results based on how many overrides are registered.
|
||||
*
|
||||
* @param combined
|
||||
* The combined object based on the TestIntegration root.
|
||||
* @param overridesCount
|
||||
* Zero if the root object is not overridden, or a higher value to test
|
||||
* the presence of one or more integration overrides.
|
||||
*/
|
||||
function* assertCombinedResults(combined, overridesCount) {
|
||||
let expectedValue = overridesCount > 0 ? "overridden-value" : "value";
|
||||
let prefix = "overridden-".repeat(overridesCount);
|
||||
|
||||
Assert.equal(combined.value, expectedValue);
|
||||
Assert.equal(combined.valueFromThis, expectedValue);
|
||||
|
||||
combined.property = "property";
|
||||
Assert.equal(combined.property, prefix.repeat(2) + "property");
|
||||
|
||||
combined.methodArgument = "";
|
||||
Assert.equal(combined.method("-argument"), prefix + "method-argument");
|
||||
Assert.equal(combined.methodArgument, "-argument");
|
||||
|
||||
combined.asyncMethodArgument = "";
|
||||
Assert.equal(yield combined.asyncMethod("-argument"),
|
||||
prefix + "asyncMethod-argument");
|
||||
Assert.equal(combined.asyncMethodArgument, "-argument");
|
||||
}
|
||||
|
||||
/**
|
||||
* Fails the test if the results of method invocations on the combined object
|
||||
* for the "testModule" integration point don't match the expected results based
|
||||
* on how many overrides are registered.
|
||||
*
|
||||
* @param overridesCount
|
||||
* Zero if the root object is not overridden, or a higher value to test
|
||||
* the presence of one or more integration overrides.
|
||||
*/
|
||||
function* assertCurrentCombinedResults(overridesCount) {
|
||||
let combined = Integration.testModule.getCombined(TestIntegration);
|
||||
yield assertCombinedResults(combined, overridesCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the initial state with no integration override functions registered.
|
||||
*/
|
||||
add_task(function* test_base() {
|
||||
yield assertCurrentCombinedResults(0);
|
||||
});
|
||||
|
||||
/**
|
||||
* Registers and unregisters an integration override function.
|
||||
*/
|
||||
add_task(function* test_override() {
|
||||
Integration.testModule.register(overrideFn);
|
||||
yield assertCurrentCombinedResults(1);
|
||||
|
||||
// Registering the same function more than once has no effect.
|
||||
Integration.testModule.register(overrideFn);
|
||||
yield assertCurrentCombinedResults(1);
|
||||
|
||||
Integration.testModule.unregister(overrideFn);
|
||||
yield assertCurrentCombinedResults(0);
|
||||
});
|
||||
|
||||
/**
|
||||
* Registers and unregisters more than one integration override function, of
|
||||
* which one uses the prototype and the "super" keyword to access the base.
|
||||
*/
|
||||
add_task(function* test_override_super_multiple() {
|
||||
Integration.testModule.register(overrideFn);
|
||||
Integration.testModule.register(superOverrideFn);
|
||||
yield assertCurrentCombinedResults(2);
|
||||
|
||||
Integration.testModule.unregister(overrideFn);
|
||||
yield assertCurrentCombinedResults(1);
|
||||
|
||||
Integration.testModule.unregister(superOverrideFn);
|
||||
yield assertCurrentCombinedResults(0);
|
||||
});
|
||||
|
||||
/**
|
||||
* Registers an integration override function that throws an exception, and
|
||||
* ensures that this does not block other functions from being registered.
|
||||
*/
|
||||
add_task(function* test_override_error() {
|
||||
let errorOverrideFn = base => { throw "Expected error." };
|
||||
|
||||
Integration.testModule.register(errorOverrideFn);
|
||||
Integration.testModule.register(overrideFn);
|
||||
yield assertCurrentCombinedResults(1);
|
||||
|
||||
Integration.testModule.unregister(errorOverrideFn);
|
||||
Integration.testModule.unregister(overrideFn);
|
||||
yield assertCurrentCombinedResults(0);
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that state saved using the "this" reference is preserved as a shallow
|
||||
* copy when registering new integration override functions.
|
||||
*/
|
||||
add_task(function* test_state_preserved() {
|
||||
let valueObject = { toString: () => "toString" };
|
||||
|
||||
let combined = Integration.testModule.getCombined(TestIntegration);
|
||||
combined.property = valueObject;
|
||||
Assert.ok(combined.property === valueObject);
|
||||
|
||||
Integration.testModule.register(overrideFn);
|
||||
combined = Integration.testModule.getCombined(TestIntegration);
|
||||
Assert.equal(combined.property, "overridden-toString");
|
||||
|
||||
Integration.testModule.unregister(overrideFn);
|
||||
combined = Integration.testModule.getCombined(TestIntegration);
|
||||
Assert.ok(combined.property === valueObject);
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that the combined integration objects cannot be used with XPCOM.
|
||||
*
|
||||
* This is limited by the fact that interfaces with the "[function]" annotation,
|
||||
* for example nsIObserver, do not call the QueryInterface implementation.
|
||||
*/
|
||||
add_task(function* test_xpcom_throws() {
|
||||
let combined = Integration.testModule.getCombined(TestIntegration);
|
||||
|
||||
// This calls QueryInterface because it looks for nsISupportsWeakReference.
|
||||
Assert.throws(() => Services.obs.addObserver(combined, "test-topic", true),
|
||||
"NS_NOINTERFACE");
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that getters defined by defineModuleGetter are able to retrieve the
|
||||
* latest version of the combined integration object.
|
||||
*/
|
||||
add_task(function* test_defineModuleGetter() {
|
||||
let objectForGetters = {};
|
||||
|
||||
// Test with and without the optional "symbol" parameter.
|
||||
Integration.testModule.defineModuleGetter(objectForGetters,
|
||||
"TestIntegration", "resource://testing-common/TestIntegration.jsm");
|
||||
Integration.testModule.defineModuleGetter(objectForGetters,
|
||||
"integration", "resource://testing-common/TestIntegration.jsm",
|
||||
"TestIntegration");
|
||||
|
||||
Integration.testModule.register(overrideFn);
|
||||
yield assertCombinedResults(objectForGetters.integration, 1);
|
||||
yield assertCombinedResults(objectForGetters.TestIntegration, 1);
|
||||
|
||||
Integration.testModule.unregister(overrideFn);
|
||||
yield assertCombinedResults(objectForGetters.integration, 0);
|
||||
yield assertCombinedResults(objectForGetters.TestIntegration, 0);
|
||||
});
|
||||
|
|
@ -1,242 +0,0 @@
|
|||
/**
|
||||
* Tests the JSONFile object.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
// Globals
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadPaths",
|
||||
"resource://gre/modules/DownloadPaths.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||
"resource://gre/modules/osfile.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "JSONFile",
|
||||
"resource://gre/modules/JSONFile.jsm");
|
||||
|
||||
let gFileCounter = Math.floor(Math.random() * 1000000);
|
||||
|
||||
/**
|
||||
* Returns a reference to a temporary file, that is guaranteed not to exist, and
|
||||
* to have never been created before.
|
||||
*
|
||||
* @param aLeafName
|
||||
* Suggested leaf name for the file to be created.
|
||||
*
|
||||
* @return nsIFile pointing to a non-existent file in a temporary directory.
|
||||
*
|
||||
* @note It is not enough to delete the file if it exists, or to delete the file
|
||||
* after calling nsIFile.createUnique, because on Windows the delete
|
||||
* operation in the file system may still be pending, preventing a new
|
||||
* file with the same name to be created.
|
||||
*/
|
||||
function getTempFile(aLeafName)
|
||||
{
|
||||
// Prepend a serial number to the extension in the suggested leaf name.
|
||||
let [base, ext] = DownloadPaths.splitBaseNameAndExtension(aLeafName);
|
||||
let leafName = base + "-" + gFileCounter + ext;
|
||||
gFileCounter++;
|
||||
|
||||
// Get a file reference under the temporary directory for this test file.
|
||||
let file = FileUtils.getFile("TmpD", [leafName]);
|
||||
do_check_false(file.exists());
|
||||
|
||||
do_register_cleanup(function () {
|
||||
if (file.exists()) {
|
||||
file.remove(false);
|
||||
}
|
||||
});
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
const TEST_STORE_FILE_NAME = "test-store.json";
|
||||
|
||||
const TEST_DATA = {
|
||||
number: 123,
|
||||
string: "test",
|
||||
object: {
|
||||
prop1: 1,
|
||||
prop2: 2,
|
||||
},
|
||||
};
|
||||
|
||||
// Tests
|
||||
|
||||
add_task(function* test_save_reload()
|
||||
{
|
||||
let storeForSave = new JSONFile({
|
||||
path: getTempFile(TEST_STORE_FILE_NAME).path,
|
||||
});
|
||||
|
||||
yield storeForSave.load();
|
||||
|
||||
do_check_true(storeForSave.dataReady);
|
||||
do_check_matches(storeForSave.data, {});
|
||||
|
||||
Object.assign(storeForSave.data, TEST_DATA);
|
||||
|
||||
yield new Promise((resolve) => {
|
||||
let save = storeForSave._save.bind(storeForSave);
|
||||
storeForSave._save = () => {
|
||||
save();
|
||||
resolve();
|
||||
};
|
||||
storeForSave.saveSoon();
|
||||
});
|
||||
|
||||
let storeForLoad = new JSONFile({
|
||||
path: storeForSave.path,
|
||||
});
|
||||
|
||||
yield storeForLoad.load();
|
||||
|
||||
Assert.deepEqual(storeForLoad.data, TEST_DATA);
|
||||
});
|
||||
|
||||
add_task(function* test_load_sync()
|
||||
{
|
||||
let storeForSave = new JSONFile({
|
||||
path: getTempFile(TEST_STORE_FILE_NAME).path
|
||||
});
|
||||
yield storeForSave.load();
|
||||
Object.assign(storeForSave.data, TEST_DATA);
|
||||
yield storeForSave._save();
|
||||
|
||||
let storeForLoad = new JSONFile({
|
||||
path: storeForSave.path,
|
||||
});
|
||||
storeForLoad.ensureDataReady();
|
||||
|
||||
Assert.deepEqual(storeForLoad.data, TEST_DATA);
|
||||
});
|
||||
|
||||
add_task(function* test_load_with_dataPostProcessor()
|
||||
{
|
||||
let storeForSave = new JSONFile({
|
||||
path: getTempFile(TEST_STORE_FILE_NAME).path
|
||||
});
|
||||
yield storeForSave.load();
|
||||
Object.assign(storeForSave.data, TEST_DATA);
|
||||
yield storeForSave._save();
|
||||
|
||||
let random = Math.random();
|
||||
let storeForLoad = new JSONFile({
|
||||
path: storeForSave.path,
|
||||
dataPostProcessor: (data) => {
|
||||
Assert.deepEqual(data, TEST_DATA);
|
||||
|
||||
data.test = random;
|
||||
return data;
|
||||
},
|
||||
});
|
||||
|
||||
yield storeForLoad.load();
|
||||
|
||||
do_check_eq(storeForLoad.data.test, random);
|
||||
});
|
||||
|
||||
add_task(function* test_load_with_dataPostProcessor_fails()
|
||||
{
|
||||
let store = new JSONFile({
|
||||
path: getTempFile(TEST_STORE_FILE_NAME).path,
|
||||
dataPostProcessor: () => {
|
||||
throw new Error("dataPostProcessor fails.");
|
||||
},
|
||||
});
|
||||
|
||||
yield Assert.rejects(store.load(), /dataPostProcessor fails\./);
|
||||
|
||||
do_check_false(store.dataReady);
|
||||
});
|
||||
|
||||
add_task(function* test_load_sync_with_dataPostProcessor_fails()
|
||||
{
|
||||
let store = new JSONFile({
|
||||
path: getTempFile(TEST_STORE_FILE_NAME).path,
|
||||
dataPostProcessor: () => {
|
||||
throw new Error("dataPostProcessor fails.");
|
||||
},
|
||||
});
|
||||
|
||||
Assert.throws(() => store.ensureDataReady(), /dataPostProcessor fails\./);
|
||||
|
||||
do_check_false(store.dataReady);
|
||||
});
|
||||
|
||||
/**
|
||||
* Loads data from a string in a predefined format. The purpose of this test is
|
||||
* to verify that the JSON format used in previous versions can be loaded.
|
||||
*/
|
||||
add_task(function* test_load_string_predefined()
|
||||
{
|
||||
let store = new JSONFile({
|
||||
path: getTempFile(TEST_STORE_FILE_NAME).path,
|
||||
});
|
||||
|
||||
let string =
|
||||
"{\"number\":123,\"string\":\"test\",\"object\":{\"prop1\":1,\"prop2\":2}}";
|
||||
|
||||
yield OS.File.writeAtomic(store.path, new TextEncoder().encode(string),
|
||||
{ tmpPath: store.path + ".tmp" });
|
||||
|
||||
yield store.load();
|
||||
|
||||
Assert.deepEqual(store.data, TEST_DATA);
|
||||
});
|
||||
|
||||
/**
|
||||
* Loads data from a malformed JSON string.
|
||||
*/
|
||||
add_task(function* test_load_string_malformed()
|
||||
{
|
||||
let store = new JSONFile({
|
||||
path: getTempFile(TEST_STORE_FILE_NAME).path,
|
||||
});
|
||||
|
||||
let string = "{\"number\":123,\"string\":\"test\",\"object\":{\"prop1\":1,";
|
||||
|
||||
yield OS.File.writeAtomic(store.path, new TextEncoder().encode(string),
|
||||
{ tmpPath: store.path + ".tmp" });
|
||||
|
||||
yield store.load();
|
||||
|
||||
// A backup file should have been created.
|
||||
do_check_true(yield OS.File.exists(store.path + ".corrupt"));
|
||||
yield OS.File.remove(store.path + ".corrupt");
|
||||
|
||||
// The store should be ready to accept new data.
|
||||
do_check_true(store.dataReady);
|
||||
do_check_matches(store.data, {});
|
||||
});
|
||||
|
||||
/**
|
||||
* Loads data from a malformed JSON string, using the synchronous initialization
|
||||
* path.
|
||||
*/
|
||||
add_task(function* test_load_string_malformed_sync()
|
||||
{
|
||||
let store = new JSONFile({
|
||||
path: getTempFile(TEST_STORE_FILE_NAME).path,
|
||||
});
|
||||
|
||||
let string = "{\"number\":123,\"string\":\"test\",\"object\":{\"prop1\":1,";
|
||||
|
||||
yield OS.File.writeAtomic(store.path, new TextEncoder().encode(string),
|
||||
{ tmpPath: store.path + ".tmp" });
|
||||
|
||||
store.ensureDataReady();
|
||||
|
||||
// A backup file should have been created.
|
||||
do_check_true(yield OS.File.exists(store.path + ".corrupt"));
|
||||
yield OS.File.remove(store.path + ".corrupt");
|
||||
|
||||
// The store should be ready to accept new data.
|
||||
do_check_true(store.dataReady);
|
||||
do_check_matches(store.data, {});
|
||||
});
|
||||
|
|
@ -1,592 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/* eslint-disable block-spacing */
|
||||
|
||||
var {utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource://gre/modules/osfile.jsm");
|
||||
|
||||
Cu.import("resource://gre/modules/Promise.jsm")
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
|
||||
var testFormatter = {
|
||||
format: function format(message) {
|
||||
return message.loggerName + "\t" +
|
||||
message.levelDesc + "\t" +
|
||||
message.message;
|
||||
}
|
||||
};
|
||||
|
||||
function MockAppender(formatter) {
|
||||
Log.Appender.call(this, formatter);
|
||||
this.messages = [];
|
||||
}
|
||||
MockAppender.prototype = {
|
||||
__proto__: Log.Appender.prototype,
|
||||
|
||||
doAppend: function DApp_doAppend(message) {
|
||||
this.messages.push(message);
|
||||
}
|
||||
};
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function test_Logger() {
|
||||
let log = Log.repository.getLogger("test.logger");
|
||||
let appender = new MockAppender(new Log.BasicFormatter());
|
||||
|
||||
log.level = Log.Level.Debug;
|
||||
appender.level = Log.Level.Info;
|
||||
log.addAppender(appender);
|
||||
log.info("info test");
|
||||
log.debug("this should be logged but not appended.");
|
||||
|
||||
do_check_eq(appender.messages.length, 1);
|
||||
|
||||
let msgRe = /\d+\ttest.logger\t\INFO\tinfo test/;
|
||||
do_check_true(msgRe.test(appender.messages[0]));
|
||||
});
|
||||
|
||||
add_task(function test_Logger_parent() {
|
||||
// Check whether parenting is correct
|
||||
let grandparentLog = Log.repository.getLogger("grandparent");
|
||||
let childLog = Log.repository.getLogger("grandparent.parent.child");
|
||||
do_check_eq(childLog.parent.name, "grandparent");
|
||||
|
||||
let parentLog = Log.repository.getLogger("grandparent.parent");
|
||||
do_check_eq(childLog.parent.name, "grandparent.parent");
|
||||
|
||||
// Check that appends are exactly in scope
|
||||
let gpAppender = new MockAppender(new Log.BasicFormatter());
|
||||
gpAppender.level = Log.Level.Info;
|
||||
grandparentLog.addAppender(gpAppender);
|
||||
childLog.info("child info test");
|
||||
Log.repository.rootLogger.info("this shouldn't show up in gpAppender");
|
||||
|
||||
do_check_eq(gpAppender.messages.length, 1);
|
||||
do_check_true(gpAppender.messages[0].indexOf("child info test") > 0);
|
||||
});
|
||||
|
||||
add_test(function test_LoggerWithMessagePrefix() {
|
||||
let log = Log.repository.getLogger("test.logger.prefix");
|
||||
let appender = new MockAppender(new Log.MessageOnlyFormatter());
|
||||
log.addAppender(appender);
|
||||
|
||||
let prefixed = Log.repository.getLoggerWithMessagePrefix(
|
||||
"test.logger.prefix", "prefix: ");
|
||||
|
||||
log.warn("no prefix");
|
||||
prefixed.warn("with prefix");
|
||||
|
||||
Assert.equal(appender.messages.length, 2, "2 messages were logged.");
|
||||
Assert.deepEqual(appender.messages, [
|
||||
"no prefix",
|
||||
"prefix: with prefix",
|
||||
], "Prefix logger works.");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
/*
|
||||
* A utility method for checking object equivalence.
|
||||
* Fields with a reqular expression value in expected will be tested
|
||||
* against the corresponding value in actual. Otherwise objects
|
||||
* are expected to have the same keys and equal values.
|
||||
*/
|
||||
function checkObjects(expected, actual) {
|
||||
do_check_true(expected instanceof Object);
|
||||
do_check_true(actual instanceof Object);
|
||||
for (let key in expected) {
|
||||
do_check_neq(actual[key], undefined);
|
||||
if (expected[key] instanceof RegExp) {
|
||||
do_check_true(expected[key].test(actual[key].toString()));
|
||||
} else if (expected[key] instanceof Object) {
|
||||
checkObjects(expected[key], actual[key]);
|
||||
} else {
|
||||
do_check_eq(expected[key], actual[key]);
|
||||
}
|
||||
}
|
||||
|
||||
for (let key in actual) {
|
||||
do_check_neq(expected[key], undefined);
|
||||
}
|
||||
}
|
||||
|
||||
add_task(function test_StructuredLogCommands() {
|
||||
let appender = new MockAppender(new Log.StructuredFormatter());
|
||||
let logger = Log.repository.getLogger("test.StructuredOutput");
|
||||
logger.addAppender(appender);
|
||||
logger.level = Log.Level.Info;
|
||||
|
||||
logger.logStructured("test_message", {_message: "message string one"});
|
||||
logger.logStructured("test_message", {_message: "message string two",
|
||||
_level: "ERROR",
|
||||
source_file: "test_Log.js"});
|
||||
logger.logStructured("test_message");
|
||||
logger.logStructured("test_message", {source_file: "test_Log.js",
|
||||
message_position: 4});
|
||||
|
||||
let messageOne = {"_time": /\d+/,
|
||||
"_namespace": "test.StructuredOutput",
|
||||
"_level": "INFO",
|
||||
"_message": "message string one",
|
||||
"action": "test_message"};
|
||||
|
||||
let messageTwo = {"_time": /\d+/,
|
||||
"_namespace": "test.StructuredOutput",
|
||||
"_level": "ERROR",
|
||||
"_message": "message string two",
|
||||
"action": "test_message",
|
||||
"source_file": "test_Log.js"};
|
||||
|
||||
let messageThree = {"_time": /\d+/,
|
||||
"_namespace": "test.StructuredOutput",
|
||||
"_level": "INFO",
|
||||
"action": "test_message"};
|
||||
|
||||
let messageFour = {"_time": /\d+/,
|
||||
"_namespace": "test.StructuredOutput",
|
||||
"_level": "INFO",
|
||||
"action": "test_message",
|
||||
"source_file": "test_Log.js",
|
||||
"message_position": 4};
|
||||
|
||||
checkObjects(messageOne, JSON.parse(appender.messages[0]));
|
||||
checkObjects(messageTwo, JSON.parse(appender.messages[1]));
|
||||
checkObjects(messageThree, JSON.parse(appender.messages[2]));
|
||||
checkObjects(messageFour, JSON.parse(appender.messages[3]));
|
||||
|
||||
let errored = false;
|
||||
try {
|
||||
logger.logStructured("", {_message: "invalid message"});
|
||||
} catch (e) {
|
||||
errored = true;
|
||||
do_check_eq(e, "An action is required when logging a structured message.");
|
||||
} finally {
|
||||
do_check_true(errored);
|
||||
}
|
||||
|
||||
errored = false;
|
||||
try {
|
||||
logger.logStructured("message_action", "invalid params");
|
||||
} catch (e) {
|
||||
errored = true;
|
||||
do_check_eq(e, "The params argument is required to be an object.");
|
||||
} finally {
|
||||
do_check_true(errored);
|
||||
}
|
||||
|
||||
// Logging with unstructured interface should produce the same messages
|
||||
// as the structured interface for these cases.
|
||||
appender = new MockAppender(new Log.StructuredFormatter());
|
||||
logger = Log.repository.getLogger("test.StructuredOutput1");
|
||||
messageOne._namespace = "test.StructuredOutput1";
|
||||
messageTwo._namespace = "test.StructuredOutput1";
|
||||
logger.addAppender(appender);
|
||||
logger.level = Log.Level.All;
|
||||
logger.info("message string one", {action: "test_message"});
|
||||
logger.error("message string two", {action: "test_message",
|
||||
source_file: "test_Log.js"});
|
||||
|
||||
checkObjects(messageOne, JSON.parse(appender.messages[0]));
|
||||
checkObjects(messageTwo, JSON.parse(appender.messages[1]));
|
||||
});
|
||||
|
||||
add_task(function test_StorageStreamAppender() {
|
||||
let appender = new Log.StorageStreamAppender(testFormatter);
|
||||
do_check_eq(appender.getInputStream(), null);
|
||||
|
||||
// Log to the storage stream and verify the log was written and can be
|
||||
// read back.
|
||||
let logger = Log.repository.getLogger("test.StorageStreamAppender");
|
||||
logger.addAppender(appender);
|
||||
logger.info("OHAI");
|
||||
let inputStream = appender.getInputStream();
|
||||
let data = NetUtil.readInputStreamToString(inputStream,
|
||||
inputStream.available());
|
||||
do_check_eq(data, "test.StorageStreamAppender\tINFO\tOHAI\n");
|
||||
|
||||
// We can read it again even.
|
||||
let sndInputStream = appender.getInputStream();
|
||||
let sameData = NetUtil.readInputStreamToString(sndInputStream,
|
||||
sndInputStream.available());
|
||||
do_check_eq(data, sameData);
|
||||
|
||||
// Reset the appender and log some more.
|
||||
appender.reset();
|
||||
do_check_eq(appender.getInputStream(), null);
|
||||
logger.debug("wut?!?");
|
||||
inputStream = appender.getInputStream();
|
||||
data = NetUtil.readInputStreamToString(inputStream,
|
||||
inputStream.available());
|
||||
do_check_eq(data, "test.StorageStreamAppender\tDEBUG\twut?!?\n");
|
||||
});
|
||||
|
||||
function fileContents(path) {
|
||||
let decoder = new TextDecoder();
|
||||
return OS.File.read(path).then(array => {
|
||||
return decoder.decode(array);
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function* test_FileAppender() {
|
||||
// This directory does not exist yet
|
||||
let dir = OS.Path.join(do_get_profile().path, "test_Log");
|
||||
do_check_false(yield OS.File.exists(dir));
|
||||
let path = OS.Path.join(dir, "test_FileAppender");
|
||||
let appender = new Log.FileAppender(path, testFormatter);
|
||||
let logger = Log.repository.getLogger("test.FileAppender");
|
||||
logger.addAppender(appender);
|
||||
|
||||
// Logging to a file that can't be created won't do harm.
|
||||
do_check_false(yield OS.File.exists(path));
|
||||
logger.info("OHAI!");
|
||||
|
||||
yield OS.File.makeDir(dir);
|
||||
logger.info("OHAI");
|
||||
yield appender._lastWritePromise;
|
||||
|
||||
do_check_eq((yield fileContents(path)),
|
||||
"test.FileAppender\tINFO\tOHAI\n");
|
||||
|
||||
logger.info("OHAI");
|
||||
yield appender._lastWritePromise;
|
||||
|
||||
do_check_eq((yield fileContents(path)),
|
||||
"test.FileAppender\tINFO\tOHAI\n" +
|
||||
"test.FileAppender\tINFO\tOHAI\n");
|
||||
|
||||
// Reset the appender and log some more.
|
||||
yield appender.reset();
|
||||
do_check_false(yield OS.File.exists(path));
|
||||
|
||||
logger.debug("O RLY?!?");
|
||||
yield appender._lastWritePromise;
|
||||
do_check_eq((yield fileContents(path)),
|
||||
"test.FileAppender\tDEBUG\tO RLY?!?\n");
|
||||
|
||||
yield appender.reset();
|
||||
logger.debug("1");
|
||||
logger.info("2");
|
||||
logger.info("3");
|
||||
logger.info("4");
|
||||
logger.info("5");
|
||||
// Waiting on only the last promise should account for all of these.
|
||||
yield appender._lastWritePromise;
|
||||
|
||||
// Messages ought to be logged in order.
|
||||
do_check_eq((yield fileContents(path)),
|
||||
"test.FileAppender\tDEBUG\t1\n" +
|
||||
"test.FileAppender\tINFO\t2\n" +
|
||||
"test.FileAppender\tINFO\t3\n" +
|
||||
"test.FileAppender\tINFO\t4\n" +
|
||||
"test.FileAppender\tINFO\t5\n");
|
||||
});
|
||||
|
||||
add_task(function* test_BoundedFileAppender() {
|
||||
let dir = OS.Path.join(do_get_profile().path, "test_Log");
|
||||
|
||||
if (!(yield OS.File.exists(dir))) {
|
||||
yield OS.File.makeDir(dir);
|
||||
}
|
||||
|
||||
let path = OS.Path.join(dir, "test_BoundedFileAppender");
|
||||
// This appender will hold about two lines at a time.
|
||||
let appender = new Log.BoundedFileAppender(path, testFormatter, 40);
|
||||
let logger = Log.repository.getLogger("test.BoundedFileAppender");
|
||||
logger.addAppender(appender);
|
||||
|
||||
logger.info("ONE");
|
||||
logger.info("TWO");
|
||||
yield appender._lastWritePromise;
|
||||
|
||||
do_check_eq((yield fileContents(path)),
|
||||
"test.BoundedFileAppender\tINFO\tONE\n" +
|
||||
"test.BoundedFileAppender\tINFO\tTWO\n");
|
||||
|
||||
logger.info("THREE");
|
||||
logger.info("FOUR");
|
||||
|
||||
do_check_neq(appender._removeFilePromise, undefined);
|
||||
yield appender._removeFilePromise;
|
||||
yield appender._lastWritePromise;
|
||||
|
||||
do_check_eq((yield fileContents(path)),
|
||||
"test.BoundedFileAppender\tINFO\tTHREE\n" +
|
||||
"test.BoundedFileAppender\tINFO\tFOUR\n");
|
||||
|
||||
yield appender.reset();
|
||||
logger.info("ONE");
|
||||
logger.info("TWO");
|
||||
logger.info("THREE");
|
||||
logger.info("FOUR");
|
||||
|
||||
do_check_neq(appender._removeFilePromise, undefined);
|
||||
yield appender._removeFilePromise;
|
||||
yield appender._lastWritePromise;
|
||||
|
||||
do_check_eq((yield fileContents(path)),
|
||||
"test.BoundedFileAppender\tINFO\tTHREE\n" +
|
||||
"test.BoundedFileAppender\tINFO\tFOUR\n");
|
||||
|
||||
});
|
||||
|
||||
/*
|
||||
* Test parameter formatting.
|
||||
*/
|
||||
add_task(function* log_message_with_params() {
|
||||
let formatter = new Log.BasicFormatter();
|
||||
|
||||
function formatMessage(text, params) {
|
||||
let full = formatter.format(new Log.LogMessage("test.logger", Log.Level.Warn, text, params));
|
||||
return full.split("\t")[3];
|
||||
}
|
||||
|
||||
// Strings are substituted directly.
|
||||
do_check_eq(formatMessage("String is ${foo}", {foo: "bar"}),
|
||||
"String is bar");
|
||||
|
||||
// Numbers are substituted.
|
||||
do_check_eq(formatMessage("Number is ${number}", {number: 47}),
|
||||
"Number is 47")
|
||||
|
||||
// The entire params object is JSON-formatted and substituted.
|
||||
do_check_eq(formatMessage("Object is ${}", {foo: "bar"}),
|
||||
'Object is {"foo":"bar"}');
|
||||
|
||||
// An object nested inside params is JSON-formatted and substituted.
|
||||
do_check_eq(formatMessage("Sub object is ${sub}", {sub: {foo: "bar"}}),
|
||||
'Sub object is {"foo":"bar"}');
|
||||
|
||||
// The substitution field is missing from params. Leave the placeholder behind
|
||||
// to make the mistake obvious.
|
||||
do_check_eq(formatMessage("Missing object is ${missing}", {}),
|
||||
'Missing object is ${missing}');
|
||||
|
||||
// Make sure we don't treat the parameter name 'false' as a falsey value.
|
||||
do_check_eq(formatMessage("False is ${false}", {false: true}),
|
||||
'False is true');
|
||||
|
||||
// If an object has a .toJSON method, the formatter uses it.
|
||||
let ob = function() {};
|
||||
ob.toJSON = function() {return {sneaky: "value"}};
|
||||
do_check_eq(formatMessage("JSON is ${sub}", {sub: ob}),
|
||||
'JSON is {"sneaky":"value"}');
|
||||
|
||||
// Fall back to .toSource() if JSON.stringify() fails on an object.
|
||||
ob = function() {};
|
||||
ob.toJSON = function() {throw "oh noes JSON"};
|
||||
do_check_eq(formatMessage("Fail is ${sub}", {sub: ob}),
|
||||
'Fail is (function() {})');
|
||||
|
||||
// Fall back to .toString if both .toJSON and .toSource fail.
|
||||
ob.toSource = function() {throw "oh noes SOURCE"};
|
||||
do_check_eq(formatMessage("Fail is ${sub}", {sub: ob}),
|
||||
'Fail is function() {}');
|
||||
|
||||
// Fall back to '[object]' if .toJSON, .toSource and .toString fail.
|
||||
ob.toString = function() {throw "oh noes STRING"};
|
||||
do_check_eq(formatMessage("Fail is ${sub}", {sub: ob}),
|
||||
'Fail is [object]');
|
||||
|
||||
// If params are passed but there are no substitution in the text
|
||||
// we JSON format and append the entire parameters object.
|
||||
do_check_eq(formatMessage("Text with no subs", {a: "b", c: "d"}),
|
||||
'Text with no subs: {"a":"b","c":"d"}');
|
||||
|
||||
// If we substitute one parameter but not the other,
|
||||
// we ignore any params that aren't substituted.
|
||||
do_check_eq(formatMessage("Text with partial sub ${a}", {a: "b", c: "d"}),
|
||||
'Text with partial sub b');
|
||||
|
||||
// We don't format internal fields stored in params.
|
||||
do_check_eq(formatMessage("Params with _ ${}", {a: "b", _c: "d", _level:20, _message:"froo",
|
||||
_time:123456, _namespace:"here.there"}),
|
||||
'Params with _ {"a":"b","_c":"d"}');
|
||||
|
||||
// Don't print an empty params holder if all params are internal.
|
||||
do_check_eq(formatMessage("All params internal", {_level:20, _message:"froo",
|
||||
_time:123456, _namespace:"here.there"}),
|
||||
'All params internal');
|
||||
|
||||
// Format params with null and undefined values.
|
||||
do_check_eq(formatMessage("Null ${n} undefined ${u}", {n: null, u: undefined}),
|
||||
'Null null undefined undefined');
|
||||
|
||||
// Format params with number, bool, and Object/String type.
|
||||
do_check_eq(formatMessage("number ${n} boolean ${b} boxed Boolean ${bx} String ${s}",
|
||||
{n: 45, b: false, bx: new Boolean(true), s: new String("whatevs")}),
|
||||
'number 45 boolean false boxed Boolean true String whatevs');
|
||||
|
||||
/*
|
||||
* Check that errors get special formatting if they're formatted directly as
|
||||
* a named param or they're the only param, but not if they're a field in a
|
||||
* larger structure.
|
||||
*/
|
||||
let err = Components.Exception("test exception", Components.results.NS_ERROR_FAILURE);
|
||||
let str = formatMessage("Exception is ${}", err);
|
||||
do_check_true(str.includes('Exception is [Exception... "test exception"'));
|
||||
do_check_true(str.includes("(NS_ERROR_FAILURE)"));
|
||||
str = formatMessage("Exception is", err);
|
||||
do_check_true(str.includes('Exception is: [Exception... "test exception"'));
|
||||
str = formatMessage("Exception is ${error}", {error: err});
|
||||
do_check_true(str.includes('Exception is [Exception... "test exception"'));
|
||||
str = formatMessage("Exception is", {_error: err});
|
||||
do_print(str);
|
||||
// Exceptions buried inside objects are formatted badly.
|
||||
do_check_true(str.includes('Exception is: {"_error":{}'));
|
||||
// If the message text is null, the message contains only the formatted params object.
|
||||
str = formatMessage(null, err);
|
||||
do_check_true(str.startsWith('[Exception... "test exception"'));
|
||||
// If the text is null and 'params' is a String object, the message is exactly that string.
|
||||
str = formatMessage(null, new String("String in place of params"));
|
||||
do_check_eq(str, "String in place of params");
|
||||
|
||||
// We use object.valueOf() internally; make sure a broken valueOf() method
|
||||
// doesn't cause the logger to fail.
|
||||
let vOf = {a: 1, valueOf: function() {throw "oh noes valueOf"}};
|
||||
do_check_eq(formatMessage("Broken valueOf ${}", vOf),
|
||||
'Broken valueOf ({a:1, valueOf:(function() {throw "oh noes valueOf"})})');
|
||||
|
||||
// Test edge cases of bad data to formatter:
|
||||
// If 'params' is not an object, format it as a basic type.
|
||||
do_check_eq(formatMessage("non-object no subst", 1),
|
||||
'non-object no subst: 1');
|
||||
do_check_eq(formatMessage("non-object all subst ${}", 2),
|
||||
'non-object all subst 2');
|
||||
do_check_eq(formatMessage("false no subst", false),
|
||||
'false no subst: false');
|
||||
do_check_eq(formatMessage("null no subst", null),
|
||||
'null no subst: null');
|
||||
// If 'params' is undefined and there are no substitutions expected,
|
||||
// the message should still be output.
|
||||
do_check_eq(formatMessage("undefined no subst", undefined),
|
||||
'undefined no subst');
|
||||
// If 'params' is not an object, no named substitutions can succeed;
|
||||
// therefore we leave the placeholder and append the formatted params.
|
||||
do_check_eq(formatMessage("non-object named subst ${junk} space", 3),
|
||||
'non-object named subst ${junk} space: 3');
|
||||
// If there are no params, we leave behind the placeholders in the text.
|
||||
do_check_eq(formatMessage("no params ${missing}", undefined),
|
||||
'no params ${missing}');
|
||||
// If params doesn't contain any of the tags requested in the text,
|
||||
// we leave them all behind and append the formatted params.
|
||||
do_check_eq(formatMessage("object missing tag ${missing} space", {mising: "not here"}),
|
||||
'object missing tag ${missing} space: {"mising":"not here"}');
|
||||
// If we are given null text and no params, the resulting formatted message is empty.
|
||||
do_check_eq(formatMessage(null), '');
|
||||
});
|
||||
|
||||
/*
|
||||
* If we call a log function with a non-string object in place of the text
|
||||
* argument, and no parameters, treat that the same as logging empty text
|
||||
* with the object argument as parameters. This makes the log useful when the
|
||||
* caller does "catch(err) {logger.error(err)}"
|
||||
*/
|
||||
add_task(function* test_log_err_only() {
|
||||
let log = Log.repository.getLogger("error.only");
|
||||
let mockFormatter = { format: msg => msg };
|
||||
let appender = new MockAppender(mockFormatter);
|
||||
log.addAppender(appender);
|
||||
|
||||
/*
|
||||
* Check that log.error(err) is treated the same as
|
||||
* log.error(null, err) by the logMessage constructor; the formatMessage()
|
||||
* tests above ensure that the combination of null text and an error object
|
||||
* is formatted correctly.
|
||||
*/
|
||||
try {
|
||||
eval("javascript syntax error");
|
||||
}
|
||||
catch (e) {
|
||||
log.error(e);
|
||||
msg = appender.messages.pop();
|
||||
do_check_eq(msg.message, null);
|
||||
do_check_eq(msg.params, e);
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Test logStructured() messages through basic formatter.
|
||||
*/
|
||||
add_task(function* test_structured_basic() {
|
||||
let log = Log.repository.getLogger("test.logger");
|
||||
let appender = new MockAppender(new Log.BasicFormatter());
|
||||
|
||||
log.level = Log.Level.Info;
|
||||
appender.level = Log.Level.Info;
|
||||
log.addAppender(appender);
|
||||
|
||||
// A structured entry with no _message is treated the same as log./level/(null, params)
|
||||
// except the 'action' field is added to the object.
|
||||
log.logStructured("action", {data: "structure"});
|
||||
do_check_eq(appender.messages.length, 1);
|
||||
do_check_true(appender.messages[0].includes('{"data":"structure","action":"action"}'));
|
||||
|
||||
// A structured entry with _message and substitution is treated the same as
|
||||
// log./level/(null, params).
|
||||
log.logStructured("action", {_message: "Structured sub ${data}", data: "structure"});
|
||||
do_check_eq(appender.messages.length, 2);
|
||||
do_print(appender.messages[1]);
|
||||
do_check_true(appender.messages[1].includes('Structured sub structure'));
|
||||
});
|
||||
|
||||
/*
|
||||
* Test that all the basic logger methods pass the message and params through to the appender.
|
||||
*/
|
||||
add_task(function* log_message_with_params() {
|
||||
let log = Log.repository.getLogger("error.logger");
|
||||
let mockFormatter = { format: msg => msg };
|
||||
let appender = new MockAppender(mockFormatter);
|
||||
log.addAppender(appender);
|
||||
|
||||
let testParams = {a:1, b:2};
|
||||
log.fatal("Test fatal", testParams);
|
||||
log.error("Test error", testParams);
|
||||
log.warn("Test warn", testParams);
|
||||
log.info("Test info", testParams);
|
||||
log.config("Test config", testParams);
|
||||
log.debug("Test debug", testParams);
|
||||
log.trace("Test trace", testParams);
|
||||
do_check_eq(appender.messages.length, 7);
|
||||
for (let msg of appender.messages) {
|
||||
do_check_true(msg.params === testParams);
|
||||
do_check_true(msg.message.startsWith("Test "));
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Check that we format JS Errors reasonably.
|
||||
*/
|
||||
add_task(function* format_errors() {
|
||||
let pFormat = new Log.ParameterFormatter();
|
||||
|
||||
// Test that subclasses of Error are recognized as errors.
|
||||
err = new ReferenceError("Ref Error", "ERROR_FILE", 28);
|
||||
str = pFormat.format(err);
|
||||
do_check_true(str.includes("ReferenceError"));
|
||||
do_check_true(str.includes("ERROR_FILE:28"));
|
||||
do_check_true(str.includes("Ref Error"));
|
||||
|
||||
// Test that JS-generated Errors are recognized and formatted.
|
||||
try {
|
||||
yield Promise.resolve(); // Scrambles the stack
|
||||
eval("javascript syntax error");
|
||||
}
|
||||
catch (e) {
|
||||
str = pFormat.format(e);
|
||||
do_check_true(str.includes("SyntaxError: missing ;"));
|
||||
// Make sure we identified it as an Error and formatted the error location as
|
||||
// lineNumber:columnNumber.
|
||||
do_check_true(str.includes(":1:11)"));
|
||||
// Make sure that we use human-readable stack traces
|
||||
// Check that the error doesn't contain any reference to "Promise.jsm" or "Task.jsm"
|
||||
do_check_false(str.includes("Promise.jsm"));
|
||||
do_check_false(str.includes("Task.jsm"));
|
||||
do_check_true(str.includes("format_errors"));
|
||||
}
|
||||
});
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
print("Define some functions in well defined line positions for the test");
|
||||
function foo(v) { return bar(v + 1); } // line 2
|
||||
function bar(v) { return baz(v + 1); } // line 3
|
||||
function baz(v) { throw new Error(v + 1); } // line 4
|
||||
|
||||
print("Make sure lazy constructor calling/assignment works");
|
||||
Components.utils.import("resource://gre/modules/Log.jsm");
|
||||
|
||||
function run_test() {
|
||||
print("Make sure functions, arguments, files are pretty printed in the trace");
|
||||
let trace = "";
|
||||
try {
|
||||
foo(0);
|
||||
}
|
||||
catch (ex) {
|
||||
trace = Log.stackTrace(ex);
|
||||
}
|
||||
print(`Got trace: ${trace}`);
|
||||
do_check_neq(trace, "");
|
||||
|
||||
let bazPos = trace.indexOf("baz@test_Log_stackTrace.js:4");
|
||||
let barPos = trace.indexOf("bar@test_Log_stackTrace.js:3");
|
||||
let fooPos = trace.indexOf("foo@test_Log_stackTrace.js:2");
|
||||
print(`String positions: ${bazPos} ${barPos} ${fooPos}`);
|
||||
|
||||
print("Make sure the desired messages show up");
|
||||
do_check_true(bazPos >= 0);
|
||||
do_check_true(barPos > bazPos);
|
||||
do_check_true(fooPos > barPos);
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/MatchPattern.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function test(url, pattern) {
|
||||
let uri = Services.io.newURI(url, null, null);
|
||||
let m = new MatchGlobs(pattern);
|
||||
return m.matches(uri.spec);
|
||||
}
|
||||
|
||||
function pass({url, pattern}) {
|
||||
ok(test(url, pattern), `Expected match: ${JSON.stringify(pattern)}, ${url}`);
|
||||
}
|
||||
|
||||
function fail({url, pattern}) {
|
||||
ok(!test(url, pattern), `Expected no match: ${JSON.stringify(pattern)}, ${url}`);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
let moz = "http://mozilla.org";
|
||||
|
||||
pass({url: moz, pattern: ["*"]});
|
||||
pass({url: moz, pattern: ["http://*"]}),
|
||||
pass({url: moz, pattern: ["*mozilla*"]});
|
||||
pass({url: moz, pattern: ["*example*", "*mozilla*"]});
|
||||
|
||||
pass({url: moz, pattern: ["*://*"]});
|
||||
pass({url: "https://mozilla.org", pattern: ["*://*"]});
|
||||
|
||||
// Documentation example
|
||||
pass({url: "http://www.example.com/foo/bar", pattern: ["http://???.example.com/foo/*"]});
|
||||
pass({url: "http://the.example.com/foo/", pattern: ["http://???.example.com/foo/*"]});
|
||||
fail({url: "http://my.example.com/foo/bar", pattern: ["http://???.example.com/foo/*"]});
|
||||
fail({url: "http://example.com/foo/", pattern: ["http://???.example.com/foo/*"]});
|
||||
fail({url: "http://www.example.com/foo", pattern: ["http://???.example.com/foo/*"]});
|
||||
|
||||
// Matches path
|
||||
let path = moz + "/abc/def";
|
||||
pass({url: path, pattern: ["*def"]});
|
||||
pass({url: path, pattern: ["*c/d*"]});
|
||||
pass({url: path, pattern: ["*org/abc*"]});
|
||||
fail({url: path + "/", pattern: ["*def"]});
|
||||
|
||||
// Trailing slash
|
||||
pass({url: moz, pattern: ["*.org/"]});
|
||||
fail({url: moz, pattern: ["*.org"]});
|
||||
|
||||
// Wrong TLD
|
||||
fail({url: moz, pattern: ["www*.m*.com/"]});
|
||||
// Case sensitive
|
||||
fail({url: moz, pattern: ["*.ORG/"]});
|
||||
|
||||
fail({url: moz, pattern: []});
|
||||
}
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/MatchPattern.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function test(url, pattern)
|
||||
{
|
||||
let uri = Services.io.newURI(url, null, null);
|
||||
let m = new MatchPattern(pattern);
|
||||
return m.matches(uri);
|
||||
}
|
||||
|
||||
function pass({url, pattern})
|
||||
{
|
||||
do_check_true(test(url, pattern), `Expected match: ${JSON.stringify(pattern)}, ${url}`);
|
||||
}
|
||||
|
||||
function fail({url, pattern})
|
||||
{
|
||||
do_check_false(test(url, pattern), `Expected no match: ${JSON.stringify(pattern)}, ${url}`);
|
||||
}
|
||||
|
||||
function run_test()
|
||||
{
|
||||
// Invalid pattern.
|
||||
fail({url: "http://mozilla.org", pattern: ""});
|
||||
|
||||
// Pattern must include trailing slash.
|
||||
fail({url: "http://mozilla.org", pattern: "http://mozilla.org"});
|
||||
|
||||
// Protocol not allowed.
|
||||
fail({url: "http://mozilla.org", pattern: "gopher://wuarchive.wustl.edu/"});
|
||||
|
||||
pass({url: "http://mozilla.org", pattern: "http://mozilla.org/"});
|
||||
pass({url: "http://mozilla.org/", pattern: "http://mozilla.org/"});
|
||||
|
||||
pass({url: "http://mozilla.org/", pattern: "*://mozilla.org/"});
|
||||
pass({url: "https://mozilla.org/", pattern: "*://mozilla.org/"});
|
||||
fail({url: "file://mozilla.org/", pattern: "*://mozilla.org/"});
|
||||
fail({url: "ftp://mozilla.org/", pattern: "*://mozilla.org/"});
|
||||
|
||||
fail({url: "http://mozilla.com", pattern: "http://*mozilla.com*/"});
|
||||
fail({url: "http://mozilla.com", pattern: "http://mozilla.*/"});
|
||||
fail({url: "http://mozilla.com", pattern: "http:/mozilla.com/"});
|
||||
|
||||
pass({url: "http://google.com", pattern: "http://*.google.com/"});
|
||||
pass({url: "http://docs.google.com", pattern: "http://*.google.com/"});
|
||||
|
||||
pass({url: "http://mozilla.org:8080", pattern: "http://mozilla.org/"});
|
||||
pass({url: "http://mozilla.org:8080", pattern: "*://mozilla.org/"});
|
||||
fail({url: "http://mozilla.org:8080", pattern: "http://mozilla.org:8080/"});
|
||||
|
||||
// Now try with * in the path.
|
||||
pass({url: "http://mozilla.org", pattern: "http://mozilla.org/*"});
|
||||
pass({url: "http://mozilla.org/", pattern: "http://mozilla.org/*"});
|
||||
|
||||
pass({url: "http://mozilla.org/", pattern: "*://mozilla.org/*"});
|
||||
pass({url: "https://mozilla.org/", pattern: "*://mozilla.org/*"});
|
||||
fail({url: "file://mozilla.org/", pattern: "*://mozilla.org/*"});
|
||||
fail({url: "http://mozilla.com", pattern: "http://mozilla.*/*"});
|
||||
|
||||
pass({url: "http://google.com", pattern: "http://*.google.com/*"});
|
||||
pass({url: "http://docs.google.com", pattern: "http://*.google.com/*"});
|
||||
|
||||
// Check path stuff.
|
||||
fail({url: "http://mozilla.com/abc/def", pattern: "http://mozilla.com/"});
|
||||
pass({url: "http://mozilla.com/abc/def", pattern: "http://mozilla.com/*"});
|
||||
pass({url: "http://mozilla.com/abc/def", pattern: "http://mozilla.com/a*f"});
|
||||
pass({url: "http://mozilla.com/abc/def", pattern: "http://mozilla.com/a*"});
|
||||
pass({url: "http://mozilla.com/abc/def", pattern: "http://mozilla.com/*f"});
|
||||
fail({url: "http://mozilla.com/abc/def", pattern: "http://mozilla.com/*e"});
|
||||
fail({url: "http://mozilla.com/abc/def", pattern: "http://mozilla.com/*c"});
|
||||
|
||||
fail({url: "http:///a.html", pattern: "http:///a.html"});
|
||||
pass({url: "file:///foo", pattern: "file:///foo*"});
|
||||
pass({url: "file:///foo/bar.html", pattern: "file:///foo*"});
|
||||
|
||||
pass({url: "http://mozilla.org/a", pattern: "<all_urls>"});
|
||||
pass({url: "https://mozilla.org/a", pattern: "<all_urls>"});
|
||||
pass({url: "ftp://mozilla.org/a", pattern: "<all_urls>"});
|
||||
pass({url: "file:///a", pattern: "<all_urls>"});
|
||||
fail({url: "gopher://wuarchive.wustl.edu/a", pattern: "<all_urls>"});
|
||||
|
||||
// Multiple patterns.
|
||||
pass({url: "http://mozilla.org", pattern: ["http://mozilla.org/"]});
|
||||
pass({url: "http://mozilla.org", pattern: ["http://mozilla.org/", "http://mozilla.com/"]});
|
||||
pass({url: "http://mozilla.com", pattern: ["http://mozilla.org/", "http://mozilla.com/"]});
|
||||
fail({url: "http://mozilla.biz", pattern: ["http://mozilla.org/", "http://mozilla.com/"]});
|
||||
|
||||
// Match url with fragments.
|
||||
pass({url: "http://mozilla.org/base#some-fragment", pattern: "http://mozilla.org/base"});
|
||||
}
|
||||
|
|
@ -1,396 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/MatchPattern.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function createTestFilter({url, filters}) {
|
||||
let m = new MatchURLFilters(filters);
|
||||
return m.matches(url);
|
||||
}
|
||||
|
||||
function expectPass({url, filters}) {
|
||||
ok(createTestFilter({url, filters}),
|
||||
`Expected match: ${JSON.stringify(filters)}, ${url}`);
|
||||
}
|
||||
|
||||
function expectFail({url, filters}) {
|
||||
ok(!createTestFilter({url, filters}),
|
||||
`Expected no match: ${JSON.stringify(filters)}, ${url}`);
|
||||
}
|
||||
|
||||
function expectThrow({url, filters, exceptionMessageContains}) {
|
||||
let logData = {filters, url};
|
||||
|
||||
Assert.throws(
|
||||
() => {
|
||||
createTestFilter({url, filters});
|
||||
},
|
||||
exceptionMessageContains,
|
||||
`Check received exception for expected message: ${JSON.stringify(logData)}`
|
||||
);
|
||||
}
|
||||
|
||||
add_task(function* test_match_url_filters() {
|
||||
const shouldPass = true;
|
||||
const shouldFail = true;
|
||||
const shouldThrow = true;
|
||||
|
||||
var testCases = [
|
||||
// Empty, undefined and null filters.
|
||||
{shouldThrow, exceptionMessageContains: "filters array should not be empty",
|
||||
filters: [], url: "http://mozilla.org", },
|
||||
{shouldThrow, exceptionMessageContains: "filters should be an array",
|
||||
filters: undefined, url: "http://mozilla.org"},
|
||||
{shouldThrow, exceptionMessageContains: "filters should be an array",
|
||||
filters: null, url: "http://mozilla.org"},
|
||||
|
||||
// Wrong formats (in a real webextension this will be blocked by the schema validation).
|
||||
{shouldThrow, exceptionMessageContains: "filters should be an array", filters: {},
|
||||
url: "http://mozilla.org"},
|
||||
{shouldThrow, exceptionMessageContains: "filters should be an array",
|
||||
filters: {nonExistentCriteria: true}, url: "http://mozilla.org", },
|
||||
{shouldPass, filters: [{nonExistentCriteria: true}], url: "http://mozilla.org"},
|
||||
|
||||
// Schemes filter over various url schemes.
|
||||
{shouldPass, filters: [{schemes: ["http"]}], url: "http://mozilla.org"},
|
||||
{shouldPass, filters: [{schemes: ["https"]}], url: "https://mozilla.org"},
|
||||
{shouldPass, filters: [{schemes: ["ftp"]}], url: "ftp://fake/ftp/url"},
|
||||
{shouldPass, filters: [{schemes: ["about"]}], url: "about:blank"},
|
||||
{shouldPass, filters: [{schemes: ["data"]}], url: "data:,testDataURL"},
|
||||
{shouldFail, filters: [{schemes: ["http"]}], url: "ftp://fake/ftp/url"},
|
||||
|
||||
// Multiple schemes: pass when at least one scheme matches.
|
||||
{shouldPass, filters: [{schemes: ["https", "about"]}], url: "https://mozilla.org"},
|
||||
{shouldPass, filters: [{schemes: ["about", "https"]}], url: "https://mozilla.org"},
|
||||
{shouldFail, filters: [{schemes: ["about", "http"]}], url: "https://mozilla.org"},
|
||||
|
||||
// Port filter: standard (implicit) ports.
|
||||
{shouldPass, filters: [{ports: [443]}], url: "https://mozilla.org"},
|
||||
{shouldPass, filters: [{ports: [80]}], url: "http://mozilla.org"},
|
||||
{shouldPass, filters: [{ports: [21]}], url: "ftp://ftp.mozilla.org"},
|
||||
|
||||
// Port filter: schemes without a default port.
|
||||
{shouldFail, filters: [{ports: [-1]}], url: "about:blank"},
|
||||
{shouldFail, filters: [{ports: [-1]}], url: "data:,testDataURL"},
|
||||
|
||||
{shouldFail, filters: [{ports: [[1, 65535]]}], url: "about:blank"},
|
||||
{shouldFail, filters: [{ports: [[1, 65535]]}], url: "data:,testDataURL"},
|
||||
|
||||
// Host filters (hostEquals, hostContains, hostPrefix, hostSuffix): schemes with an host.
|
||||
{shouldFail, filters: [{hostEquals: ""}], url: "https://mozilla.org"},
|
||||
{shouldPass, filters: [{hostEquals: null}], url: "https://mozilla.org"},
|
||||
{shouldPass, filters: [{hostEquals: "mozilla.org"}], url: "https://mozilla.org"},
|
||||
{shouldFail, filters: [{hostEquals: "mozilla.com"}], url: "https://mozilla.org"},
|
||||
// NOTE: trying at least once another valid protocol.
|
||||
{shouldPass, filters: [{hostEquals: "mozilla.org"}], url: "ftp://mozilla.org"},
|
||||
{shouldFail, filters: [{hostEquals: "mozilla.com"}], url: "ftp://mozilla.org"},
|
||||
{shouldPass, filters: [{hostEquals: "mozilla.org"}], url: "https://mozilla.org:8888"},
|
||||
|
||||
{shouldPass, filters: [{hostContains: "moz"}], url: "https://mozilla.org"},
|
||||
// NOTE: an implicit '.' char is inserted into the host.
|
||||
{shouldPass, filters: [{hostContains: ".moz"}], url: "https://mozilla.org"},
|
||||
{shouldFail, filters: [{hostContains: "com"}], url: "https://mozilla.org"},
|
||||
{shouldPass, filters: [{hostContains: ""}], url: "https://mozilla.org"},
|
||||
{shouldPass, filters: [{hostContains: null}], url: "https://mozilla.org"},
|
||||
|
||||
{shouldPass, filters: [{hostPrefix: "moz"}], url: "https://mozilla.org"},
|
||||
{shouldFail, filters: [{hostPrefix: "org"}], url: "https://mozilla.org"},
|
||||
{shouldPass, filters: [{hostPrefix: ""}], url: "https://mozilla.org"},
|
||||
{shouldPass, filters: [{hostPrefix: null}], url: "https://mozilla.org"},
|
||||
|
||||
{shouldPass, filters: [{hostSuffix: ".org"}], url: "https://mozilla.org"},
|
||||
{shouldFail, filters: [{hostSuffix: "moz"}], url: "https://mozilla.org"},
|
||||
{shouldPass, filters: [{hostSuffix: ""}], url: "https://mozilla.org"},
|
||||
{shouldPass, filters: [{hostSuffix: null}], url: "https://mozilla.org"},
|
||||
{shouldPass, filters: [{hostSuffix: "lla.org"}], url: "https://mozilla.org:8888"},
|
||||
|
||||
// hostEquals: urls without an host.
|
||||
// TODO: should we explicitly cover hostContains, hostPrefix, hostSuffix for
|
||||
// these sub-cases?
|
||||
{shouldFail, filters: [{hostEquals: "blank"}], url: "about:blank"},
|
||||
{shouldFail, filters: [{hostEquals: "blank"}], url: "about://blank"},
|
||||
{shouldFail, filters: [{hostEquals: "testDataURL"}], url: "data:,testDataURL"},
|
||||
{shouldPass, filters: [{hostEquals: ""}], url: "about:blank"},
|
||||
{shouldPass, filters: [{hostEquals: ""}], url: "about://blank"},
|
||||
{shouldPass, filters: [{hostEquals: ""}], url: "data:,testDataURL"},
|
||||
|
||||
// Path filters (pathEquals, pathContains, pathPrefix, pathSuffix).
|
||||
{shouldFail, filters: [{pathEquals: ""}], url: "https://mozilla.org/test/path"},
|
||||
{shouldPass, filters: [{pathEquals: null}], url: "https://mozilla.org/test/path"},
|
||||
{shouldPass, filters: [{pathEquals: "/test/path"}], url: "https://mozilla.org/test/path"},
|
||||
{shouldFail, filters: [{pathEquals: "/wrong/path"}], url: "https://mozilla.org/test/path"},
|
||||
{shouldPass, filters: [{pathEquals: "/test/path"}], url: "https://mozilla.org:8888/test/path"},
|
||||
// NOTE: trying at least once another valid protocol
|
||||
{shouldPass, filters: [{pathEquals: "/test/path"}], url: "ftp://mozilla.org/test/path"},
|
||||
{shouldFail, filters: [{pathEquals: "/wrong/path"}], url: "ftp://mozilla.org/test/path"},
|
||||
|
||||
{shouldPass, filters: [{pathContains: "st/"}], url: "https://mozilla.org/test/path"},
|
||||
{shouldPass, filters: [{pathContains: "/test"}], url: "https://mozilla.org/test/path"},
|
||||
{shouldFail, filters: [{pathContains: "org"}], url: "https://mozilla.org/test/path"},
|
||||
{shouldPass, filters: [{pathContains: ""}], url: "https://mozilla.org/test/path"},
|
||||
{shouldPass, filters: [{pathContains: null}], url: "https://mozilla.org/test/path"},
|
||||
{shouldFail, filters: [{pathContains: "param"}], url: "https://mozilla.org:8888/test/path?param=1"},
|
||||
{shouldFail, filters: [{pathContains: "ref"}], url: "https://mozilla.org:8888/test/path#ref"},
|
||||
{shouldPass, filters: [{pathContains: "st/pa"}], url: "https://mozilla.org:8888/test/path"},
|
||||
|
||||
{shouldPass, filters: [{pathPrefix: "/te"}], url: "https://mozilla.org/test/path"},
|
||||
{shouldFail, filters: [{pathPrefix: "org/"}], url: "https://mozilla.org/test/path"},
|
||||
{shouldPass, filters: [{pathPrefix: ""}], url: "https://mozilla.org/test/path"},
|
||||
{shouldPass, filters: [{pathPrefix: null}], url: "https://mozilla.org/test/path"},
|
||||
|
||||
{shouldPass, filters: [{pathSuffix: "/path"}], url: "https://mozilla.org/test/path"},
|
||||
{shouldFail, filters: [{pathSuffix: "th/"}], url: "https://mozilla.org/test/path"},
|
||||
{shouldPass, filters: [{pathSuffix: ""}], url: "https://mozilla.org/test/path"},
|
||||
{shouldPass, filters: [{pathSuffix: null}], url: "https://mozilla.org/test/path"},
|
||||
{shouldFail, filters: [{pathSuffix: "p=1"}], url: "https://mozilla.org:8888/test/path?p=1"},
|
||||
{shouldFail, filters: [{pathSuffix: "ref"}], url: "https://mozilla.org:8888/test/path#ref"},
|
||||
|
||||
// Query filters (queryEquals, queryContains, queryPrefix, querySuffix).
|
||||
{shouldFail, filters: [{queryEquals: ""}], url: "https://mozilla.org/?param=val"},
|
||||
{shouldPass, filters: [{queryEquals: null}], url: "https://mozilla.org/?param=val"},
|
||||
{shouldPass, filters: [{queryEquals: "param=val"}], url: "https://mozilla.org/?param=val"},
|
||||
{shouldFail, filters: [{queryEquals: "?param=val"}], url: "https://mozilla.org/?param=val"},
|
||||
{shouldFail, filters: [{queryEquals: "/path?param=val"}], url: "https://mozilla.org/path?param=val"},
|
||||
|
||||
// NOTE: about scheme urls cannot be matched by query.
|
||||
{shouldFail, filters: [{queryEquals: "param=val"}], url: "about:blank?param=val"},
|
||||
{shouldFail, filters: [{queryEquals: "param"}], url: "ftp://mozilla.org?param=val"},
|
||||
|
||||
{shouldPass, filters: [{queryContains: "ram"}], url: "https://mozilla.org/?param=val"},
|
||||
{shouldPass, filters: [{queryContains: "=val"}], url: "https://mozilla.org/?param=val"},
|
||||
{shouldFail, filters: [{queryContains: "?param"}], url: "https://mozilla.org/?param=val"},
|
||||
{shouldFail, filters: [{queryContains: "path"}], url: "https://mozilla.org/path/?p=v#ref"},
|
||||
{shouldPass, filters: [{queryContains: ""}], url: "https://mozilla.org/?param=val"},
|
||||
{shouldPass, filters: [{queryContains: null}], url: "https://mozilla.org/?param=val"},
|
||||
|
||||
{shouldPass, filters: [{queryPrefix: "param"}], url: "https://mozilla.org/?param=val"},
|
||||
{shouldFail, filters: [{queryPrefix: "p="}], url: "https://mozilla.org/?param=val"},
|
||||
{shouldFail, filters: [{queryPrefix: "path"}], url: "https://mozilla.org/path?param=val"},
|
||||
{shouldPass, filters: [{queryPrefix: ""}], url: "https://mozilla.org/?param=val"},
|
||||
{shouldPass, filters: [{queryPrefix: null}], url: "https://mozilla.org/?param=val"},
|
||||
|
||||
{shouldPass, filters: [{querySuffix: "=val"}], url: "https://mozilla.org/?param=val"},
|
||||
{shouldFail, filters: [{querySuffix: "=wrong"}], url: "https://mozilla.org/?param=val"},
|
||||
{shouldPass, filters: [{querySuffix: ""}], url: "https://mozilla.org/?param=val"},
|
||||
{shouldPass, filters: [{querySuffix: null}], url: "https://mozilla.org/?param=val"},
|
||||
|
||||
// URL filters (urlEquals, urlContains, urlPrefix, urlSuffix).
|
||||
{shouldFail, filters: [{urlEquals: ""}], url: "https://mozilla.org/?p=v#ref"},
|
||||
{shouldPass, filters: [{urlEquals: null}], url: "https://mozilla.org/?p=v#ref"},
|
||||
{shouldPass, filters: [{urlEquals: "https://mozilla.org/?p=v#ref"}],
|
||||
url: "https://mozilla.org/?p=v#ref"},
|
||||
{shouldFail, filters: [{urlEquals: "https://mozilla.org/?p=v#ref2"}],
|
||||
url: "https://mozilla.org/?p=v#ref"},
|
||||
{shouldPass, filters: [{urlEquals: "about:blank?p=v#ref"}], url: "about:blank?p=v#ref"},
|
||||
{shouldPass, filters: [{urlEquals: "ftp://mozilla.org?p=v#ref"}],
|
||||
url: "ftp://mozilla.org?p=v#ref"},
|
||||
|
||||
{shouldPass, filters: [{urlContains: "org/?p"}], url: "https://mozilla.org/?p=v#ref"},
|
||||
{shouldPass, filters: [{urlContains: "=v#ref"}], url: "https://mozilla.org/?p=v#ref"},
|
||||
{shouldFail, filters: [{urlContains: "ftp"}], url: "https://mozilla.org/?p=v#ref"},
|
||||
{shouldPass, filters: [{urlContains: ""}], url: "https://mozilla.org/?p=v#ref"},
|
||||
{shouldPass, filters: [{urlContains: null}], url: "https://mozilla.org/?p=v#ref"},
|
||||
|
||||
{shouldPass, filters: [{urlPrefix: "http"}], url: "https://mozilla.org/?p=v#ref"},
|
||||
{shouldFail, filters: [{urlPrefix: "moz"}], url: "https://mozilla.org/?p=v#ref"},
|
||||
{shouldPass, filters: [{urlPrefix: ""}], url: "https://mozilla.org/?p=v#ref"},
|
||||
{shouldPass, filters: [{urlPrefix: null}], url: "https://mozilla.org/?p=v#ref"},
|
||||
|
||||
{shouldPass, filters: [{urlSuffix: "#ref"}], url: "https://mozilla.org/?p=v#ref"},
|
||||
{shouldFail, filters: [{urlSuffix: "=wrong"}], url: "https://mozilla.org/?p=v#ref"},
|
||||
{shouldPass, filters: [{urlSuffix: ""}], url: "https://mozilla.org/?p=v#ref"},
|
||||
{shouldPass, filters: [{urlSuffix: null}], url: "https://mozilla.org/?p=v#ref"},
|
||||
|
||||
// More url filters: urlMatches.
|
||||
{shouldPass, filters: [{urlMatches: ".*://mozilla"}], url: "https://mozilla.org/?p=v#ref"},
|
||||
{shouldPass, filters: [{urlMatches: ".*://mozilla"}], url: "ftp://mozilla.org/?p=v#ref"},
|
||||
{shouldPass, filters: [{urlMatches: ".*://.*/\?p"}], url: "ftp://mozilla.org/?p=v#ref"},
|
||||
// NOTE: urlMatches should not match the url without the ref.
|
||||
{shouldFail, filters: [{urlMatches: "v#ref$"}], url: "https://mozilla.org/?p=v#ref"},
|
||||
{shouldPass, filters: [{urlMatches: "^ftp"}], url: "ftp://mozilla.org/?p=v#ref"},
|
||||
|
||||
// More url filters: originAndPathMatches.
|
||||
{shouldPass, filters: [{originAndPathMatches: ".*://mozilla"}],
|
||||
url: "https://mozilla.org/?p=v#ref"},
|
||||
{shouldPass, filters: [{originAndPathMatches: ".*://mozilla"}],
|
||||
url: "ftp://mozilla.org/?p=v#ref"},
|
||||
// NOTE: urlMatches should not match the url without the query and the ref.
|
||||
{shouldFail, filters: [{originAndPathMatches: ".*://.*/\?p"}],
|
||||
url: "ftp://mozilla.org/?p=v#ref"},
|
||||
{shouldFail, filters: [{originAndPathMatches: "v#ref$"}],
|
||||
url: "https://mozilla.org/?p=v#ref"},
|
||||
{shouldPass, filters: [{originAndPathMatches: "^ftp"}],
|
||||
url: "ftp://mozilla.org/?p=v#ref"},
|
||||
|
||||
// Filter with all criteria: all matches, none matches, some matches.
|
||||
|
||||
// All matches.
|
||||
{shouldPass, filters: [
|
||||
{
|
||||
schemes: ["https", "http"],
|
||||
ports: [443, 80],
|
||||
hostEquals: "www.mozilla.org",
|
||||
hostContains: ".moz",
|
||||
hostPrefix: "www",
|
||||
hostSuffix: "org",
|
||||
pathEquals: "/sub/path",
|
||||
pathContains: "b/p",
|
||||
pathPrefix: "/sub",
|
||||
pathSuffix: "/path",
|
||||
queryEquals: "p=v",
|
||||
queryContains: "1=",
|
||||
queryPrefix: "p1",
|
||||
querySuffix: "=v",
|
||||
urlEquals: "https://www.mozilla.org/sub/path?p1=v#ref",
|
||||
urlContains: "org/sub",
|
||||
urlPrefix: "https://moz",
|
||||
urlSuffix: "#ref",
|
||||
urlMatches: "v#ref$",
|
||||
originAndPathMatches: ".*://moz.*/"
|
||||
},
|
||||
], url: "https://www.mozilla.org/sub/path?p1=v#ref"},
|
||||
// None matches.
|
||||
{shouldFail, filters: [
|
||||
{
|
||||
schemes: ["http"],
|
||||
ports: [80],
|
||||
hostEquals: "mozilla.com",
|
||||
hostContains: "www.moz",
|
||||
hostPrefix: "www",
|
||||
hostSuffix: "com",
|
||||
pathEquals: "/wrong/path",
|
||||
pathContains: "g/p",
|
||||
pathPrefix: "/wrong",
|
||||
pathSuffix: "/wrong",
|
||||
queryEquals: "p2=v",
|
||||
queryContains: "2=",
|
||||
queryPrefix: "p2",
|
||||
querySuffix: "=value",
|
||||
urlEquals: "http://mozilla.com/sub/path?p1=v#ref",
|
||||
urlContains: "com/sub",
|
||||
urlPrefix: "http://moz",
|
||||
urlSuffix: "#ref2",
|
||||
urlMatches: "value#ref2$",
|
||||
originAndPathMatches: ".*://moz.*com/"
|
||||
},
|
||||
], url: "https://mozilla.org/sub/path?p1=v#ref"},
|
||||
// Some matches
|
||||
{shouldFail, filters: [
|
||||
{
|
||||
schemes: ["https"],
|
||||
ports: [80],
|
||||
hostEquals: "mozilla.com",
|
||||
hostContains: "www.moz",
|
||||
hostPrefix: "www",
|
||||
hostSuffix: "com",
|
||||
pathEquals: "/wrong/path",
|
||||
pathContains: "g/p",
|
||||
pathPrefix: "/wrong",
|
||||
pathSuffix: "/wrong",
|
||||
queryEquals: "p2=v",
|
||||
queryContains: "2=",
|
||||
queryPrefix: "p2",
|
||||
querySuffix: "=value",
|
||||
urlEquals: "http://mozilla.com/sub/path?p1=v#ref",
|
||||
urlContains: "com/sub",
|
||||
urlPrefix: "http://moz",
|
||||
urlSuffix: "#ref2",
|
||||
urlMatches: "value#ref2$",
|
||||
originAndPathMatches: ".*://moz.*com/"
|
||||
},
|
||||
], url: "https://mozilla.org/sub/path?p1=v#ref"},
|
||||
|
||||
// Filter with multiple filters: all matches, some matches, none matches.
|
||||
|
||||
// All matches.
|
||||
{shouldPass, filters: [
|
||||
{schemes: ["https", "http"]},
|
||||
{ports: [443, 80]},
|
||||
{hostEquals: "www.mozilla.org"},
|
||||
{hostContains: ".moz"},
|
||||
{hostPrefix: "www"},
|
||||
{hostSuffix: "org"},
|
||||
{pathEquals: "/sub/path"},
|
||||
{pathContains: "b/p"},
|
||||
{pathPrefix: "/sub"},
|
||||
{pathSuffix: "/path"},
|
||||
{queryEquals: "p=v"},
|
||||
{queryContains: "1="},
|
||||
{queryPrefix: "p1"},
|
||||
{querySuffix: "=v"},
|
||||
{urlEquals: "https://www.mozilla.org/sub/path?p1=v#ref"},
|
||||
{urlContains: "org/sub"},
|
||||
{urlPrefix: "https://moz"},
|
||||
{urlSuffix: "#ref"},
|
||||
{urlMatches: "v#ref$"},
|
||||
{originAndPathMatches: ".*://moz.*/"},
|
||||
], url: "https://www.mozilla.org/sub/path?p1=v#ref"},
|
||||
|
||||
// None matches.
|
||||
{shouldFail, filters: [
|
||||
{schemes: ["http"]},
|
||||
{ports: [80]},
|
||||
{hostEquals: "mozilla.com"},
|
||||
{hostContains: "www.moz"},
|
||||
{hostPrefix: "www"},
|
||||
{hostSuffix: "com"},
|
||||
{pathEquals: "/wrong/path"},
|
||||
{pathContains: "g/p"},
|
||||
{pathPrefix: "/wrong"},
|
||||
{pathSuffix: "/wrong"},
|
||||
{queryEquals: "p2=v"},
|
||||
{queryContains: "2="},
|
||||
{queryPrefix: "p2"},
|
||||
{querySuffix: "=value"},
|
||||
{urlEquals: "http://mozilla.com/sub/path?p1=v#ref"},
|
||||
{urlContains: "com/sub"},
|
||||
{urlPrefix: "http://moz"},
|
||||
{urlSuffix: "#ref2"},
|
||||
{urlMatches: "value#ref2$"},
|
||||
{originAndPathMatches: ".*://moz.*com/"},
|
||||
], url: "https://mozilla.org/sub/path?p1=v#ref"},
|
||||
|
||||
// Some matches.
|
||||
{shouldPass, filters: [
|
||||
{schemes: ["https"]},
|
||||
{ports: [80]},
|
||||
{hostEquals: "mozilla.com"},
|
||||
{hostContains: "www.moz"},
|
||||
{hostPrefix: "www"},
|
||||
{hostSuffix: "com"},
|
||||
{pathEquals: "/wrong/path"},
|
||||
{pathContains: "g/p"},
|
||||
{pathPrefix: "/wrong"},
|
||||
{pathSuffix: "/wrong"},
|
||||
{queryEquals: "p2=v"},
|
||||
{queryContains: "2="},
|
||||
{queryPrefix: "p2"},
|
||||
{querySuffix: "=value"},
|
||||
{urlEquals: "http://mozilla.com/sub/path?p1=v#ref"},
|
||||
{urlContains: "com/sub"},
|
||||
{urlPrefix: "http://moz"},
|
||||
{urlSuffix: "#ref2"},
|
||||
{urlMatches: "value#ref2$"},
|
||||
{originAndPathMatches: ".*://moz.*com/"},
|
||||
], url: "https://mozilla.org/sub/path?p1=v#ref"},
|
||||
];
|
||||
|
||||
// Run all the the testCases defined above.
|
||||
for (let currentTest of testCases) {
|
||||
let {
|
||||
exceptionMessageContains,
|
||||
url, filters,
|
||||
} = currentTest;
|
||||
|
||||
if (currentTest.shouldThrow) {
|
||||
expectThrow({url, filters, exceptionMessageContains})
|
||||
} else if (currentTest.shouldFail) {
|
||||
expectFail({url, filters});
|
||||
} else {
|
||||
expectPass({url, filters});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -1,378 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// See also browser/base/content/test/newtab/.
|
||||
|
||||
var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
|
||||
Cu.import("resource://gre/modules/NewTabUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const PREF_NEWTAB_ENHANCED = "browser.newtabpage.enhanced";
|
||||
|
||||
function run_test() {
|
||||
Services.prefs.setBoolPref(PREF_NEWTAB_ENHANCED, true);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* validCacheMidPopulation() {
|
||||
let expectedLinks = makeLinks(0, 3, 1);
|
||||
|
||||
let provider = new TestProvider(done => done(expectedLinks));
|
||||
provider.maxNumLinks = expectedLinks.length;
|
||||
|
||||
NewTabUtils.initWithoutProviders();
|
||||
NewTabUtils.links.addProvider(provider);
|
||||
let promise = new Promise(resolve => NewTabUtils.links.populateCache(resolve));
|
||||
|
||||
// isTopSiteGivenProvider() and getProviderLinks() should still return results
|
||||
// even when cache is empty or being populated.
|
||||
do_check_false(NewTabUtils.isTopSiteGivenProvider("example1.com", provider));
|
||||
do_check_links(NewTabUtils.getProviderLinks(provider), []);
|
||||
|
||||
yield promise;
|
||||
|
||||
// Once the cache is populated, we get the expected results
|
||||
do_check_true(NewTabUtils.isTopSiteGivenProvider("example1.com", provider));
|
||||
do_check_links(NewTabUtils.getProviderLinks(provider), expectedLinks);
|
||||
NewTabUtils.links.removeProvider(provider);
|
||||
});
|
||||
|
||||
add_task(function* notifyLinkDelete() {
|
||||
let expectedLinks = makeLinks(0, 3, 1);
|
||||
|
||||
let provider = new TestProvider(done => done(expectedLinks));
|
||||
provider.maxNumLinks = expectedLinks.length;
|
||||
|
||||
NewTabUtils.initWithoutProviders();
|
||||
NewTabUtils.links.addProvider(provider);
|
||||
yield new Promise(resolve => NewTabUtils.links.populateCache(resolve));
|
||||
|
||||
do_check_links(NewTabUtils.links.getLinks(), expectedLinks);
|
||||
|
||||
// Remove a link.
|
||||
let removedLink = expectedLinks[2];
|
||||
provider.notifyLinkChanged(removedLink, 2, true);
|
||||
let links = NewTabUtils.links._providers.get(provider);
|
||||
|
||||
// Check that sortedLinks is correctly updated.
|
||||
do_check_links(NewTabUtils.links.getLinks(), expectedLinks.slice(0, 2));
|
||||
|
||||
// Check that linkMap is accurately updated.
|
||||
do_check_eq(links.linkMap.size, 2);
|
||||
do_check_true(links.linkMap.get(expectedLinks[0].url));
|
||||
do_check_true(links.linkMap.get(expectedLinks[1].url));
|
||||
do_check_false(links.linkMap.get(removedLink.url));
|
||||
|
||||
// Check that siteMap is correctly updated.
|
||||
do_check_eq(links.siteMap.size, 2);
|
||||
do_check_true(links.siteMap.has(NewTabUtils.extractSite(expectedLinks[0].url)));
|
||||
do_check_true(links.siteMap.has(NewTabUtils.extractSite(expectedLinks[1].url)));
|
||||
do_check_false(links.siteMap.has(NewTabUtils.extractSite(removedLink.url)));
|
||||
|
||||
NewTabUtils.links.removeProvider(provider);
|
||||
});
|
||||
|
||||
add_task(function* populatePromise() {
|
||||
let count = 0;
|
||||
let expectedLinks = makeLinks(0, 10, 2);
|
||||
|
||||
let getLinksFcn = Task.async(function* (callback) {
|
||||
// Should not be calling getLinksFcn twice
|
||||
count++;
|
||||
do_check_eq(count, 1);
|
||||
yield Promise.resolve();
|
||||
callback(expectedLinks);
|
||||
});
|
||||
|
||||
let provider = new TestProvider(getLinksFcn);
|
||||
|
||||
NewTabUtils.initWithoutProviders();
|
||||
NewTabUtils.links.addProvider(provider);
|
||||
|
||||
NewTabUtils.links.populateProviderCache(provider, () => {});
|
||||
NewTabUtils.links.populateProviderCache(provider, () => {
|
||||
do_check_links(NewTabUtils.links.getLinks(), expectedLinks);
|
||||
NewTabUtils.links.removeProvider(provider);
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function* isTopSiteGivenProvider() {
|
||||
let expectedLinks = makeLinks(0, 10, 2);
|
||||
|
||||
// The lowest 2 frecencies have the same base domain.
|
||||
expectedLinks[expectedLinks.length - 2].url = expectedLinks[expectedLinks.length - 1].url + "Test";
|
||||
|
||||
let provider = new TestProvider(done => done(expectedLinks));
|
||||
provider.maxNumLinks = expectedLinks.length;
|
||||
|
||||
NewTabUtils.initWithoutProviders();
|
||||
NewTabUtils.links.addProvider(provider);
|
||||
yield new Promise(resolve => NewTabUtils.links.populateCache(resolve));
|
||||
|
||||
do_check_eq(NewTabUtils.isTopSiteGivenProvider("example2.com", provider), true);
|
||||
do_check_eq(NewTabUtils.isTopSiteGivenProvider("example1.com", provider), false);
|
||||
|
||||
// Push out frecency 2 because the maxNumLinks is reached when adding frecency 3
|
||||
let newLink = makeLink(3);
|
||||
provider.notifyLinkChanged(newLink);
|
||||
|
||||
// There is still a frecent url with example2 domain, so it's still frecent.
|
||||
do_check_eq(NewTabUtils.isTopSiteGivenProvider("example3.com", provider), true);
|
||||
do_check_eq(NewTabUtils.isTopSiteGivenProvider("example2.com", provider), true);
|
||||
|
||||
// Push out frecency 3
|
||||
newLink = makeLink(5);
|
||||
provider.notifyLinkChanged(newLink);
|
||||
|
||||
// Push out frecency 4
|
||||
newLink = makeLink(9);
|
||||
provider.notifyLinkChanged(newLink);
|
||||
|
||||
// Our count reached 0 for the example2.com domain so it's no longer a frecent site.
|
||||
do_check_eq(NewTabUtils.isTopSiteGivenProvider("example5.com", provider), true);
|
||||
do_check_eq(NewTabUtils.isTopSiteGivenProvider("example2.com", provider), false);
|
||||
|
||||
NewTabUtils.links.removeProvider(provider);
|
||||
});
|
||||
|
||||
add_task(function* multipleProviders() {
|
||||
// Make each provider generate NewTabUtils.links.maxNumLinks links to check
|
||||
// that no more than maxNumLinks are actually returned in the merged list.
|
||||
let evenLinks = makeLinks(0, 2 * NewTabUtils.links.maxNumLinks, 2);
|
||||
let evenProvider = new TestProvider(done => done(evenLinks));
|
||||
let oddLinks = makeLinks(0, 2 * NewTabUtils.links.maxNumLinks - 1, 2);
|
||||
let oddProvider = new TestProvider(done => done(oddLinks));
|
||||
|
||||
NewTabUtils.initWithoutProviders();
|
||||
NewTabUtils.links.addProvider(evenProvider);
|
||||
NewTabUtils.links.addProvider(oddProvider);
|
||||
|
||||
yield new Promise(resolve => NewTabUtils.links.populateCache(resolve));
|
||||
|
||||
let links = NewTabUtils.links.getLinks();
|
||||
let expectedLinks = makeLinks(NewTabUtils.links.maxNumLinks,
|
||||
2 * NewTabUtils.links.maxNumLinks,
|
||||
1);
|
||||
do_check_eq(links.length, NewTabUtils.links.maxNumLinks);
|
||||
do_check_links(links, expectedLinks);
|
||||
|
||||
NewTabUtils.links.removeProvider(evenProvider);
|
||||
NewTabUtils.links.removeProvider(oddProvider);
|
||||
});
|
||||
|
||||
add_task(function* changeLinks() {
|
||||
let expectedLinks = makeLinks(0, 20, 2);
|
||||
let provider = new TestProvider(done => done(expectedLinks));
|
||||
|
||||
NewTabUtils.initWithoutProviders();
|
||||
NewTabUtils.links.addProvider(provider);
|
||||
|
||||
yield new Promise(resolve => NewTabUtils.links.populateCache(resolve));
|
||||
|
||||
do_check_links(NewTabUtils.links.getLinks(), expectedLinks);
|
||||
|
||||
// Notify of a new link.
|
||||
let newLink = makeLink(19);
|
||||
expectedLinks.splice(1, 0, newLink);
|
||||
provider.notifyLinkChanged(newLink);
|
||||
do_check_links(NewTabUtils.links.getLinks(), expectedLinks);
|
||||
|
||||
// Notify of a link that's changed sort criteria.
|
||||
newLink.frecency = 17;
|
||||
expectedLinks.splice(1, 1);
|
||||
expectedLinks.splice(2, 0, newLink);
|
||||
provider.notifyLinkChanged({
|
||||
url: newLink.url,
|
||||
frecency: 17,
|
||||
});
|
||||
do_check_links(NewTabUtils.links.getLinks(), expectedLinks);
|
||||
|
||||
// Notify of a link that's changed title.
|
||||
newLink.title = "My frecency is now 17";
|
||||
provider.notifyLinkChanged({
|
||||
url: newLink.url,
|
||||
title: newLink.title,
|
||||
});
|
||||
do_check_links(NewTabUtils.links.getLinks(), expectedLinks);
|
||||
|
||||
// Notify of a new link again, but this time make it overflow maxNumLinks.
|
||||
provider.maxNumLinks = expectedLinks.length;
|
||||
newLink = makeLink(21);
|
||||
expectedLinks.unshift(newLink);
|
||||
expectedLinks.pop();
|
||||
do_check_eq(expectedLinks.length, provider.maxNumLinks); // Sanity check.
|
||||
provider.notifyLinkChanged(newLink);
|
||||
do_check_links(NewTabUtils.links.getLinks(), expectedLinks);
|
||||
|
||||
// Notify of many links changed.
|
||||
expectedLinks = makeLinks(0, 3, 1);
|
||||
provider.notifyManyLinksChanged();
|
||||
|
||||
// Since _populateProviderCache() is async, we must wait until the provider's
|
||||
// populate promise has been resolved.
|
||||
yield NewTabUtils.links._providers.get(provider).populatePromise;
|
||||
|
||||
// NewTabUtils.links will now repopulate its cache
|
||||
do_check_links(NewTabUtils.links.getLinks(), expectedLinks);
|
||||
|
||||
NewTabUtils.links.removeProvider(provider);
|
||||
});
|
||||
|
||||
add_task(function* oneProviderAlreadyCached() {
|
||||
let links1 = makeLinks(0, 10, 1);
|
||||
let provider1 = new TestProvider(done => done(links1));
|
||||
|
||||
NewTabUtils.initWithoutProviders();
|
||||
NewTabUtils.links.addProvider(provider1);
|
||||
|
||||
yield new Promise(resolve => NewTabUtils.links.populateCache(resolve));
|
||||
do_check_links(NewTabUtils.links.getLinks(), links1);
|
||||
|
||||
let links2 = makeLinks(10, 20, 1);
|
||||
let provider2 = new TestProvider(done => done(links2));
|
||||
NewTabUtils.links.addProvider(provider2);
|
||||
|
||||
yield new Promise(resolve => NewTabUtils.links.populateCache(resolve));
|
||||
do_check_links(NewTabUtils.links.getLinks(), links2.concat(links1));
|
||||
|
||||
NewTabUtils.links.removeProvider(provider1);
|
||||
NewTabUtils.links.removeProvider(provider2);
|
||||
});
|
||||
|
||||
add_task(function* newLowRankedLink() {
|
||||
// Init a provider with 10 links and make its maximum number also 10.
|
||||
let links = makeLinks(0, 10, 1);
|
||||
let provider = new TestProvider(done => done(links));
|
||||
provider.maxNumLinks = links.length;
|
||||
|
||||
NewTabUtils.initWithoutProviders();
|
||||
NewTabUtils.links.addProvider(provider);
|
||||
|
||||
yield new Promise(resolve => NewTabUtils.links.populateCache(resolve));
|
||||
do_check_links(NewTabUtils.links.getLinks(), links);
|
||||
|
||||
// Notify of a new link that's low-ranked enough not to make the list.
|
||||
let newLink = makeLink(0);
|
||||
provider.notifyLinkChanged(newLink);
|
||||
do_check_links(NewTabUtils.links.getLinks(), links);
|
||||
|
||||
// Notify about the new link's title change.
|
||||
provider.notifyLinkChanged({
|
||||
url: newLink.url,
|
||||
title: "a new title",
|
||||
});
|
||||
do_check_links(NewTabUtils.links.getLinks(), links);
|
||||
|
||||
NewTabUtils.links.removeProvider(provider);
|
||||
});
|
||||
|
||||
add_task(function* extractSite() {
|
||||
// All these should extract to the same site
|
||||
[ "mozilla.org",
|
||||
"m.mozilla.org",
|
||||
"mobile.mozilla.org",
|
||||
"www.mozilla.org",
|
||||
"www3.mozilla.org",
|
||||
].forEach(host => {
|
||||
let url = "http://" + host;
|
||||
do_check_eq(NewTabUtils.extractSite(url), "mozilla.org", "extracted same " + host);
|
||||
});
|
||||
|
||||
// All these should extract to the same subdomain
|
||||
[ "bugzilla.mozilla.org",
|
||||
"www.bugzilla.mozilla.org",
|
||||
].forEach(host => {
|
||||
let url = "http://" + host;
|
||||
do_check_eq(NewTabUtils.extractSite(url), "bugzilla.mozilla.org", "extracted eTLD+2 " + host);
|
||||
});
|
||||
|
||||
// All these should not extract to the same site
|
||||
[ "bugzilla.mozilla.org",
|
||||
"bug123.bugzilla.mozilla.org",
|
||||
"too.many.levels.bugzilla.mozilla.org",
|
||||
"m2.mozilla.org",
|
||||
"mobile30.mozilla.org",
|
||||
"ww.mozilla.org",
|
||||
"ww2.mozilla.org",
|
||||
"wwwww.mozilla.org",
|
||||
"wwwww50.mozilla.org",
|
||||
"wwws.mozilla.org",
|
||||
"secure.mozilla.org",
|
||||
"secure10.mozilla.org",
|
||||
"many.levels.deep.mozilla.org",
|
||||
"just.check.in",
|
||||
"192.168.0.1",
|
||||
"localhost",
|
||||
].forEach(host => {
|
||||
let url = "http://" + host;
|
||||
do_check_neq(NewTabUtils.extractSite(url), "mozilla.org", "extracted diff " + host);
|
||||
});
|
||||
|
||||
// All these should not extract to the same site
|
||||
[ "about:blank",
|
||||
"file:///Users/user/file",
|
||||
"chrome://browser/something",
|
||||
"ftp://ftp.mozilla.org/",
|
||||
].forEach(url => {
|
||||
do_check_neq(NewTabUtils.extractSite(url), "mozilla.org", "extracted diff url " + url);
|
||||
});
|
||||
});
|
||||
|
||||
function TestProvider(getLinksFn) {
|
||||
this.getLinks = getLinksFn;
|
||||
this._observers = new Set();
|
||||
}
|
||||
|
||||
TestProvider.prototype = {
|
||||
addObserver: function (observer) {
|
||||
this._observers.add(observer);
|
||||
},
|
||||
notifyLinkChanged: function (link, index=-1, deleted=false) {
|
||||
this._notifyObservers("onLinkChanged", link, index, deleted);
|
||||
},
|
||||
notifyManyLinksChanged: function () {
|
||||
this._notifyObservers("onManyLinksChanged");
|
||||
},
|
||||
_notifyObservers: function () {
|
||||
let observerMethodName = arguments[0];
|
||||
let args = Array.prototype.slice.call(arguments, 1);
|
||||
args.unshift(this);
|
||||
for (let obs of this._observers) {
|
||||
if (obs[observerMethodName])
|
||||
obs[observerMethodName].apply(NewTabUtils.links, args);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
function do_check_links(actualLinks, expectedLinks) {
|
||||
do_check_true(Array.isArray(actualLinks));
|
||||
do_check_eq(actualLinks.length, expectedLinks.length);
|
||||
for (let i = 0; i < expectedLinks.length; i++) {
|
||||
let expected = expectedLinks[i];
|
||||
let actual = actualLinks[i];
|
||||
do_check_eq(actual.url, expected.url);
|
||||
do_check_eq(actual.title, expected.title);
|
||||
do_check_eq(actual.frecency, expected.frecency);
|
||||
do_check_eq(actual.lastVisitDate, expected.lastVisitDate);
|
||||
}
|
||||
}
|
||||
|
||||
function makeLinks(frecRangeStart, frecRangeEnd, step) {
|
||||
let links = [];
|
||||
// Remember, links are ordered by frecency descending.
|
||||
for (let i = frecRangeEnd; i > frecRangeStart; i -= step) {
|
||||
links.push(makeLink(i));
|
||||
}
|
||||
return links;
|
||||
}
|
||||
|
||||
function makeLink(frecency) {
|
||||
return {
|
||||
url: "http://example" + frecency + ".com/",
|
||||
title: "My frecency is " + frecency,
|
||||
frecency: frecency,
|
||||
lastVisitDate: 0,
|
||||
};
|
||||
}
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
Components.utils.import("resource://gre/modules/ObjectUtils.jsm");
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_deepEqual() {
|
||||
let deepEqual = ObjectUtils.deepEqual.bind(ObjectUtils);
|
||||
// CommonJS 7.2
|
||||
Assert.ok(deepEqual(new Date(2000, 3, 14), new Date(2000, 3, 14)), "deepEqual date");
|
||||
Assert.ok(deepEqual(new Date(NaN), new Date(NaN)), "deepEqual invalid dates");
|
||||
|
||||
Assert.ok(!deepEqual(new Date(), new Date(2000, 3, 14)), "deepEqual date");
|
||||
|
||||
// 7.3
|
||||
Assert.ok(deepEqual(/a/, /a/));
|
||||
Assert.ok(deepEqual(/a/g, /a/g));
|
||||
Assert.ok(deepEqual(/a/i, /a/i));
|
||||
Assert.ok(deepEqual(/a/m, /a/m));
|
||||
Assert.ok(deepEqual(/a/igm, /a/igm));
|
||||
Assert.ok(!deepEqual(/ab/, /a/));
|
||||
Assert.ok(!deepEqual(/a/g, /a/));
|
||||
Assert.ok(!deepEqual(/a/i, /a/));
|
||||
Assert.ok(!deepEqual(/a/m, /a/));
|
||||
Assert.ok(!deepEqual(/a/igm, /a/im));
|
||||
|
||||
let re1 = /a/;
|
||||
re1.lastIndex = 3;
|
||||
Assert.ok(!deepEqual(re1, /a/));
|
||||
|
||||
// 7.4
|
||||
Assert.ok(deepEqual(4, "4"), "deepEqual == check");
|
||||
Assert.ok(deepEqual(true, 1), "deepEqual == check");
|
||||
Assert.ok(!deepEqual(4, "5"), "deepEqual == check");
|
||||
|
||||
// 7.5
|
||||
// having the same number of owned properties && the same set of keys
|
||||
Assert.ok(deepEqual({a: 4}, {a: 4}));
|
||||
Assert.ok(deepEqual({a: 4, b: "2"}, {a: 4, b: "2"}));
|
||||
Assert.ok(deepEqual([4], ["4"]));
|
||||
Assert.ok(!deepEqual({a: 4}, {a: 4, b: true}));
|
||||
Assert.ok(deepEqual(["a"], {0: "a"}));
|
||||
|
||||
let a1 = [1, 2, 3];
|
||||
let a2 = [1, 2, 3];
|
||||
a1.a = "test";
|
||||
a1.b = true;
|
||||
a2.b = true;
|
||||
a2.a = "test";
|
||||
Assert.ok(!deepEqual(Object.keys(a1), Object.keys(a2)));
|
||||
Assert.ok(deepEqual(a1, a2));
|
||||
|
||||
let nbRoot = {
|
||||
toString: function() { return this.first + " " + this.last; }
|
||||
};
|
||||
|
||||
function nameBuilder(first, last) {
|
||||
this.first = first;
|
||||
this.last = last;
|
||||
return this;
|
||||
}
|
||||
nameBuilder.prototype = nbRoot;
|
||||
|
||||
function nameBuilder2(first, last) {
|
||||
this.first = first;
|
||||
this.last = last;
|
||||
return this;
|
||||
}
|
||||
nameBuilder2.prototype = nbRoot;
|
||||
|
||||
let nb1 = new nameBuilder("Ryan", "Dahl");
|
||||
let nb2 = new nameBuilder2("Ryan", "Dahl");
|
||||
|
||||
Assert.ok(deepEqual(nb1, nb2));
|
||||
|
||||
nameBuilder2.prototype = Object;
|
||||
nb2 = new nameBuilder2("Ryan", "Dahl");
|
||||
Assert.ok(!deepEqual(nb1, nb2));
|
||||
|
||||
// String literal + object
|
||||
Assert.ok(!deepEqual("a", {}));
|
||||
|
||||
// Make sure deepEqual doesn't loop forever on circular refs
|
||||
|
||||
let b = {};
|
||||
b.b = b;
|
||||
|
||||
let c = {};
|
||||
c.b = c;
|
||||
|
||||
try {
|
||||
Assert.ok(!deepEqual(b, c));
|
||||
} catch (e) {
|
||||
Assert.ok(true, "Didn't recurse infinitely.");
|
||||
}
|
||||
});
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
var {ObjectUtils} = Components.utils.import("resource://gre/modules/ObjectUtils.jsm", {});
|
||||
var {PromiseTestUtils} = Components.utils.import("resource://testing-common/PromiseTestUtils.jsm", {});
|
||||
|
||||
add_task(function* test_strict() {
|
||||
let loose = { a: 1 };
|
||||
let strict = ObjectUtils.strict(loose);
|
||||
|
||||
loose.a; // Should not throw.
|
||||
loose.b || undefined; // Should not throw.
|
||||
|
||||
strict.a; // Should not throw.
|
||||
PromiseTestUtils.expectUncaughtRejection(/No such property: "b"/);
|
||||
Assert.throws(() => strict.b, /No such property: "b"/);
|
||||
"b" in strict; // Should not throw.
|
||||
strict.b = 2;
|
||||
strict.b; // Should not throw.
|
||||
|
||||
PromiseTestUtils.expectUncaughtRejection(/No such property: "c"/);
|
||||
Assert.throws(() => strict.c, /No such property: "c"/);
|
||||
"c" in strict; // Should not throw.
|
||||
loose.c = 3;
|
||||
strict.c; // Should not throw.
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// Tests that PerrmissionsUtils.jsm works as expected, including:
|
||||
// * PermissionsUtils.importfromPrefs()
|
||||
// <ROOT>.[whitelist|blacklist].add preferences are emptied when
|
||||
// converted into permissions on startup.
|
||||
|
||||
|
||||
const PREF_ROOT = "testpermissions.";
|
||||
const TEST_PERM = "test-permission";
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource://gre/modules/PermissionsUtils.jsm");
|
||||
|
||||
function run_test() {
|
||||
test_importfromPrefs();
|
||||
}
|
||||
|
||||
|
||||
function test_importfromPrefs() {
|
||||
// Create own preferences to test
|
||||
Services.prefs.setCharPref(PREF_ROOT + "whitelist.add.EMPTY", "");
|
||||
Services.prefs.setCharPref(PREF_ROOT + "whitelist.add.EMPTY2", ",");
|
||||
Services.prefs.setCharPref(PREF_ROOT + "whitelist.add.TEST", "http://whitelist.example.com");
|
||||
Services.prefs.setCharPref(PREF_ROOT + "whitelist.add.TEST2", "https://whitelist2-1.example.com,http://whitelist2-2.example.com:8080,about:home");
|
||||
Services.prefs.setCharPref(PREF_ROOT + "whitelist.add.TEST3", "whitelist3-1.example.com,about:config"); // legacy style - host only
|
||||
Services.prefs.setCharPref(PREF_ROOT + "blacklist.add.EMPTY", "");
|
||||
Services.prefs.setCharPref(PREF_ROOT + "blacklist.add.TEST", "http://blacklist.example.com,");
|
||||
Services.prefs.setCharPref(PREF_ROOT + "blacklist.add.TEST2", ",https://blacklist2-1.example.com,http://blacklist2-2.example.com:8080,about:mozilla");
|
||||
Services.prefs.setCharPref(PREF_ROOT + "blacklist.add.TEST3", "blacklist3-1.example.com,about:preferences"); // legacy style - host only
|
||||
|
||||
// Check they are unknown in the permission manager prior to importing.
|
||||
let whitelisted = ["http://whitelist.example.com",
|
||||
"https://whitelist2-1.example.com",
|
||||
"http://whitelist2-2.example.com:8080",
|
||||
"http://whitelist3-1.example.com",
|
||||
"https://whitelist3-1.example.com",
|
||||
"about:config",
|
||||
"about:home"];
|
||||
let blacklisted = ["http://blacklist.example.com",
|
||||
"https://blacklist2-1.example.com",
|
||||
"http://blacklist2-2.example.com:8080",
|
||||
"http://blacklist3-1.example.com",
|
||||
"https://blacklist3-1.example.com",
|
||||
"about:preferences",
|
||||
"about:mozilla"];
|
||||
let untouched = ["https://whitelist.example.com",
|
||||
"https://blacklist.example.com",
|
||||
"http://whitelist2-1.example.com",
|
||||
"http://blacklist2-1.example.com",
|
||||
"https://whitelist2-2.example.com:8080",
|
||||
"https://blacklist2-2.example.com:8080"];
|
||||
let unknown = whitelisted.concat(blacklisted).concat(untouched);
|
||||
for (let url of unknown) {
|
||||
let uri = Services.io.newURI(url, null, null);
|
||||
do_check_eq(Services.perms.testPermission(uri, TEST_PERM), Services.perms.UNKNOWN_ACTION);
|
||||
}
|
||||
|
||||
// Import them
|
||||
PermissionsUtils.importFromPrefs(PREF_ROOT, TEST_PERM);
|
||||
|
||||
// Get list of preferences to check
|
||||
let preferences = Services.prefs.getChildList(PREF_ROOT, {});
|
||||
|
||||
// Check preferences were emptied
|
||||
for (let pref of preferences) {
|
||||
do_check_eq(Services.prefs.getCharPref(pref), "");
|
||||
}
|
||||
|
||||
// Check they were imported into the permissions manager
|
||||
for (let url of whitelisted) {
|
||||
let uri = Services.io.newURI(url, null, null);
|
||||
do_check_eq(Services.perms.testPermission(uri, TEST_PERM), Services.perms.ALLOW_ACTION);
|
||||
}
|
||||
for (let url of blacklisted) {
|
||||
let uri = Services.io.newURI(url, null, null);
|
||||
do_check_eq(Services.perms.testPermission(uri, TEST_PERM), Services.perms.DENY_ACTION);
|
||||
}
|
||||
for (let url of untouched) {
|
||||
let uri = Services.io.newURI(url, null, null);
|
||||
do_check_eq(Services.perms.testPermission(uri, TEST_PERM), Services.perms.UNKNOWN_ACTION);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,378 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
var {classes: Cc, interfaces: Ci, results: Cr, utils: Cu, manager: Cm} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_test(function test_set_get_pref() {
|
||||
Preferences.set("test_set_get_pref.integer", 1);
|
||||
do_check_eq(Preferences.get("test_set_get_pref.integer"), 1);
|
||||
|
||||
Preferences.set("test_set_get_pref.string", "foo");
|
||||
do_check_eq(Preferences.get("test_set_get_pref.string"), "foo");
|
||||
|
||||
Preferences.set("test_set_get_pref.boolean", true);
|
||||
do_check_eq(Preferences.get("test_set_get_pref.boolean"), true);
|
||||
|
||||
// Clean up.
|
||||
Preferences.resetBranch("test_set_get_pref.");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_set_get_branch_pref() {
|
||||
let prefs = new Preferences("test_set_get_branch_pref.");
|
||||
|
||||
prefs.set("something", 1);
|
||||
do_check_eq(prefs.get("something"), 1);
|
||||
do_check_false(Preferences.has("something"));
|
||||
|
||||
// Clean up.
|
||||
prefs.reset("something");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_set_get_multiple_prefs() {
|
||||
Preferences.set({ "test_set_get_multiple_prefs.integer": 1,
|
||||
"test_set_get_multiple_prefs.string": "foo",
|
||||
"test_set_get_multiple_prefs.boolean": true });
|
||||
|
||||
let [i, s, b] = Preferences.get(["test_set_get_multiple_prefs.integer",
|
||||
"test_set_get_multiple_prefs.string",
|
||||
"test_set_get_multiple_prefs.boolean"]);
|
||||
|
||||
do_check_eq(i, 1);
|
||||
do_check_eq(s, "foo");
|
||||
do_check_eq(b, true);
|
||||
|
||||
// Clean up.
|
||||
Preferences.resetBranch("test_set_get_multiple_prefs.");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_get_multiple_prefs_with_default_value() {
|
||||
Preferences.set({ "test_get_multiple_prefs_with_default_value.a": 1,
|
||||
"test_get_multiple_prefs_with_default_value.b": 2 });
|
||||
|
||||
let [a, b, c] = Preferences.get(["test_get_multiple_prefs_with_default_value.a",
|
||||
"test_get_multiple_prefs_with_default_value.b",
|
||||
"test_get_multiple_prefs_with_default_value.c"],
|
||||
0);
|
||||
|
||||
do_check_eq(a, 1);
|
||||
do_check_eq(b, 2);
|
||||
do_check_eq(c, 0);
|
||||
|
||||
// Clean up.
|
||||
Preferences.resetBranch("test_get_multiple_prefs_with_default_value.");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_set_get_unicode_pref() {
|
||||
Preferences.set("test_set_get_unicode_pref", String.fromCharCode(960));
|
||||
do_check_eq(Preferences.get("test_set_get_unicode_pref"), String.fromCharCode(960));
|
||||
|
||||
// Clean up.
|
||||
Preferences.reset("test_set_get_unicode_pref");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_set_null_pref() {
|
||||
try {
|
||||
Preferences.set("test_set_null_pref", null);
|
||||
// We expect this to throw, so the test is designed to fail if it doesn't.
|
||||
do_check_true(false);
|
||||
}
|
||||
catch (ex) {}
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_set_undefined_pref() {
|
||||
try {
|
||||
Preferences.set("test_set_undefined_pref");
|
||||
// We expect this to throw, so the test is designed to fail if it doesn't.
|
||||
do_check_true(false);
|
||||
}
|
||||
catch (ex) {}
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_set_unsupported_pref() {
|
||||
try {
|
||||
Preferences.set("test_set_unsupported_pref", new Array());
|
||||
// We expect this to throw, so the test is designed to fail if it doesn't.
|
||||
do_check_true(false);
|
||||
}
|
||||
catch (ex) {}
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// Make sure that we can get a string pref that we didn't set ourselves
|
||||
// (i.e. that the way we get a string pref using getComplexValue doesn't
|
||||
// hork us getting a string pref that wasn't set using setComplexValue).
|
||||
add_test(function test_get_string_pref() {
|
||||
let svc = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefService).
|
||||
getBranch("");
|
||||
svc.setCharPref("test_get_string_pref", "a normal string");
|
||||
do_check_eq(Preferences.get("test_get_string_pref"), "a normal string");
|
||||
|
||||
// Clean up.
|
||||
Preferences.reset("test_get_string_pref");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_get_localized_string_pref() {
|
||||
let svc = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefService).
|
||||
getBranch("");
|
||||
let prefName = "test_get_localized_string_pref";
|
||||
let localizedString = Cc["@mozilla.org/pref-localizedstring;1"]
|
||||
.createInstance(Ci.nsIPrefLocalizedString);
|
||||
localizedString.data = "a localized string";
|
||||
svc.setComplexValue(prefName, Ci.nsIPrefLocalizedString, localizedString);
|
||||
do_check_eq(Preferences.get(prefName, null, Ci.nsIPrefLocalizedString),
|
||||
"a localized string");
|
||||
|
||||
// Clean up.
|
||||
Preferences.reset(prefName);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_set_get_number_pref() {
|
||||
Preferences.set("test_set_get_number_pref", 5);
|
||||
do_check_eq(Preferences.get("test_set_get_number_pref"), 5);
|
||||
|
||||
// Non-integer values get converted to integers.
|
||||
Preferences.set("test_set_get_number_pref", 3.14159);
|
||||
do_check_eq(Preferences.get("test_set_get_number_pref"), 3);
|
||||
|
||||
// Values outside the range -(2^31-1) to 2^31-1 overflow.
|
||||
try {
|
||||
Preferences.set("test_set_get_number_pref", Math.pow(2, 31));
|
||||
// We expect this to throw, so the test is designed to fail if it doesn't.
|
||||
do_check_true(false);
|
||||
}
|
||||
catch (ex) {}
|
||||
|
||||
// Clean up.
|
||||
Preferences.reset("test_set_get_number_pref");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_reset_pref() {
|
||||
Preferences.set("test_reset_pref", 1);
|
||||
Preferences.reset("test_reset_pref");
|
||||
do_check_eq(Preferences.get("test_reset_pref"), undefined);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_reset_pref_branch() {
|
||||
Preferences.set("test_reset_pref_branch.foo", 1);
|
||||
Preferences.set("test_reset_pref_branch.bar", 2);
|
||||
Preferences.resetBranch("test_reset_pref_branch.");
|
||||
do_check_eq(Preferences.get("test_reset_pref_branch.foo"), undefined);
|
||||
do_check_eq(Preferences.get("test_reset_pref_branch.bar"), undefined);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// Make sure the module doesn't throw an exception when asked to reset
|
||||
// a nonexistent pref.
|
||||
add_test(function test_reset_nonexistent_pref() {
|
||||
Preferences.reset("test_reset_nonexistent_pref");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// Make sure the module doesn't throw an exception when asked to reset
|
||||
// a nonexistent pref branch.
|
||||
add_test(function test_reset_nonexistent_pref_branch() {
|
||||
Preferences.resetBranch("test_reset_nonexistent_pref_branch.");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_observe_prefs_function() {
|
||||
let observed = false;
|
||||
let observer = function() { observed = !observed };
|
||||
|
||||
Preferences.observe("test_observe_prefs_function", observer);
|
||||
Preferences.set("test_observe_prefs_function", "something");
|
||||
do_check_true(observed);
|
||||
|
||||
Preferences.ignore("test_observe_prefs_function", observer);
|
||||
Preferences.set("test_observe_prefs_function", "something else");
|
||||
do_check_true(observed);
|
||||
|
||||
// Clean up.
|
||||
Preferences.reset("test_observe_prefs_function");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_observe_prefs_object() {
|
||||
let observer = {
|
||||
observed: false,
|
||||
observe: function() {
|
||||
this.observed = !this.observed;
|
||||
}
|
||||
};
|
||||
|
||||
Preferences.observe("test_observe_prefs_object", observer.observe, observer);
|
||||
Preferences.set("test_observe_prefs_object", "something");
|
||||
do_check_true(observer.observed);
|
||||
|
||||
Preferences.ignore("test_observe_prefs_object", observer.observe, observer);
|
||||
Preferences.set("test_observe_prefs_object", "something else");
|
||||
do_check_true(observer.observed);
|
||||
|
||||
// Clean up.
|
||||
Preferences.reset("test_observe_prefs_object");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_observe_prefs_nsIObserver() {
|
||||
let observer = {
|
||||
observed: false,
|
||||
observe: function(subject, topic, data) {
|
||||
this.observed = !this.observed;
|
||||
do_check_true(subject instanceof Ci.nsIPrefBranch);
|
||||
do_check_eq(topic, "nsPref:changed");
|
||||
do_check_eq(data, "test_observe_prefs_nsIObserver");
|
||||
}
|
||||
};
|
||||
|
||||
Preferences.observe("test_observe_prefs_nsIObserver", observer);
|
||||
Preferences.set("test_observe_prefs_nsIObserver", "something");
|
||||
do_check_true(observer.observed);
|
||||
|
||||
Preferences.ignore("test_observe_prefs_nsIObserver", observer);
|
||||
Preferences.set("test_observe_prefs_nsIObserver", "something else");
|
||||
do_check_true(observer.observed);
|
||||
|
||||
// Clean up.
|
||||
Preferences.reset("test_observe_prefs_nsIObserver");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
/*
|
||||
add_test(function test_observe_exact_pref() {
|
||||
let observed = false;
|
||||
let observer = function() { observed = !observed };
|
||||
|
||||
Preferences.observe("test_observe_exact_pref", observer);
|
||||
Preferences.set("test_observe_exact_pref.sub-pref", "something");
|
||||
do_check_false(observed);
|
||||
|
||||
// Clean up.
|
||||
Preferences.ignore("test_observe_exact_pref", observer);
|
||||
Preferences.reset("test_observe_exact_pref.sub-pref");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
*/
|
||||
|
||||
add_test(function test_observe_value_of_set_pref() {
|
||||
let observer = function(newVal) { do_check_eq(newVal, "something") };
|
||||
|
||||
Preferences.observe("test_observe_value_of_set_pref", observer);
|
||||
Preferences.set("test_observe_value_of_set_pref", "something");
|
||||
|
||||
// Clean up.
|
||||
Preferences.ignore("test_observe_value_of_set_pref", observer);
|
||||
Preferences.reset("test_observe_value_of_set_pref");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_observe_value_of_reset_pref() {
|
||||
let observer = function(newVal) { do_check_true(typeof newVal == "undefined") };
|
||||
|
||||
Preferences.set("test_observe_value_of_reset_pref", "something");
|
||||
Preferences.observe("test_observe_value_of_reset_pref", observer);
|
||||
Preferences.reset("test_observe_value_of_reset_pref");
|
||||
|
||||
// Clean up.
|
||||
Preferences.ignore("test_observe_value_of_reset_pref", observer);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_has_pref() {
|
||||
do_check_false(Preferences.has("test_has_pref"));
|
||||
Preferences.set("test_has_pref", "foo");
|
||||
do_check_true(Preferences.has("test_has_pref"));
|
||||
|
||||
Preferences.set("test_has_pref.foo", "foo");
|
||||
Preferences.set("test_has_pref.bar", "bar");
|
||||
let [hasFoo, hasBar, hasBaz] = Preferences.has(["test_has_pref.foo",
|
||||
"test_has_pref.bar",
|
||||
"test_has_pref.baz"]);
|
||||
do_check_true(hasFoo);
|
||||
do_check_true(hasBar);
|
||||
do_check_false(hasBaz);
|
||||
|
||||
// Clean up.
|
||||
Preferences.resetBranch("test_has_pref");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_isSet_pref() {
|
||||
// Use a pref that we know has a default value but no user-set value.
|
||||
// This feels dangerous; perhaps we should create some other default prefs
|
||||
// that we can use for testing.
|
||||
do_check_false(Preferences.isSet("toolkit.defaultChromeURI"));
|
||||
Preferences.set("toolkit.defaultChromeURI", "foo");
|
||||
do_check_true(Preferences.isSet("toolkit.defaultChromeURI"));
|
||||
|
||||
// Clean up.
|
||||
Preferences.reset("toolkit.defaultChromeURI");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
/*
|
||||
add_test(function test_lock_prefs() {
|
||||
// Use a pref that we know has a default value.
|
||||
// This feels dangerous; perhaps we should create some other default prefs
|
||||
// that we can use for testing.
|
||||
do_check_false(Preferences.locked("toolkit.defaultChromeURI"));
|
||||
Preferences.lock("toolkit.defaultChromeURI");
|
||||
do_check_true(Preferences.locked("toolkit.defaultChromeURI"));
|
||||
Preferences.unlock("toolkit.defaultChromeURI");
|
||||
do_check_false(Preferences.locked("toolkit.defaultChromeURI"));
|
||||
|
||||
let val = Preferences.get("toolkit.defaultChromeURI");
|
||||
Preferences.set("toolkit.defaultChromeURI", "test_lock_prefs");
|
||||
do_check_eq(Preferences.get("toolkit.defaultChromeURI"), "test_lock_prefs");
|
||||
Preferences.lock("toolkit.defaultChromeURI");
|
||||
do_check_eq(Preferences.get("toolkit.defaultChromeURI"), val);
|
||||
Preferences.unlock("toolkit.defaultChromeURI");
|
||||
do_check_eq(Preferences.get("toolkit.defaultChromeURI"), "test_lock_prefs");
|
||||
|
||||
// Clean up.
|
||||
Preferences.reset("toolkit.defaultChromeURI");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
*/
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,105 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/PromiseUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/Timer.jsm");
|
||||
Components.utils.import("resource://testing-common/PromiseTestUtils.jsm");
|
||||
|
||||
// Tests for PromiseUtils.jsm
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
// Tests for PromiseUtils.defer()
|
||||
|
||||
/* Tests for checking the resolve method of the Deferred object
|
||||
* returned by PromiseUtils.defer() */
|
||||
add_task(function* test_resolve_string() {
|
||||
let def = PromiseUtils.defer();
|
||||
let expected = "The promise is resolved " + Math.random();
|
||||
def.resolve(expected);
|
||||
let result = yield def.promise;
|
||||
Assert.equal(result, expected, "def.resolve() resolves the promise");
|
||||
});
|
||||
|
||||
/* Test for the case when undefined is passed to the resolve method
|
||||
* of the Deferred object */
|
||||
add_task(function* test_resolve_undefined() {
|
||||
let def = PromiseUtils.defer();
|
||||
def.resolve();
|
||||
let result = yield def.promise;
|
||||
Assert.equal(result, undefined, "resolve works with undefined as well");
|
||||
});
|
||||
|
||||
/* Test when a pending promise is passed to the resolve method
|
||||
* of the Deferred object */
|
||||
add_task(function* test_resolve_pending_promise() {
|
||||
let def = PromiseUtils.defer();
|
||||
let expected = 100 + Math.random();
|
||||
let p = new Promise((resolve, reject) => {
|
||||
setTimeout(() => resolve(expected), 100);
|
||||
});
|
||||
def.resolve(p);
|
||||
let result = yield def.promise;
|
||||
Assert.equal(result, expected, "def.promise assumed the state of the passed promise");
|
||||
});
|
||||
|
||||
/* Test when a resovled promise is passed
|
||||
* to the resolve method of the Deferred object */
|
||||
add_task(function* test_resolve_resolved_promise() {
|
||||
let def = PromiseUtils.defer();
|
||||
let expected = "Yeah resolved" + Math.random();
|
||||
let p = new Promise((resolve, reject) => resolve(expected));
|
||||
def.resolve(p);
|
||||
let result = yield def.promise;
|
||||
Assert.equal(result, expected, "Resolved promise is passed to the resolve method");
|
||||
});
|
||||
|
||||
/* Test for the case when a rejected promise is
|
||||
* passed to the resolve method */
|
||||
add_task(function* test_resolve_rejected_promise() {
|
||||
let def = PromiseUtils.defer();
|
||||
let p = new Promise((resolve, reject) => reject(new Error("There its an rejection")));
|
||||
def.resolve(p);
|
||||
yield Assert.rejects(def.promise, /There its an rejection/, "Settled rejection promise passed to the resolve method");
|
||||
});
|
||||
|
||||
/* Test for the checking the reject method of
|
||||
* the Deferred object returned by PromiseUtils.defer() */
|
||||
add_task(function* test_reject_Error() {
|
||||
let def = PromiseUtils.defer();
|
||||
def.reject(new Error("This one rejects"));
|
||||
yield Assert.rejects(def.promise, /This one rejects/, "reject method with Error for rejection");
|
||||
});
|
||||
|
||||
/* Test for the case when a pending Promise is passed to
|
||||
* the reject method of Deferred object */
|
||||
add_task(function* test_reject_pending_promise() {
|
||||
let def = PromiseUtils.defer();
|
||||
let p = new Promise((resolve, reject) => {
|
||||
setTimeout(() => resolve(100), 100);
|
||||
});
|
||||
def.reject(p);
|
||||
yield Assert.rejects(def.promise, Promise, "Rejection with a pending promise uses the passed promise itself as the reason of rejection");
|
||||
});
|
||||
|
||||
/* Test for the case when a resolved Promise
|
||||
* is passed to the reject method */
|
||||
add_task(function* test_reject_resolved_promise() {
|
||||
let def = PromiseUtils.defer();
|
||||
let p = new Promise((resolve, reject) => resolve("This resolved"));
|
||||
def.reject(p);
|
||||
yield Assert.rejects(def.promise, Promise, "Rejection with a resolved promise uses the passed promise itself as the reason of rejection");
|
||||
});
|
||||
|
||||
/* Test for the case when a rejected Promise is
|
||||
* passed to the reject method */
|
||||
add_task(function* test_reject_resolved_promise() {
|
||||
PromiseTestUtils.expectUncaughtRejection(/This one rejects/);
|
||||
let def = PromiseUtils.defer();
|
||||
let p = new Promise((resolve, reject) => reject(new Error("This one rejects")));
|
||||
def.reject(p);
|
||||
yield Assert.rejects(def.promise, Promise, "Rejection with a rejected promise uses the passed promise itself as the reason of rejection");
|
||||
});
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* This file tests the Services.jsm module.
|
||||
*/
|
||||
|
||||
// Globals
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
var Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function checkService(service, interface) {
|
||||
do_print("Checking that Services." + service + " is an " + interface);
|
||||
do_check_true(service in Services);
|
||||
do_check_true(Services[service] instanceof interface);
|
||||
}
|
||||
|
||||
// Tests
|
||||
|
||||
function run_test()
|
||||
{
|
||||
do_get_profile();
|
||||
|
||||
checkService("appShell", Ci.nsIAppShellService);
|
||||
checkService("appinfo", Ci.nsIXULRuntime);
|
||||
checkService("blocklist", Ci.nsIBlocklistService);
|
||||
checkService("cache", Ci.nsICacheService);
|
||||
checkService("cache2", Ci.nsICacheStorageService);
|
||||
checkService("clipboard", Ci.nsIClipboard);
|
||||
checkService("console", Ci.nsIConsoleService);
|
||||
checkService("contentPrefs", Ci.nsIContentPrefService);
|
||||
checkService("cookies", Ci.nsICookieManager2);
|
||||
checkService("dirsvc", Ci.nsIDirectoryService);
|
||||
checkService("dirsvc", Ci.nsIProperties);
|
||||
checkService("DOMRequest", Ci.nsIDOMRequestService);
|
||||
checkService("domStorageManager", Ci.nsIDOMStorageManager);
|
||||
checkService("downloads", Ci.nsIDownloadManager);
|
||||
checkService("droppedLinkHandler", Ci.nsIDroppedLinkHandler);
|
||||
checkService("eTLD", Ci.nsIEffectiveTLDService);
|
||||
checkService("focus", Ci.nsIFocusManager);
|
||||
checkService("io", Ci.nsIIOService);
|
||||
checkService("io", Ci.nsIIOService2);
|
||||
checkService("locale", Ci.nsILocaleService);
|
||||
checkService("logins", Ci.nsILoginManager);
|
||||
checkService("obs", Ci.nsIObserverService);
|
||||
checkService("perms", Ci.nsIPermissionManager);
|
||||
checkService("prefs", Ci.nsIPrefBranch);
|
||||
checkService("prefs", Ci.nsIPrefService);
|
||||
checkService("prompt", Ci.nsIPromptService);
|
||||
checkService("scriptSecurityManager", Ci.nsIScriptSecurityManager);
|
||||
checkService("scriptloader", Ci.mozIJSSubScriptLoader);
|
||||
checkService("startup", Ci.nsIAppStartup);
|
||||
checkService("storage", Ci.mozIStorageService);
|
||||
checkService("strings", Ci.nsIStringBundleService);
|
||||
checkService("sysinfo", Ci.nsIPropertyBag2);
|
||||
checkService("telemetry", Ci.nsITelemetry);
|
||||
checkService("tm", Ci.nsIThreadManager);
|
||||
checkService("uriFixup", Ci.nsIURIFixup);
|
||||
checkService("urlFormatter", Ci.nsIURLFormatter);
|
||||
checkService("vc", Ci.nsIVersionComparator);
|
||||
checkService("wm", Ci.nsIWindowMediator);
|
||||
checkService("ww", Ci.nsIWindowWatcher);
|
||||
if ("nsIBrowserSearchService" in Ci) {
|
||||
checkService("search", Ci.nsIBrowserSearchService);
|
||||
}
|
||||
if ("nsIAndroidBridge" in Ci) {
|
||||
checkService("androidBridge", Ci.nsIAndroidBridge);
|
||||
}
|
||||
|
||||
// In xpcshell tests, the "@mozilla.org/xre/app-info;1" component implements
|
||||
// only the nsIXULRuntime interface, but not nsIXULAppInfo. To test the
|
||||
// service getter for the latter interface, load mock app-info.
|
||||
let tmp = {};
|
||||
Cu.import("resource://testing-common/AppInfo.jsm", tmp);
|
||||
tmp.updateAppInfo();
|
||||
|
||||
// We need to reload the module to update the lazy getter.
|
||||
Cu.unload("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
checkService("appinfo", Ci.nsIXULAppInfo);
|
||||
|
||||
Cu.unload("resource://gre/modules/Services.jsm");
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* 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 { utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
Cu.import("resource://gre/modules/UpdateUtils.jsm");
|
||||
|
||||
const PREF_APP_UPDATE_CHANNEL = "app.update.channel";
|
||||
const TEST_CHANNEL = "TestChannel";
|
||||
const PREF_PARTNER_A = "app.partner.test_partner_a";
|
||||
const TEST_PARTNER_A = "TestPartnerA";
|
||||
const PREF_PARTNER_B = "app.partner.test_partner_b";
|
||||
const TEST_PARTNER_B = "TestPartnerB";
|
||||
|
||||
add_task(function* test_updatechannel() {
|
||||
let defaultPrefs = new Preferences({ defaultBranch: true });
|
||||
let currentChannel = defaultPrefs.get(PREF_APP_UPDATE_CHANNEL);
|
||||
|
||||
do_check_eq(UpdateUtils.UpdateChannel, currentChannel);
|
||||
do_check_eq(UpdateUtils.getUpdateChannel(true), currentChannel);
|
||||
do_check_eq(UpdateUtils.getUpdateChannel(false), currentChannel);
|
||||
|
||||
defaultPrefs.set(PREF_APP_UPDATE_CHANNEL, TEST_CHANNEL);
|
||||
do_check_eq(UpdateUtils.UpdateChannel, TEST_CHANNEL);
|
||||
do_check_eq(UpdateUtils.getUpdateChannel(true), TEST_CHANNEL);
|
||||
do_check_eq(UpdateUtils.getUpdateChannel(false), TEST_CHANNEL);
|
||||
|
||||
defaultPrefs.set(PREF_PARTNER_A, TEST_PARTNER_A);
|
||||
defaultPrefs.set(PREF_PARTNER_B, TEST_PARTNER_B);
|
||||
do_check_eq(UpdateUtils.UpdateChannel,
|
||||
TEST_CHANNEL + "-cck-" + TEST_PARTNER_A + "-" + TEST_PARTNER_B);
|
||||
do_check_eq(UpdateUtils.getUpdateChannel(true),
|
||||
TEST_CHANNEL + "-cck-" + TEST_PARTNER_A + "-" + TEST_PARTNER_B);
|
||||
do_check_eq(UpdateUtils.getUpdateChannel(false), TEST_CHANNEL);
|
||||
});
|
||||
|
|
@ -1,292 +0,0 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* 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 { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/UpdateUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/AppConstants.jsm");
|
||||
Cu.import("resource://testing-common/AppInfo.jsm");
|
||||
Cu.import("resource://gre/modules/ctypes.jsm");
|
||||
|
||||
const PREF_APP_UPDATE_CHANNEL = "app.update.channel";
|
||||
const PREF_APP_PARTNER_BRANCH = "app.partner.";
|
||||
const PREF_DISTRIBUTION_ID = "distribution.id";
|
||||
const PREF_DISTRIBUTION_VERSION = "distribution.version";
|
||||
|
||||
const URL_PREFIX = "http://localhost/";
|
||||
|
||||
const MSG_SHOULD_EQUAL = " should equal the expected value";
|
||||
|
||||
updateAppInfo();
|
||||
const gAppInfo = getAppInfo();
|
||||
const gDefaultPrefBranch = Services.prefs.getDefaultBranch(null);
|
||||
|
||||
function setUpdateChannel(aChannel) {
|
||||
gDefaultPrefBranch.setCharPref(PREF_APP_UPDATE_CHANNEL, aChannel);
|
||||
}
|
||||
|
||||
function getServicePack() {
|
||||
// NOTE: This function is a helper function and not a test. Thus,
|
||||
// it uses throw() instead of do_throw(). Any tests that use this function
|
||||
// should catch exceptions thrown in this function and deal with them
|
||||
// appropriately (usually by calling do_throw).
|
||||
const BYTE = ctypes.uint8_t;
|
||||
const WORD = ctypes.uint16_t;
|
||||
const DWORD = ctypes.uint32_t;
|
||||
const WCHAR = ctypes.char16_t;
|
||||
const BOOL = ctypes.int;
|
||||
|
||||
// This structure is described at:
|
||||
// http://msdn.microsoft.com/en-us/library/ms724833%28v=vs.85%29.aspx
|
||||
const SZCSDVERSIONLENGTH = 128;
|
||||
const OSVERSIONINFOEXW = new ctypes.StructType('OSVERSIONINFOEXW',
|
||||
[
|
||||
{dwOSVersionInfoSize: DWORD},
|
||||
{dwMajorVersion: DWORD},
|
||||
{dwMinorVersion: DWORD},
|
||||
{dwBuildNumber: DWORD},
|
||||
{dwPlatformId: DWORD},
|
||||
{szCSDVersion: ctypes.ArrayType(WCHAR, SZCSDVERSIONLENGTH)},
|
||||
{wServicePackMajor: WORD},
|
||||
{wServicePackMinor: WORD},
|
||||
{wSuiteMask: WORD},
|
||||
{wProductType: BYTE},
|
||||
{wReserved: BYTE}
|
||||
]);
|
||||
|
||||
let kernel32 = ctypes.open("kernel32");
|
||||
try {
|
||||
let GetVersionEx = kernel32.declare("GetVersionExW",
|
||||
ctypes.default_abi,
|
||||
BOOL,
|
||||
OSVERSIONINFOEXW.ptr);
|
||||
let winVer = OSVERSIONINFOEXW();
|
||||
winVer.dwOSVersionInfoSize = OSVERSIONINFOEXW.size;
|
||||
|
||||
if (0 === GetVersionEx(winVer.address())) {
|
||||
// Using "throw" instead of "do_throw" (see NOTE above)
|
||||
throw ("Failure in GetVersionEx (returned 0)");
|
||||
}
|
||||
|
||||
return winVer.wServicePackMajor + "." + winVer.wServicePackMinor;
|
||||
} finally {
|
||||
kernel32.close();
|
||||
}
|
||||
}
|
||||
|
||||
function getProcArchitecture() {
|
||||
// NOTE: This function is a helper function and not a test. Thus,
|
||||
// it uses throw() instead of do_throw(). Any tests that use this function
|
||||
// should catch exceptions thrown in this function and deal with them
|
||||
// appropriately (usually by calling do_throw).
|
||||
const WORD = ctypes.uint16_t;
|
||||
const DWORD = ctypes.uint32_t;
|
||||
|
||||
// This structure is described at:
|
||||
// http://msdn.microsoft.com/en-us/library/ms724958%28v=vs.85%29.aspx
|
||||
const SYSTEM_INFO = new ctypes.StructType('SYSTEM_INFO',
|
||||
[
|
||||
{wProcessorArchitecture: WORD},
|
||||
{wReserved: WORD},
|
||||
{dwPageSize: DWORD},
|
||||
{lpMinimumApplicationAddress: ctypes.voidptr_t},
|
||||
{lpMaximumApplicationAddress: ctypes.voidptr_t},
|
||||
{dwActiveProcessorMask: DWORD.ptr},
|
||||
{dwNumberOfProcessors: DWORD},
|
||||
{dwProcessorType: DWORD},
|
||||
{dwAllocationGranularity: DWORD},
|
||||
{wProcessorLevel: WORD},
|
||||
{wProcessorRevision: WORD}
|
||||
]);
|
||||
|
||||
let kernel32 = ctypes.open("kernel32");
|
||||
try {
|
||||
let GetNativeSystemInfo = kernel32.declare("GetNativeSystemInfo",
|
||||
ctypes.default_abi,
|
||||
ctypes.void_t,
|
||||
SYSTEM_INFO.ptr);
|
||||
let sysInfo = SYSTEM_INFO();
|
||||
// Default to unknown
|
||||
sysInfo.wProcessorArchitecture = 0xffff;
|
||||
|
||||
GetNativeSystemInfo(sysInfo.address());
|
||||
switch (sysInfo.wProcessorArchitecture) {
|
||||
case 9:
|
||||
return "x64";
|
||||
case 6:
|
||||
return "IA64";
|
||||
case 0:
|
||||
return "x86";
|
||||
default:
|
||||
// Using "throw" instead of "do_throw" (see NOTE above)
|
||||
throw ("Unknown architecture returned from GetNativeSystemInfo: " + sysInfo.wProcessorArchitecture);
|
||||
}
|
||||
} finally {
|
||||
kernel32.close();
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function for formatting a url and getting the result we're
|
||||
// interested in
|
||||
function getResult(url) {
|
||||
url = UpdateUtils.formatUpdateURL(url);
|
||||
return url.substr(URL_PREFIX.length).split("/")[0];
|
||||
}
|
||||
|
||||
// url constructed with %PRODUCT%
|
||||
add_task(function* test_product() {
|
||||
let url = URL_PREFIX + "%PRODUCT%/";
|
||||
Assert.equal(getResult(url), gAppInfo.name,
|
||||
"the url param for %PRODUCT%" + MSG_SHOULD_EQUAL);
|
||||
});
|
||||
|
||||
// url constructed with %VERSION%
|
||||
add_task(function* test_version() {
|
||||
let url = URL_PREFIX + "%VERSION%/";
|
||||
Assert.equal(getResult(url), gAppInfo.version,
|
||||
"the url param for %VERSION%" + MSG_SHOULD_EQUAL);
|
||||
});
|
||||
|
||||
// url constructed with %BUILD_ID%
|
||||
add_task(function* test_build_id() {
|
||||
let url = URL_PREFIX + "%BUILD_ID%/";
|
||||
Assert.equal(getResult(url), gAppInfo.appBuildID,
|
||||
"the url param for %BUILD_ID%" + MSG_SHOULD_EQUAL);
|
||||
});
|
||||
|
||||
// url constructed with %BUILD_TARGET%
|
||||
// XXX TODO - it might be nice if we tested the actual ABI
|
||||
add_task(function* test_build_target() {
|
||||
let url = URL_PREFIX + "%BUILD_TARGET%/";
|
||||
|
||||
let abi;
|
||||
try {
|
||||
abi = gAppInfo.XPCOMABI;
|
||||
} catch (e) {
|
||||
do_throw("nsIXULAppInfo:XPCOMABI not defined\n");
|
||||
}
|
||||
|
||||
if (AppConstants.platform == "macosx") {
|
||||
// Mac universal build should report a different ABI than either macppc
|
||||
// or mactel. This is necessary since nsUpdateService.js will set the ABI to
|
||||
// Universal-gcc3 for Mac universal builds.
|
||||
let macutils = Cc["@mozilla.org/xpcom/mac-utils;1"].
|
||||
getService(Ci.nsIMacUtils);
|
||||
|
||||
if (macutils.isUniversalBinary) {
|
||||
abi += "-u-" + macutils.architecturesInBinary;
|
||||
}
|
||||
} else if (AppConstants.platform == "win") {
|
||||
// Windows build should report the CPU architecture that it's running on.
|
||||
abi += "-" + getProcArchitecture();
|
||||
}
|
||||
|
||||
Assert.equal(getResult(url), gAppInfo.OS + "_" + abi,
|
||||
"the url param for %BUILD_TARGET%" + MSG_SHOULD_EQUAL);
|
||||
});
|
||||
|
||||
// url constructed with %LOCALE%
|
||||
// Bug 488936 added the update.locale file that stores the update locale
|
||||
add_task(function* test_locale() {
|
||||
// The code that gets the locale accesses the profile which is only available
|
||||
// after calling do_get_profile in xpcshell tests. This prevents an error from
|
||||
// being logged.
|
||||
do_get_profile();
|
||||
|
||||
let url = URL_PREFIX + "%LOCALE%/";
|
||||
Assert.equal(getResult(url), AppConstants.INSTALL_LOCALE,
|
||||
"the url param for %LOCALE%" + MSG_SHOULD_EQUAL);
|
||||
});
|
||||
|
||||
// url constructed with %CHANNEL%
|
||||
add_task(function* test_channel() {
|
||||
let url = URL_PREFIX + "%CHANNEL%/";
|
||||
setUpdateChannel("test_channel");
|
||||
Assert.equal(getResult(url), "test_channel",
|
||||
"the url param for %CHANNEL%" + MSG_SHOULD_EQUAL);
|
||||
});
|
||||
|
||||
// url constructed with %CHANNEL% with distribution partners
|
||||
add_task(function* test_channel_distribution() {
|
||||
let url = URL_PREFIX + "%CHANNEL%/";
|
||||
gDefaultPrefBranch.setCharPref(PREF_APP_PARTNER_BRANCH + "test_partner1",
|
||||
"test_partner1");
|
||||
gDefaultPrefBranch.setCharPref(PREF_APP_PARTNER_BRANCH + "test_partner2",
|
||||
"test_partner2");
|
||||
Assert.equal(getResult(url),
|
||||
"test_channel-cck-test_partner1-test_partner2",
|
||||
"the url param for %CHANNEL%" + MSG_SHOULD_EQUAL);
|
||||
});
|
||||
|
||||
// url constructed with %PLATFORM_VERSION%
|
||||
add_task(function* test_platform_version() {
|
||||
let url = URL_PREFIX + "%PLATFORM_VERSION%/";
|
||||
Assert.equal(getResult(url), gAppInfo.platformVersion,
|
||||
"the url param for %PLATFORM_VERSION%" + MSG_SHOULD_EQUAL);
|
||||
});
|
||||
|
||||
// url constructed with %OS_VERSION%
|
||||
add_task(function* test_os_version() {
|
||||
let url = URL_PREFIX + "%OS_VERSION%/";
|
||||
let osVersion;
|
||||
let sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2);
|
||||
osVersion = sysInfo.getProperty("name") + " " + sysInfo.getProperty("version");
|
||||
|
||||
if (AppConstants.platform == "win") {
|
||||
try {
|
||||
let servicePack = getServicePack();
|
||||
osVersion += "." + servicePack;
|
||||
} catch (e) {
|
||||
do_throw("Failure obtaining service pack: " + e);
|
||||
}
|
||||
|
||||
if ("5.0" === sysInfo.getProperty("version")) { // Win2K
|
||||
osVersion += " (unknown)";
|
||||
} else {
|
||||
try {
|
||||
osVersion += " (" + getProcArchitecture() + ")";
|
||||
} catch (e) {
|
||||
do_throw("Failed to obtain processor architecture: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (osVersion) {
|
||||
try {
|
||||
osVersion += " (" + sysInfo.getProperty("secondaryLibrary") + ")";
|
||||
} catch (e) {
|
||||
// Not all platforms have a secondary widget library, so an error is
|
||||
// nothing to worry about.
|
||||
}
|
||||
osVersion = encodeURIComponent(osVersion);
|
||||
}
|
||||
|
||||
Assert.equal(getResult(url), osVersion,
|
||||
"the url param for %OS_VERSION%" + MSG_SHOULD_EQUAL);
|
||||
});
|
||||
|
||||
// url constructed with %DISTRIBUTION%
|
||||
add_task(function* test_distribution() {
|
||||
let url = URL_PREFIX + "%DISTRIBUTION%/";
|
||||
gDefaultPrefBranch.setCharPref(PREF_DISTRIBUTION_ID, "test_distro");
|
||||
Assert.equal(getResult(url), "test_distro",
|
||||
"the url param for %DISTRIBUTION%" + MSG_SHOULD_EQUAL);
|
||||
});
|
||||
|
||||
// url constructed with %DISTRIBUTION_VERSION%
|
||||
add_task(function* test_distribution_version() {
|
||||
let url = URL_PREFIX + "%DISTRIBUTION_VERSION%/";
|
||||
gDefaultPrefBranch.setCharPref(PREF_DISTRIBUTION_VERSION, "test_distro_version");
|
||||
Assert.equal(getResult(url), "test_distro_version",
|
||||
"the url param for %DISTRIBUTION_VERSION%" + MSG_SHOULD_EQUAL);
|
||||
});
|
||||
|
||||
add_task(function* test_custom() {
|
||||
Services.prefs.setCharPref("app.update.custom", "custom");
|
||||
let url = URL_PREFIX + "%CUSTOM%/";
|
||||
Assert.equal(getResult(url), "custom",
|
||||
"the url query string for %CUSTOM%" + MSG_SHOULD_EQUAL);
|
||||
});
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const ARCHIVE = "zips/zen.zip";
|
||||
const SUBDIR = "zen";
|
||||
const SYMLINK = "beyond_link";
|
||||
const ENTRIES = ["beyond.txt", SYMLINK, "waterwood.txt"];
|
||||
|
||||
Components.utils.import("resource://gre/modules/ZipUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/FileUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const archive = do_get_file(ARCHIVE, false);
|
||||
const dir = do_get_profile().clone();
|
||||
dir.append("test_ZipUtils");
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function ensureExtracted(target) {
|
||||
target.append(SUBDIR);
|
||||
do_check_true(target.exists());
|
||||
|
||||
for (let i = 0; i < ENTRIES.length; i++) {
|
||||
let entry = target.clone();
|
||||
entry.append(ENTRIES[i]);
|
||||
do_print("ENTRY " + entry.path);
|
||||
do_check_true(entry.exists());
|
||||
}
|
||||
}
|
||||
|
||||
function ensureHasSymlink(target) {
|
||||
// Just bail out if running on Windows, since symlinks do not exists there.
|
||||
if (Services.appinfo.OS === "WINNT") {
|
||||
return;
|
||||
}
|
||||
|
||||
let entry = target.clone();
|
||||
entry.append(SYMLINK);
|
||||
|
||||
do_print("ENTRY " + entry.path);
|
||||
do_check_true(entry.exists());
|
||||
do_check_true(entry.isSymlink());
|
||||
}
|
||||
|
||||
add_task(function test_extractFiles() {
|
||||
let target = dir.clone();
|
||||
target.append("test_extractFiles");
|
||||
|
||||
try {
|
||||
ZipUtils.extractFiles(archive, target);
|
||||
} catch (e) {
|
||||
do_throw("Failed to extract synchronously!");
|
||||
}
|
||||
|
||||
ensureExtracted(target);
|
||||
ensureHasSymlink(target);
|
||||
});
|
||||
|
||||
add_task(function* test_extractFilesAsync() {
|
||||
let target = dir.clone();
|
||||
target.append("test_extractFilesAsync");
|
||||
target.create(Components.interfaces.nsIFile.DIRECTORY_TYPE,
|
||||
FileUtils.PERMS_DIRECTORY);
|
||||
|
||||
yield ZipUtils.extractFilesAsync(archive, target).then(
|
||||
function success() {
|
||||
do_print("SUCCESS");
|
||||
ensureExtracted(target);
|
||||
},
|
||||
function failure() {
|
||||
do_print("FAILURE");
|
||||
do_throw("Failed to extract asynchronously!");
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
var {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/ClientID.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
Cu.import("resource://gre/modules/osfile.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* () {
|
||||
const drsPath = OS.Path.join(OS.Constants.Path.profileDir, "datareporting", "state.json");
|
||||
const fhrDir = OS.Path.join(OS.Constants.Path.profileDir, "healthreport");
|
||||
const fhrPath = OS.Path.join(fhrDir, "state.json");
|
||||
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
||||
const invalidIDs = [-1, 0.5, "INVALID-UUID", true, "", "3d1e1560-682a-4043-8cf2-aaaaaaaaaaaZ"];
|
||||
const PREF_CACHED_CLIENTID = "toolkit.telemetry.cachedClientID";
|
||||
|
||||
yield OS.File.makeDir(fhrDir);
|
||||
|
||||
// Check that we are importing the FHR client ID.
|
||||
let clientID = CommonUtils.generateUUID();
|
||||
yield CommonUtils.writeJSON({clientID: clientID}, fhrPath);
|
||||
Assert.equal(clientID, yield ClientID.getClientID());
|
||||
|
||||
// We should persist the ID in DRS now and not pick up a differing ID from FHR.
|
||||
yield ClientID._reset();
|
||||
yield CommonUtils.writeJSON({clientID: CommonUtils.generateUUID()}, fhrPath);
|
||||
Assert.equal(clientID, yield ClientID.getClientID());
|
||||
|
||||
// We should be guarded against broken FHR data.
|
||||
for (let invalidID of invalidIDs) {
|
||||
yield ClientID._reset();
|
||||
yield OS.File.remove(drsPath);
|
||||
yield CommonUtils.writeJSON({clientID: invalidID}, fhrPath);
|
||||
clientID = yield ClientID.getClientID();
|
||||
Assert.equal(typeof(clientID), 'string');
|
||||
Assert.ok(uuidRegex.test(clientID));
|
||||
}
|
||||
|
||||
// We should be guarded against invalid FHR json.
|
||||
yield ClientID._reset();
|
||||
yield OS.File.remove(drsPath);
|
||||
yield OS.File.writeAtomic(fhrPath, "abcd", {encoding: "utf-8", tmpPath: fhrPath + ".tmp"});
|
||||
clientID = yield ClientID.getClientID();
|
||||
Assert.equal(typeof(clientID), 'string');
|
||||
Assert.ok(uuidRegex.test(clientID));
|
||||
|
||||
// We should be guarded against broken DRS data too and fall back to loading
|
||||
// the FHR ID.
|
||||
for (let invalidID of invalidIDs) {
|
||||
yield ClientID._reset();
|
||||
clientID = CommonUtils.generateUUID();
|
||||
yield CommonUtils.writeJSON({clientID: clientID}, fhrPath);
|
||||
yield CommonUtils.writeJSON({clientID: invalidID}, drsPath);
|
||||
Assert.equal(clientID, yield ClientID.getClientID());
|
||||
}
|
||||
|
||||
// We should be guarded against invalid DRS json too.
|
||||
yield ClientID._reset();
|
||||
yield OS.File.remove(fhrPath);
|
||||
yield OS.File.writeAtomic(drsPath, "abcd", {encoding: "utf-8", tmpPath: drsPath + ".tmp"});
|
||||
clientID = yield ClientID.getClientID();
|
||||
Assert.equal(typeof(clientID), 'string');
|
||||
Assert.ok(uuidRegex.test(clientID));
|
||||
|
||||
// If both the FHR and DSR data are broken, we should end up with a new client ID.
|
||||
for (let invalidID of invalidIDs) {
|
||||
yield ClientID._reset();
|
||||
yield CommonUtils.writeJSON({clientID: invalidID}, fhrPath);
|
||||
yield CommonUtils.writeJSON({clientID: invalidID}, drsPath);
|
||||
clientID = yield ClientID.getClientID();
|
||||
Assert.equal(typeof(clientID), 'string');
|
||||
Assert.ok(uuidRegex.test(clientID));
|
||||
}
|
||||
|
||||
// Assure that cached IDs are being checked for validity.
|
||||
for (let invalidID of invalidIDs) {
|
||||
yield ClientID._reset();
|
||||
Preferences.set(PREF_CACHED_CLIENTID, invalidID);
|
||||
let cachedID = ClientID.getCachedClientID();
|
||||
Assert.strictEqual(cachedID, null, "ClientID should ignore invalid cached IDs");
|
||||
let prefID = Preferences.get(PREF_CACHED_CLIENTID, null);
|
||||
Assert.strictEqual(prefID, null, "ClientID should reset invalid cached IDs");
|
||||
}
|
||||
});
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Components.utils.import("resource://gre/modules/third_party/jsesc/jsesc.js");
|
||||
|
||||
function run_test() {
|
||||
do_check_eq(jsesc("teééést", {lowercaseHex: true}), "te\\xe9\\xe9\\xe9st");
|
||||
do_check_eq(jsesc("teééést", {lowercaseHex: false}), "te\\xE9\\xE9\\xE9st");
|
||||
}
|
||||
|
|
@ -1,106 +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/. */
|
||||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/PropertyListUtils.jsm");
|
||||
|
||||
function checkValue(aPropertyListObject, aType, aValue) {
|
||||
do_check_eq(PropertyListUtils.getObjectType(aPropertyListObject), aType);
|
||||
if (aValue !== undefined) {
|
||||
// Perform strict equality checks until Bug 714467 is fixed.
|
||||
let strictEqualityCheck = function(a, b) {
|
||||
do_check_eq(typeof(a), typeof(b));
|
||||
do_check_eq(a, b);
|
||||
};
|
||||
|
||||
if (typeof(aPropertyListObject) == "object")
|
||||
strictEqualityCheck(aPropertyListObject.valueOf(), aValue.valueOf());
|
||||
else
|
||||
strictEqualityCheck(aPropertyListObject, aValue);
|
||||
}
|
||||
}
|
||||
|
||||
function checkLazyGetterValue(aObject, aPropertyName, aType, aValue) {
|
||||
let descriptor = Object.getOwnPropertyDescriptor(aObject, aPropertyName);
|
||||
do_check_eq(typeof(descriptor.get), "function");
|
||||
do_check_eq(typeof(descriptor.value), "undefined");
|
||||
checkValue(aObject[aPropertyName], aType, aValue);
|
||||
descriptor = Object.getOwnPropertyDescriptor(aObject, aPropertyName);
|
||||
do_check_eq(typeof(descriptor.get), "undefined");
|
||||
do_check_neq(typeof(descriptor.value), "undefined");
|
||||
}
|
||||
|
||||
function checkMainPropertyList(aPropertyListRoot) {
|
||||
const PRIMITIVE = PropertyListUtils.TYPE_PRIMITIVE;
|
||||
|
||||
checkValue(aPropertyListRoot, PropertyListUtils.TYPE_DICTIONARY);
|
||||
|
||||
// Check .has()
|
||||
Assert.ok(aPropertyListRoot.has("Boolean"));
|
||||
Assert.ok(!aPropertyListRoot.has("Nonexistent"));
|
||||
|
||||
checkValue(aPropertyListRoot.get("Boolean"), PRIMITIVE, false);
|
||||
|
||||
let array = aPropertyListRoot.get("Array");
|
||||
checkValue(array, PropertyListUtils.TYPE_ARRAY);
|
||||
do_check_eq(array.length, 8);
|
||||
|
||||
// Test both long and short values, since binary property lists store
|
||||
// long values a little bit differently (see readDataLengthAndOffset).
|
||||
|
||||
// Short ASCII string
|
||||
checkLazyGetterValue(array, 0, PRIMITIVE, "abc");
|
||||
// Long ASCII string
|
||||
checkLazyGetterValue(array, 1, PRIMITIVE, new Array(1001).join("a"));
|
||||
// Short unicode string
|
||||
checkLazyGetterValue(array, 2, PRIMITIVE, "\u05D0\u05D0\u05D0");
|
||||
// Long unicode string
|
||||
checkLazyGetterValue(array, 3, PRIMITIVE, new Array(1001).join("\u05D0"));
|
||||
// Unicode surrogate pair
|
||||
checkLazyGetterValue(array, 4, PRIMITIVE,
|
||||
"\uD800\uDC00\uD800\uDC00\uD800\uDC00");
|
||||
|
||||
// Date
|
||||
checkLazyGetterValue(array, 5, PropertyListUtils.TYPE_DATE,
|
||||
new Date("2011-12-31T11:15:23Z"));
|
||||
|
||||
// Data
|
||||
checkLazyGetterValue(array, 6, PropertyListUtils.TYPE_UINT8_ARRAY);
|
||||
let dataAsString = Array.from(array[6]).map(b => String.fromCharCode(b)).join("");
|
||||
do_check_eq(dataAsString, "2011-12-31T11:15:33Z");
|
||||
|
||||
// Dict
|
||||
let dict = array[7];
|
||||
checkValue(dict, PropertyListUtils.TYPE_DICTIONARY);
|
||||
checkValue(dict.get("Negative Number"), PRIMITIVE, -400);
|
||||
checkValue(dict.get("Real Number"), PRIMITIVE, 2.71828183);
|
||||
checkValue(dict.get("Big Int"),
|
||||
PropertyListUtils.TYPE_INT64,
|
||||
"9007199254740993");
|
||||
checkValue(dict.get("Negative Big Int"),
|
||||
PropertyListUtils.TYPE_INT64,
|
||||
"-9007199254740993");
|
||||
}
|
||||
|
||||
function readPropertyList(aFile, aCallback) {
|
||||
PropertyListUtils.read(aFile, function(aPropertyListRoot) {
|
||||
// Null root indicates failure to read property list.
|
||||
// Note: It is important not to run do_check_n/eq directly on Dict and array
|
||||
// objects, because it cases their toString to get invoked, doing away with
|
||||
// all the lazy getter we'd like to test later.
|
||||
do_check_true(aPropertyListRoot !== null);
|
||||
aCallback(aPropertyListRoot);
|
||||
run_next_test();
|
||||
});
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
add_test(readPropertyList.bind(this,
|
||||
do_get_file("propertyLists/bug710259_propertyListBinary.plist", false),
|
||||
checkMainPropertyList));
|
||||
add_test(readPropertyList.bind(this,
|
||||
do_get_file("propertyLists/bug710259_propertyListXML.plist", false),
|
||||
checkMainPropertyList));
|
||||
run_next_test();
|
||||
}
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource://gre/modules/CertUtils.jsm");
|
||||
|
||||
const PREF_PREFIX = "certutils.certs.";
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function resetPrefs() {
|
||||
var prefs = Services.prefs.getChildList(PREF_PREFIX);
|
||||
prefs.forEach(Services.prefs.clearUserPref);
|
||||
}
|
||||
|
||||
function attributes_match(aCert, aExpected) {
|
||||
if (Object.keys(aCert).length != Object.keys(aExpected).length)
|
||||
return false;
|
||||
|
||||
for (var attribute in aCert) {
|
||||
if (!(attribute in aExpected))
|
||||
return false;
|
||||
if (aCert[attribute] != aExpected[attribute])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function test_results(aCerts, aExpected) {
|
||||
do_check_eq(aCerts.length, aExpected.length);
|
||||
|
||||
for (var i = 0; i < aCerts.length; i++) {
|
||||
if (!attributes_match(aCerts[i], aExpected[i])) {
|
||||
dump("Attributes for certificate " + (i + 1) + " did not match expected attributes\n");
|
||||
dump("Saw: " + aCerts[i].toSource() + "\n");
|
||||
dump("Expected: " + aExpected[i].toSource() + "\n");
|
||||
do_check_true(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add_test(function test_singleCert() {
|
||||
Services.prefs.setCharPref(PREF_PREFIX + "1.attribute1", "foo");
|
||||
Services.prefs.setCharPref(PREF_PREFIX + "1.attribute2", "bar");
|
||||
|
||||
var certs = readCertPrefs(PREF_PREFIX);
|
||||
test_results(certs, [{
|
||||
attribute1: "foo",
|
||||
attribute2: "bar"
|
||||
}]);
|
||||
|
||||
resetPrefs();
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_multipleCert() {
|
||||
Services.prefs.setCharPref(PREF_PREFIX + "1.md5Fingerprint", "cf84a9a2a804e021f27cb5128fe151f4");
|
||||
Services.prefs.setCharPref(PREF_PREFIX + "1.nickname", "1st cert");
|
||||
Services.prefs.setCharPref(PREF_PREFIX + "2.md5Fingerprint", "9441051b7eb50e5ca2226095af710c1a");
|
||||
Services.prefs.setCharPref(PREF_PREFIX + "2.nickname", "2nd cert");
|
||||
|
||||
var certs = readCertPrefs(PREF_PREFIX);
|
||||
test_results(certs, [{
|
||||
md5Fingerprint: "cf84a9a2a804e021f27cb5128fe151f4",
|
||||
nickname: "1st cert"
|
||||
}, {
|
||||
md5Fingerprint: "9441051b7eb50e5ca2226095af710c1a",
|
||||
nickname: "2nd cert"
|
||||
}]);
|
||||
|
||||
resetPrefs();
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_skippedCert() {
|
||||
Services.prefs.setCharPref(PREF_PREFIX + "1.issuerName", "Mozilla");
|
||||
Services.prefs.setCharPref(PREF_PREFIX + "1.nickname", "1st cert");
|
||||
Services.prefs.setCharPref(PREF_PREFIX + "2.issuerName", "Top CA");
|
||||
Services.prefs.setCharPref(PREF_PREFIX + "2.nickname", "2nd cert");
|
||||
Services.prefs.setCharPref(PREF_PREFIX + "4.issuerName", "Unknown CA");
|
||||
Services.prefs.setCharPref(PREF_PREFIX + "4.nickname", "Ignored cert");
|
||||
|
||||
var certs = readCertPrefs(PREF_PREFIX);
|
||||
test_results(certs, [{
|
||||
issuerName: "Mozilla",
|
||||
nickname: "1st cert"
|
||||
}, {
|
||||
issuerName: "Top CA",
|
||||
nickname: "2nd cert"
|
||||
}]);
|
||||
|
||||
resetPrefs();
|
||||
run_next_test();
|
||||
});
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
var {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/ServiceRequest.jsm");
|
||||
|
||||
add_task(function* test_tls_conservative() {
|
||||
const request = new ServiceRequest();
|
||||
request.open("GET", "http://example.com", false);
|
||||
|
||||
const sr_channel = request.channel.QueryInterface(Ci.nsIHttpChannelInternal);
|
||||
ok(("beConservative" in sr_channel), "TLS setting is present in SR channel");
|
||||
ok(sr_channel.beConservative, "TLS setting in request channel is set to conservative for SR");
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "http://example.com", false);
|
||||
|
||||
const xhr_channel = xhr.channel.QueryInterface(Ci.nsIHttpChannelInternal);
|
||||
ok(("beConservative" in xhr_channel), "TLS setting is present in XHR channel");
|
||||
ok(!xhr_channel.beConservative, "TLS setting in request channel is not set to conservative for XHR");
|
||||
|
||||
});
|
||||
|
|
@ -1,306 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
var {utils: Cu} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/SessionRecorder.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function monkeypatchStartupInfo(recorder, start=new Date(), offset=500) {
|
||||
Object.defineProperty(recorder, "_getStartupInfo", {
|
||||
value: function _getStartupInfo() {
|
||||
return {
|
||||
process: start,
|
||||
main: new Date(start.getTime() + offset),
|
||||
firstPaint: new Date(start.getTime() + 2 * offset),
|
||||
sessionRestored: new Date(start.getTime() + 3 * offset),
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function sleep(wait) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let timer = CommonUtils.namedTimer(function onTimer() {
|
||||
deferred.resolve();
|
||||
}, wait, deferred.promise, "_sleepTimer");
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function getRecorder(name, start, offset) {
|
||||
let recorder = new SessionRecorder("testing." + name + ".");
|
||||
monkeypatchStartupInfo(recorder, start, offset);
|
||||
|
||||
return recorder;
|
||||
}
|
||||
|
||||
add_test(function test_basic() {
|
||||
let recorder = getRecorder("basic");
|
||||
recorder.onStartup();
|
||||
recorder.onShutdown();
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_task(function* test_current_properties() {
|
||||
let now = new Date();
|
||||
let recorder = getRecorder("current_properties", now);
|
||||
yield sleep(25);
|
||||
recorder.onStartup();
|
||||
|
||||
do_check_eq(recorder.startDate.getTime(), now.getTime());
|
||||
do_check_eq(recorder.activeTicks, 0);
|
||||
do_check_true(recorder.fineTotalTime > 0);
|
||||
do_check_eq(recorder.main, 500);
|
||||
do_check_eq(recorder.firstPaint, 1000);
|
||||
do_check_eq(recorder.sessionRestored, 1500);
|
||||
|
||||
recorder.incrementActiveTicks();
|
||||
do_check_eq(recorder.activeTicks, 1);
|
||||
|
||||
recorder._startDate = new Date(Date.now() - 1000);
|
||||
recorder.updateTotalTime();
|
||||
do_check_eq(recorder.totalTime, 1);
|
||||
|
||||
recorder.onShutdown();
|
||||
});
|
||||
|
||||
// If startup info isn't present yet, we should install a timer and get
|
||||
// it eventually.
|
||||
add_task(function* test_current_availability() {
|
||||
let recorder = new SessionRecorder("testing.current_availability.");
|
||||
let now = new Date();
|
||||
|
||||
Object.defineProperty(recorder, "_getStartupInfo", {
|
||||
value: function _getStartupInfo() {
|
||||
return {
|
||||
process: now,
|
||||
main: new Date(now.getTime() + 500),
|
||||
firstPaint: new Date(now.getTime() + 1000),
|
||||
};
|
||||
},
|
||||
writable: true,
|
||||
});
|
||||
|
||||
Object.defineProperty(recorder, "STARTUP_RETRY_INTERVAL_MS", {
|
||||
value: 100,
|
||||
});
|
||||
|
||||
let oldRecord = recorder.recordStartupFields;
|
||||
let recordCount = 0;
|
||||
|
||||
Object.defineProperty(recorder, "recordStartupFields", {
|
||||
value: function () {
|
||||
recordCount++;
|
||||
return oldRecord.call(recorder);
|
||||
}
|
||||
});
|
||||
|
||||
do_check_null(recorder._timer);
|
||||
recorder.onStartup();
|
||||
do_check_eq(recordCount, 1);
|
||||
do_check_eq(recorder.sessionRestored, -1);
|
||||
do_check_neq(recorder._timer, null);
|
||||
|
||||
yield sleep(125);
|
||||
do_check_eq(recordCount, 2);
|
||||
yield sleep(100);
|
||||
do_check_eq(recordCount, 3);
|
||||
do_check_eq(recorder.sessionRestored, -1);
|
||||
|
||||
monkeypatchStartupInfo(recorder, now);
|
||||
yield sleep(100);
|
||||
do_check_eq(recordCount, 4);
|
||||
do_check_eq(recorder.sessionRestored, 1500);
|
||||
|
||||
// The timer should be removed and we should not fire again.
|
||||
do_check_null(recorder._timer);
|
||||
yield sleep(100);
|
||||
do_check_eq(recordCount, 4);
|
||||
|
||||
recorder.onShutdown();
|
||||
});
|
||||
|
||||
add_test(function test_timer_clear_on_shutdown() {
|
||||
let recorder = new SessionRecorder("testing.timer_clear_on_shutdown.");
|
||||
let now = new Date();
|
||||
|
||||
Object.defineProperty(recorder, "_getStartupInfo", {
|
||||
value: function _getStartupInfo() {
|
||||
return {
|
||||
process: now,
|
||||
main: new Date(now.getTime() + 500),
|
||||
firstPaint: new Date(now.getTime() + 1000),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
do_check_null(recorder._timer);
|
||||
recorder.onStartup();
|
||||
do_check_neq(recorder._timer, null);
|
||||
|
||||
recorder.onShutdown();
|
||||
do_check_null(recorder._timer);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_task(function* test_previous_clean() {
|
||||
let now = new Date();
|
||||
let recorder = getRecorder("previous_clean", now);
|
||||
yield sleep(25);
|
||||
recorder.onStartup();
|
||||
|
||||
recorder.incrementActiveTicks();
|
||||
recorder.incrementActiveTicks();
|
||||
|
||||
yield sleep(25);
|
||||
recorder.onShutdown();
|
||||
|
||||
let total = recorder.totalTime;
|
||||
|
||||
yield sleep(25);
|
||||
let now2 = new Date();
|
||||
let recorder2 = getRecorder("previous_clean", now2, 100);
|
||||
yield sleep(25);
|
||||
recorder2.onStartup();
|
||||
|
||||
do_check_eq(recorder2.startDate.getTime(), now2.getTime());
|
||||
do_check_eq(recorder2.main, 100);
|
||||
do_check_eq(recorder2.firstPaint, 200);
|
||||
do_check_eq(recorder2.sessionRestored, 300);
|
||||
|
||||
let sessions = recorder2.getPreviousSessions();
|
||||
do_check_eq(Object.keys(sessions).length, 1);
|
||||
do_check_true(0 in sessions);
|
||||
let session = sessions[0];
|
||||
do_check_true(session.clean);
|
||||
do_check_eq(session.startDate.getTime(), now.getTime());
|
||||
do_check_eq(session.main, 500);
|
||||
do_check_eq(session.firstPaint, 1000);
|
||||
do_check_eq(session.sessionRestored, 1500);
|
||||
do_check_eq(session.totalTime, total);
|
||||
do_check_eq(session.activeTicks, 2);
|
||||
|
||||
recorder2.onShutdown();
|
||||
});
|
||||
|
||||
add_task(function* test_previous_abort() {
|
||||
let now = new Date();
|
||||
let recorder = getRecorder("previous_abort", now);
|
||||
yield sleep(25);
|
||||
recorder.onStartup();
|
||||
recorder.incrementActiveTicks();
|
||||
yield sleep(25);
|
||||
let total = recorder.totalTime;
|
||||
yield sleep(25);
|
||||
|
||||
let now2 = new Date();
|
||||
let recorder2 = getRecorder("previous_abort", now2);
|
||||
yield sleep(25);
|
||||
recorder2.onStartup();
|
||||
|
||||
let sessions = recorder2.getPreviousSessions();
|
||||
do_check_eq(Object.keys(sessions).length, 1);
|
||||
do_check_true(0 in sessions);
|
||||
let session = sessions[0];
|
||||
do_check_false(session.clean);
|
||||
do_check_eq(session.totalTime, total);
|
||||
|
||||
recorder.onShutdown();
|
||||
recorder2.onShutdown();
|
||||
});
|
||||
|
||||
add_task(function* test_multiple_sessions() {
|
||||
for (let i = 0; i < 10; i++) {
|
||||
let recorder = getRecorder("multiple_sessions");
|
||||
yield sleep(25);
|
||||
recorder.onStartup();
|
||||
for (let j = 0; j < i; j++) {
|
||||
recorder.incrementActiveTicks();
|
||||
}
|
||||
yield sleep(25);
|
||||
recorder.onShutdown();
|
||||
yield sleep(25);
|
||||
}
|
||||
|
||||
let recorder = getRecorder("multiple_sessions");
|
||||
recorder.onStartup();
|
||||
|
||||
let sessions = recorder.getPreviousSessions();
|
||||
do_check_eq(Object.keys(sessions).length, 10);
|
||||
|
||||
for (let [i, session] of Object.entries(sessions)) {
|
||||
do_check_eq(session.activeTicks, i);
|
||||
|
||||
if (i > 0) {
|
||||
do_check_true(session.startDate.getTime() > sessions[i-1].startDate.getTime());
|
||||
}
|
||||
}
|
||||
|
||||
// #6 is preserved since >=.
|
||||
let threshold = sessions[6].startDate;
|
||||
recorder.pruneOldSessions(threshold);
|
||||
|
||||
sessions = recorder.getPreviousSessions();
|
||||
do_check_eq(Object.keys(sessions).length, 4);
|
||||
|
||||
recorder.pruneOldSessions(threshold);
|
||||
sessions = recorder.getPreviousSessions();
|
||||
do_check_eq(Object.keys(sessions).length, 4);
|
||||
do_check_eq(recorder._prunedIndex, 5);
|
||||
|
||||
recorder.onShutdown();
|
||||
});
|
||||
|
||||
add_task(function* test_record_activity() {
|
||||
let recorder = getRecorder("record_activity");
|
||||
yield sleep(25);
|
||||
recorder.onStartup();
|
||||
let total = recorder.totalTime;
|
||||
yield sleep(25);
|
||||
|
||||
for (let i = 0; i < 3; i++) {
|
||||
Services.obs.notifyObservers(null, "user-interaction-active", null);
|
||||
yield sleep(25);
|
||||
do_check_true(recorder.fineTotalTime > total);
|
||||
total = recorder.fineTotalTime;
|
||||
}
|
||||
|
||||
do_check_eq(recorder.activeTicks, 3);
|
||||
|
||||
// Now send inactive. We should increment total time but not active.
|
||||
Services.obs.notifyObservers(null, "user-interaction-inactive", null);
|
||||
do_check_eq(recorder.activeTicks, 3);
|
||||
do_check_true(recorder.fineTotalTime > total);
|
||||
total = recorder.fineTotalTime;
|
||||
yield sleep(25);
|
||||
|
||||
// If we send active again, this should be counted as inactive.
|
||||
Services.obs.notifyObservers(null, "user-interaction-active", null);
|
||||
do_check_eq(recorder.activeTicks, 3);
|
||||
do_check_true(recorder.fineTotalTime > total);
|
||||
total = recorder.fineTotalTime;
|
||||
yield sleep(25);
|
||||
|
||||
// If we send active again, this should be counted as active.
|
||||
Services.obs.notifyObservers(null, "user-interaction-active", null);
|
||||
do_check_eq(recorder.activeTicks, 4);
|
||||
|
||||
Services.obs.notifyObservers(null, "user-interaction-active", null);
|
||||
do_check_eq(recorder.activeTicks, 5);
|
||||
|
||||
recorder.onShutdown();
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,122 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
var {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
do_get_profile();
|
||||
|
||||
Cu.import("resource://gre/modules/osfile.jsm");
|
||||
// OS.File doesn't like to be first imported during shutdown
|
||||
Cu.import("resource://gre/modules/Sqlite.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/AsyncShutdown.jsm");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
|
||||
function getConnection(dbName, extraOptions={}) {
|
||||
let path = dbName + ".sqlite";
|
||||
let options = {path: path};
|
||||
for (let [k, v] of Object.entries(extraOptions)) {
|
||||
options[k] = v;
|
||||
}
|
||||
|
||||
return Sqlite.openConnection(options);
|
||||
}
|
||||
|
||||
function* getDummyDatabase(name, extraOptions={}) {
|
||||
const TABLES = {
|
||||
dirs: "id INTEGER PRIMARY KEY AUTOINCREMENT, path TEXT",
|
||||
files: "id INTEGER PRIMARY KEY AUTOINCREMENT, dir_id INTEGER, path TEXT",
|
||||
};
|
||||
|
||||
let c = yield getConnection(name, extraOptions);
|
||||
c._initialStatementCount = 0;
|
||||
|
||||
for (let [k, v] of Object.entries(TABLES)) {
|
||||
yield c.execute("CREATE TABLE " + k + "(" + v + ")");
|
||||
c._initialStatementCount++;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
function sleep(ms) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let timer = Cc["@mozilla.org/timer;1"]
|
||||
.createInstance(Ci.nsITimer);
|
||||
|
||||
timer.initWithCallback({
|
||||
notify: function () {
|
||||
deferred.resolve();
|
||||
},
|
||||
}, ms, timer.TYPE_ONE_SHOT);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// ----------- Don't add a test after this one, as it shuts down Sqlite.jsm
|
||||
//
|
||||
add_task(function* test_shutdown_clients() {
|
||||
do_print("Ensuring that Sqlite.jsm doesn't shutdown before its clients");
|
||||
|
||||
let assertions = [];
|
||||
|
||||
let sleepStarted = false;
|
||||
let sleepComplete = false;
|
||||
Sqlite.shutdown.addBlocker("test_sqlite.js shutdown blocker (sleep)",
|
||||
Task.async(function*() {
|
||||
sleepStarted = true;
|
||||
yield sleep(100);
|
||||
sleepComplete = true;
|
||||
}));
|
||||
assertions.push({name: "sleepStarted", value: () => sleepStarted});
|
||||
assertions.push({name: "sleepComplete", value: () => sleepComplete});
|
||||
|
||||
Sqlite.shutdown.addBlocker("test_sqlite.js shutdown blocker (immediate)",
|
||||
true);
|
||||
|
||||
let dbOpened = false;
|
||||
let dbClosed = false;
|
||||
|
||||
Sqlite.shutdown.addBlocker("test_sqlite.js shutdown blocker (open a connection during shutdown)",
|
||||
Task.async(function*() {
|
||||
let db = yield getDummyDatabase("opened during shutdown");
|
||||
dbOpened = true;
|
||||
db.close().then(
|
||||
() => dbClosed = true
|
||||
); // Don't wait for this task to complete, Sqlite.jsm must wait automatically
|
||||
}));
|
||||
|
||||
assertions.push({name: "dbOpened", value: () => dbOpened});
|
||||
assertions.push({name: "dbClosed", value: () => dbClosed});
|
||||
|
||||
do_print("Now shutdown Sqlite.jsm synchronously");
|
||||
Services.prefs.setBoolPref("toolkit.asyncshutdown.testing", true);
|
||||
AsyncShutdown.profileBeforeChange._trigger();
|
||||
Services.prefs.clearUserPref("toolkit.asyncshutdown.testing");
|
||||
|
||||
|
||||
for (let {name, value} of assertions) {
|
||||
do_print("Checking: " + name);
|
||||
do_check_true(value());
|
||||
}
|
||||
|
||||
do_print("Ensure that we cannot open databases anymore");
|
||||
let exn;
|
||||
try {
|
||||
yield getDummyDatabase("opened after shutdown");
|
||||
} catch (ex) {
|
||||
exn = ex;
|
||||
}
|
||||
do_check_true(!!exn);
|
||||
do_check_true(exn.message.indexOf("Sqlite.jsm has been shutdown") != -1);
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue