mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2026-01-09 00:04:11 +01:00
Merge default.
--HG-- branch : key-processing
This commit is contained in:
22
HACKING
22
HACKING
@@ -133,12 +133,20 @@ In general: Just look at the existing source code!
|
||||
Wrong:
|
||||
function splitStr()
|
||||
|
||||
== Testing/Optimization ==
|
||||
== Testing ==
|
||||
|
||||
TODO: Add some information here about testing/validation/etc.
|
||||
Information about how/when to use :regressions might be nice.
|
||||
Additionally, maybe there should be some benchmark information here --
|
||||
something to let a developer know what's "too" slow...? Or general
|
||||
guidelines about optimization?
|
||||
Functional tests are implemented using the Mozmill automated testing framework
|
||||
-- https://developer.mozilla.org/en/Mozmill_Tests.
|
||||
|
||||
// vim: set ft=asciidoc fdm=marker sw=4 ts=4 et ai:
|
||||
A fresh profile is created for the duration of the test run, however, passing
|
||||
arguments to the host application won't be supported until Mozmill 1.5.2, the
|
||||
next release, so any user RC and plugin files should be temporarily disabled.
|
||||
This can be done by adding the following to the head of the RC file:
|
||||
set loadplugins=
|
||||
finish
|
||||
|
||||
The host application binary tested can be overridden via the HOSTAPP_PATH
|
||||
makefile variable. E.g.,
|
||||
$ HOSTAPP_PATH=/path/to/firefox make -e -C pentadactyl test
|
||||
|
||||
// vim: fdm=marker sw=4 ts=4 et ai:
|
||||
|
||||
@@ -9,6 +9,9 @@ GOOGLE = https://$(GOOGLE_PROJ).googlecode.com/files
|
||||
VERSION ?= $(shell sed -n 's/.*em:version\(>\|="\)\(.*\)["<].*/\2/p' $(TOP)/install.rdf | sed 1q)
|
||||
UUID := $(shell sed -n 's/.*em:id\(>\|="\)\(.*\)["<].*/\2/p' $(TOP)/install.rdf | sed 1q)
|
||||
MANGLE := $(shell date '+%s' | awk '{ printf "%x", $$1 }')
|
||||
MOZMILL = mozmill
|
||||
HOSTAPP_PATH = $(shell which $(HOSTAPP))
|
||||
TEST_DIR = $(BASE)/tests/functional
|
||||
|
||||
LOCALEDIR = locale
|
||||
DOC_FILES = $(wildcard $(LOCALEDIR)/*/*.xml)
|
||||
@@ -48,7 +51,7 @@ CURL ?= curl
|
||||
|
||||
#### rules
|
||||
|
||||
TARGETS = all help info jar xpi install clean distclean install installxpi $(CHROME) $(JAR)
|
||||
TARGETS = all help info jar xpi install clean distclean install installxpi test $(CHROME) $(JAR)
|
||||
$(TARGETS:%=\%.%):
|
||||
echo MAKE $* $(@:$*.%=%)
|
||||
$(MAKE) -C $* $(@:$*.%=%)
|
||||
@@ -71,6 +74,7 @@ help:
|
||||
@echo " make dist - uploads to Google Code (this is not for you)"
|
||||
@echo " make clean - clean up"
|
||||
@echo " make distclean - clean up more"
|
||||
@echo " make test - run functional tests"
|
||||
@echo
|
||||
@echo "running some commands with V=1 will show more build details"
|
||||
|
||||
@@ -158,6 +162,11 @@ distclean:
|
||||
@echo "More $(NAME) cleanup..."
|
||||
rm -rf $(BUILD_DIR)
|
||||
|
||||
# TODO: generalize log path
|
||||
test: $(XPI)
|
||||
@echo "Running functional tests..."
|
||||
$(MOZMILL) --show-all -l /tmp/dactyl-test.log -b $(HOSTAPP_PATH) --addons $(XPI) -t $(TEST_DIR)
|
||||
|
||||
#### xpi
|
||||
|
||||
$(XPI): $(CHROME)
|
||||
|
||||
@@ -105,7 +105,7 @@ var Bookmarks = Module("bookmarks", {
|
||||
*/
|
||||
addSearchKeyword: function (elem) {
|
||||
if (elem instanceof HTMLFormElement || elem.form)
|
||||
var [url, post,, charset] = util.parseForm(elem);
|
||||
var [url, post, charset] = util.parseForm(elem);
|
||||
else
|
||||
var [url, post, charset] = [elem.href || elem.src, null, elem.ownerDocument.characterSet];
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ var StatusLine = Module("statusline", {
|
||||
init: function () {
|
||||
this._statusLine = document.getElementById("status-bar");
|
||||
this.statusBar = document.getElementById("addon-bar") || this._statusLine;
|
||||
this.statusBar.collapsed = true; // it is later restored unless the user sets laststatus=0
|
||||
this.statusBar.collapsed = true;
|
||||
this.baseGroup = this.statusBar == this._statusLine ? "StatusLine " : "";
|
||||
|
||||
if (this.statusBar.localName == "toolbar") {
|
||||
|
||||
@@ -211,8 +211,9 @@
|
||||
<h2 tag="status-line status-bar">Status line</h2>
|
||||
|
||||
<p>
|
||||
The status line appears at the bottom of each window. The <o>laststatus</o>
|
||||
option can be used to specify when the status line appears.
|
||||
The status line appears at the bottom of each window. You can use
|
||||
<o>guioptions</o> to specify if and when the status line appears, as well
|
||||
as its relation to the command line and messages.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -169,8 +169,12 @@ function endModule() {
|
||||
|
||||
function require(obj, name, from) {
|
||||
try {
|
||||
if (arguments.length === 1)
|
||||
[obj, name] = [{}, obj];
|
||||
|
||||
defineModule.loadLog.push((from || "require") + ": loading " + name + " into " + obj.NAME);
|
||||
JSMLoader.load(name + ".jsm", obj);
|
||||
return obj;
|
||||
}
|
||||
catch (e) {
|
||||
defineModule.dump("loading " + String.quote(name + ".jsm") + "\n");
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
try {
|
||||
|
||||
let global = this;
|
||||
Components.utils.import("resource://dactyl/bootstrap.jsm");
|
||||
defineModule("config", {
|
||||
exports: ["ConfigBase", "Config", "config"],
|
||||
@@ -54,7 +55,7 @@ var ConfigBase = Class("ConfigBase", {
|
||||
addon: Class.memoize(function () {
|
||||
let addon = services.fuel.storage.get("dactyl.bootstrap", {}).addon;
|
||||
if (!addon)
|
||||
addon = AddonManager.getAddonByID(this.addonID);
|
||||
addon = require("addons").AddonManager.getAddonByID(this.addonID);
|
||||
return addon;
|
||||
}),
|
||||
|
||||
|
||||
@@ -145,10 +145,10 @@ var Highlights = Module("Highlight", {
|
||||
|
||||
let highlight = this.highlight[key] || this._create(false, [key]);
|
||||
|
||||
let extends = extend || highlight.extend;
|
||||
let bases = extend || highlight.extend;
|
||||
if (append) {
|
||||
newStyle = Styles.append(highlight.value || "", newStyle);
|
||||
extends = highlight.extends.concat(extends);
|
||||
bases = highlight.extends.concat(bases);
|
||||
}
|
||||
|
||||
if (/^\s*$/.test(newStyle))
|
||||
@@ -161,11 +161,11 @@ var Highlights = Module("Highlight", {
|
||||
return null;
|
||||
}
|
||||
newStyle = highlight.defaultValue;
|
||||
extends = highlight.defaultExtends;
|
||||
bases = highlight.defaultExtends;
|
||||
}
|
||||
|
||||
highlight.set("value", newStyle || "");
|
||||
highlight.extends = array.uniq(extends, true);
|
||||
highlight.extends = array.uniq(bases, true);
|
||||
if (force)
|
||||
highlight.style.enabled = true;
|
||||
this.highlight[highlight.class] = highlight;
|
||||
|
||||
@@ -836,7 +836,7 @@ unlet s:cpo_save
|
||||
|
||||
let result = io.system(arg);
|
||||
if (result.returnValue != 0)
|
||||
result.output += "\nshell returned " + res;
|
||||
result.output += "\nshell returned " + result.returnValue;
|
||||
|
||||
modules.commandline.command = "!" + arg;
|
||||
modules.commandline.commandOutput(<span highlight="CmdOutput">{result.output}</span>);
|
||||
|
||||
@@ -1179,7 +1179,7 @@ var Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
|
||||
}
|
||||
}
|
||||
if (post)
|
||||
return [url, elems.join('&'), elems, charset];
|
||||
return [url, elems.join('&'), charset, elems];
|
||||
return [url + "?" + elems.join('&'), null, charset];
|
||||
},
|
||||
|
||||
|
||||
@@ -1,244 +0,0 @@
|
||||
// Copyright (c) 2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
|
||||
//
|
||||
// This work is licensed for reuse under an MIT license. Details are
|
||||
// given in the LICENSE.txt file included with this file.
|
||||
|
||||
|
||||
// Script to find regressions
|
||||
//
|
||||
// It should use as few dactyl methods as possible, but fall back to standard mozilla/DOM methods
|
||||
// The reason is, we don't want to find regressions in the regressions script, and it should survive
|
||||
// massive changes in the internal dactyl API, but just test for functionality of
|
||||
// user-visible commands/mappings
|
||||
//
|
||||
// NOTE: It is preferable to run this script in a clean profile or at least do NOT use
|
||||
// :mkpentadactylrc afterwards, as it can remove commands/mappings, etc.
|
||||
//
|
||||
// Usage: :[count]regr[essions]
|
||||
// When [count] is given, just run this test. TODO: move to :regressions [spec]?
|
||||
|
||||
// all tests
|
||||
var skipTests = [":bmarks", "gg"];
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Put definitions here which might change due to internal dactyl refactoring
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var doc; // document where we output status messages
|
||||
var multilineOutput = document.getElementById("dactyl-multiline-output");
|
||||
var singlelineOutput = document.getElementById("dactyl-message");
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// TESTS
|
||||
//
|
||||
// They are run in order, so you can specify commands which expect side effects of a
|
||||
// previous command
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// A series of Ex commands or mappings, each with a
|
||||
// function checking whether the command succeeded
|
||||
// If the string starts with a ":" it is executed as an Ex command, otherwise as a mapping
|
||||
// You can also mix commands and mappings
|
||||
let tests = [
|
||||
{ cmds: [":!dir"],
|
||||
verify: function () getMultilineOutput().length > 10 },
|
||||
{ cmds: [":abbr VIMP pentadactyl labs", ":abbr"],
|
||||
verify: function () getOutput().indexOf("pentadactyl labs") >= 0 },
|
||||
{ cmds: [":unabbr VIMP", ":abbr"],
|
||||
verify: function () getOutput().indexOf("pentadactyl labs") == -1 },
|
||||
{ cmds: [":bmarks"],
|
||||
verify: function () getMultilineOutput().length > 100 },
|
||||
{ cmds: [":echo \"test\""],
|
||||
verify: function () getSinglelineOutput() == "test" },
|
||||
{ cmds: [":qmark V http://test.vimperator.org", ":qmarks"],
|
||||
verify: function () getMultilineOutput().indexOf("test.vimperator.org") >= 0 },
|
||||
{ cmds: [":javascript dactyl.echo('test', commandline.FORCE_MULTILINE)"],
|
||||
verify: function () getMultilineOutput() == "test" },
|
||||
// { cmds: [":echomsg \"testmsg\""],
|
||||
// verify: function () getOutput() == "testmsg" },
|
||||
// { cmds: [":echoerr \"testerr\""],
|
||||
// verify: function () getOutput() == "testerr" },
|
||||
{ cmds: ["gg", "<C-f>"], // NOTE: does not work when there is no page to scroll, we should load a large page before doing these tests
|
||||
verify: function () this._initialPos.y != getBufferPosition().y,
|
||||
init: function () this._initialPos = getBufferPosition() }
|
||||
|
||||
// testing tab behavior
|
||||
];
|
||||
|
||||
// these functions highly depend on the dactyl API, so use Ex command tests whenever possible
|
||||
let functions = [
|
||||
function () { return bookmarks.get("").length > 0 }, // will fail for people without bookmarks :( Might want to add one before
|
||||
function () { return history.get("").length > 0 }
|
||||
];
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// functions below should be as generic as possible, and not require being rewritten
|
||||
// even after doing major Pentadactyl refactoring
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function resetEnvironment() {
|
||||
multilineOutput.contentDocument.body.innerHTML = "";
|
||||
singlelineOutput.value = "";
|
||||
commandline.close();
|
||||
modes.reset();
|
||||
}
|
||||
|
||||
function getOutput() multilineOutput.contentDocument.body.textContent || singlelineOutput.value;
|
||||
function getMultilineOutput() multilineOutput.contentDocument.body.textContent;
|
||||
function getSinglelineOutput() singlelineOutput.value;
|
||||
|
||||
function getTabIndex() getBrowser().mTabContainer.selectedIndex;
|
||||
function getTabCount() getBrowser().mTabs.length;
|
||||
|
||||
function getBufferPosition() {
|
||||
let win = window.content;
|
||||
return { x: win.scrollMaxX ? win.pageXOffset / win.scrollMaxX : 0,
|
||||
y: win.scrollMaxY ? win.pageYOffset / win.scrollMaxY : 0 }
|
||||
};
|
||||
|
||||
function getLocation() window.content.document.location.href;
|
||||
|
||||
function echoLine(str, group) {
|
||||
if (!doc)
|
||||
return;
|
||||
|
||||
doc.body.appendChild(util.xmlToDom(
|
||||
<div highlight={group} style="border: 1px solid gray; white-space: pre; height: 1.5em; line-height: 1.5em;">{str}</div>,
|
||||
doc));
|
||||
}
|
||||
function echoMulti(str, group) {
|
||||
if (!doc)
|
||||
return;
|
||||
|
||||
doc.body.appendChild(util.xmlToDom(<div class="ex-command-output"
|
||||
style="white-space: nowrap; border: 1px solid black; min-height: 1.5em;"
|
||||
highlight={group}>{template.maybeXML(str)}</div>,
|
||||
doc));
|
||||
}
|
||||
|
||||
commands.addUserCommand(["regr[essions]"],
|
||||
"Run regression tests",
|
||||
function (args) {
|
||||
// TODO: might need to increase the 'messages' option temporarily
|
||||
// TODO: count (better even range) support to just run test 34 of 102
|
||||
// TODO: bang support to either: a) run commands like deleting bookmarks which
|
||||
// should only be done in a clean profile or b) run functions and not
|
||||
// just Ex command tests; Yet to be decided
|
||||
|
||||
let updateOutputHeight = null;
|
||||
function init() {
|
||||
dactyl.registerObserver("echoLine", echoLine);
|
||||
dactyl.registerObserver("echoMultiline", echoMulti);
|
||||
dactyl.open("chrome://dactyl/content/buffer.xhtml", dactyl.NEW_TAB);
|
||||
events.waitForPageLoad();
|
||||
doc = content.document;
|
||||
doc.body.setAttributeNS(NS.uri, "highlight", "CmdLine");
|
||||
|
||||
updateOutputHeight = commandline.updateOutputHeight;
|
||||
commandline.updateOutputHeight = function (open) {
|
||||
let elem = document.getElementById("dactyl-multiline-output");
|
||||
if (open)
|
||||
elem.collapsed = false;
|
||||
elem.height = 0;
|
||||
};
|
||||
}
|
||||
function cleanup() {
|
||||
dactyl.unregisterObserver("echoLine", echoLine);
|
||||
dactyl.unregisterObserver("echoMultiline", echoMulti);
|
||||
commandline.updateOutputHeight = updateOutputHeight;
|
||||
}
|
||||
|
||||
function run() {
|
||||
let now = Date.now();
|
||||
let totalTests = tests.length + functions.length;
|
||||
let successfulTests = 0;
|
||||
let skippedTests = 0;
|
||||
let currentTest = 0;
|
||||
|
||||
init();
|
||||
|
||||
// TODO: might want to unify 'tests' and 'functions' handling
|
||||
// 1.) run commands and mappings tests
|
||||
outer:
|
||||
for (let [, test] in Iterator(tests)) {
|
||||
currentTest++;
|
||||
if (args.count >= 1 && currentTest != args.count)
|
||||
continue;
|
||||
|
||||
let testDescription = util.clip(test.cmds.join(" -> "), 80);
|
||||
for (let [, cmd] in Iterator(test.cmds)) {
|
||||
if (skipTests.indexOf(cmd) != -1) {
|
||||
skippedTests++;
|
||||
dactyl.echomsg("Skipping test " + currentTest + " of " + totalTests + ": " + testDescription, 0);
|
||||
continue outer;
|
||||
}
|
||||
};
|
||||
|
||||
commandline.echo("Running test " + currentTest + " of " + totalTests + ": " + testDescription, "Filter", commandline.APPEND_TO_MESSAGES);
|
||||
resetEnvironment();
|
||||
if ("init" in test)
|
||||
test.init();
|
||||
|
||||
test.cmds.forEach(function (cmd) {
|
||||
if (cmd[0] == ":")
|
||||
dactyl.execute(cmd);
|
||||
else
|
||||
events.feedkeys(cmd);
|
||||
});
|
||||
|
||||
if (!test.verify())
|
||||
dactyl.echoerr("Test " + currentTest + " failed: " + testDescription);
|
||||
else
|
||||
successfulTests++;
|
||||
}
|
||||
|
||||
// 2.) Run function tests
|
||||
for (let [, func] in Iterator(functions)) {
|
||||
currentTest++;
|
||||
if (args.count >= 1 && currentTest != args.count)
|
||||
continue;
|
||||
|
||||
commandline.echo("Running test " + currentTest + " of " + totalTests + ": " + util.clip(func.toString().replace(/[\s\n]+/gm, " "), 80), "Filter", commandline.APPEND_TO_MESSAGES);
|
||||
resetEnvironment();
|
||||
|
||||
if (!func())
|
||||
dactyl.echoerr("Test " + currentTest + " failed!");
|
||||
else
|
||||
successfulTests++;
|
||||
}
|
||||
|
||||
cleanup();
|
||||
|
||||
let runTests = (args.count >= 1 ? 1 : totalTests) - skippedTests;
|
||||
XML.ignoreWhitespace = false;
|
||||
dactyl.echomsg(<e4x>
|
||||
<span style="font-weight: bold">{successfulTests}</span> of <span style="font-weight: bold">{runTests}</span>
|
||||
tests successfully completed (<span style="font-weight: bold">{skippedTests}</span> tests skipped) in
|
||||
<span class="time-total">{((Date.now() - now) / 1000.0)}</span> msec
|
||||
</e4x>.*);
|
||||
dactyl.execute(":messages");
|
||||
}
|
||||
|
||||
if (!args.bang) {
|
||||
dactyl.echo(<e4x>
|
||||
<span style="font-weight: bold">Running tests should always be done in a new profile.</span><br/>
|
||||
|
||||
It should not do any harm to your profile, but your current settings like options,
|
||||
abbreviations or mappings might not be in the same state as before running the tests.
|
||||
Just make sure, you don't :mkpentadactylrc, after running the tests.<br/><br/>
|
||||
<!--' vim. -->
|
||||
|
||||
Use :regressions! to skip this prompt.
|
||||
</e4x>.*);
|
||||
commandline.input("Type 'yes' to run the tests: ", function (res) { if (res == "yes") run(); } );
|
||||
return;
|
||||
}
|
||||
run();
|
||||
},
|
||||
{
|
||||
bang: true,
|
||||
argCount: "0",
|
||||
count: true
|
||||
});
|
||||
|
||||
// vim: set et sts=4 sw=4 :
|
||||
Reference in New Issue
Block a user