config/emacs.d/swank-js/swank-handler-tests.js
2011-06-26 15:55:20 -07:00

292 lines
11 KiB
JavaScript

// -*- mode: js2; js-run: t -*-
//
// Copyright (c) 2010 Ivan Shvedunov. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
var swh = require("./swank-handler");
var readFromString = require("./lisp").readFromString;
var config = require("./config");
var util = require("util");
var assert = require("assert");
var cfg = new config.FakeConfig();
var expected = [];
var executive = new swh.Executive({ config: cfg, pid: 4242 });
var handler = new swh.Handler(executive);
handler.on(
"response", function (response) {
// console.log("=> %s", response);
assert.ok(expected.length > 0);
assert.ok(typeof(response) == "string");
// console.log("response: %s", response);
var expectedResponse = expected.shift();
if (expectedResponse instanceof RegExp)
assert.ok(expectedResponse.test(response));
else
assert.equal(expectedResponse, response,
"got response " + response + " instead of " + expectedResponse);
});
function expect () {
for (var i = 0; i < arguments.length; ++i)
expected.push(arguments[i]);
}
function verifyExpectations () {
// console.log("expected: %s\n", expected.map(JSON.stringify).join("\n"));
assert.equal(0, expected.length);
}
function request (str) {
for (var i = 1; i < arguments.length; ++i)
expected.push(arguments[i]);
handler.receive(readFromString(str));
verifyExpectations();
}
request('(:emacs-rex (swank:connection-info) "COMMON-LISP-USER" t 1)',
'(:return (:ok (:encoding (:coding-system "utf-8" :external-format "UTF-8") ' +
':lisp-implementation (:name "JS" :type "JS" :version "1.5") ' +
':package (:name "NODE" :prompt "NODE") ' +
':pid 4242 :version "2010-11-13")) ' +
'1)');
// currently we just ignore swank-require
request('(:emacs-rex (swank:swank-require \'(swank-listener-hooks swank-indentation)) "COMMON-LISP-USER" t 2)',
'(:return (:ok nil) 2)');
request('(:emacs-rex (swank:create-repl nil) "COMMON-LISP-USER" t 3)',
'(:return (:ok ("NODE" "NODE")) 3)');
request('(:emacs-rex (swank:listener-eval "3 * 10\n") "NODE" :repl-thread 4)',
'(:return (:ok (:values "30")) 4)');
request('(:emacs-rex (swank:listener-eval "undefined") "NODE" :repl-thread 5)',
'(:return (:ok nil) 5)');
request('(:emacs-rex (swank:autodoc \'("zzzz" swank::%cursor-marker%) :print-right-margin 236)' +
' "COMMON-LISP-USER" :repl-thread 6)',
'(:return (:ok :not-available) 6)');
request('(:emacs-rex (swank:listener-eval "_swank.output(\'hello world\\\\n\')") "NODE" :repl-thread 7)',
'(:write-string "hello world\n")',
'(:return (:ok nil) 7)');
request('(:emacs-rex (swank:listener-eval "_swank.output(1234)") "NODE" :repl-thread 8)',
'(:write-string "1234")',
'(:return (:ok nil) 8)');
request('(:emacs-rex (swank:listener-eval "zzz") "NODE" :repl-thread 9)',
/^\(:write-string "ReferenceError: zzz is not defined(.|\n)*"\)$/,
'(:return (:ok nil) 9)');
// TBD: debugger
function FakeRemote (name) {
this.name = name;
};
util.inherits(FakeRemote, swh.Remote);
FakeRemote.prototype.prompt = function prompt () {
return "FAKE";
};
FakeRemote.prototype.kind = function kind () {
return "test";
};
FakeRemote.prototype.id = function id () {
return this.name;
};
FakeRemote.prototype.evaluate = function evaluate (id, str) {
this.sendResult(id, [ "R:" + this.name + ":" + str.replace(/^\s*|\s*$/g, "") ]);
};
request('(:emacs-rex (js:list-remotes) "NODE" :repl-thread 10)',
'(:return (:ok ((1 :direct "node.js" t))) 10)');
expect('(:write-string "Remote attached: (test) test/localhost:8080\n")');
var r1 = new FakeRemote("test/localhost:8080");
executive.attachRemote(r1);
verifyExpectations();
request('(:emacs-rex (js:list-remotes) "NODE" :repl-thread 11)',
'(:return (:ok ((1 :direct "node.js" t) (2 :test "test/localhost:8080" nil))) 11)');
expect('(:write-string "Remote attached: (test) test/localhost:9999\n")');
var r2 = new FakeRemote("test/localhost:9999");
executive.attachRemote(r2);
verifyExpectations();
request('(:emacs-rex (js:list-remotes) "NODE" :repl-thread 12)',
'(:return (:ok ((1 :direct "node.js" t) ' +
'(2 :test "test/localhost:8080" nil) ' +
'(3 :test "test/localhost:9999" nil))) 12)');
request('(:emacs-rex (swank:listener-eval "3 * 10\n") "NODE" :repl-thread 13)',
'(:return (:ok (:values "30")) 13)');
request('(:emacs-rex (js:select-remote 2 nil) "NODE" :repl-thread 14)',
'(:new-package "FAKE" "FAKE")',
'(:write-string "Remote selected: (test) test/localhost:8080\n")',
'(:return (:ok nil) 14)');
request('(:emacs-rex (js:list-remotes) "NODE" :repl-thread 15)',
'(:return (:ok ((1 :direct "node.js" nil) ' +
'(2 :test "test/localhost:8080" t) ' +
'(3 :test "test/localhost:9999" nil))) 15)');
request('(:emacs-rex (swank:listener-eval "3 * 10\n") "NODE" :repl-thread 16)',
'(:return (:ok (:values "R:test/localhost:8080:3 * 10")) 16)');
expect('(:write-string "Remote detached: (test) test/localhost:8080\n")',
'(:new-package "NODE" "NODE")',
'(:write-string "Remote selected (auto): (direct) node.js\n")');
r1.disconnect();
verifyExpectations();
request('(:emacs-rex (swank:listener-eval "3 * 10\n") "NODE" :repl-thread 17)',
'(:return (:ok (:values "30")) 17)');
// TBD: add higher-level functions for testing remotes
request('(:emacs-rex (js:list-remotes) "NODE" :repl-thread 18)',
'(:return (:ok ((1 :direct "node.js" t) ' +
'(3 :test "test/localhost:9999" nil))) 18)');
expect('(:write-string "Remote detached: (test) test/localhost:9999\n")');
r2.disconnect();
verifyExpectations();
request('(:emacs-rex (swank:listener-eval "3 * 10\n") "NODE" :repl-thread 19)',
'(:return (:ok (:values "30")) 19)');
request('(:emacs-rex (js:list-remotes) "NODE" :repl-thread 20)',
'(:return (:ok ((1 :direct "node.js" t))) 20)');
request('(:emacs-rex (js:select-remote 2 nil) "NODE" :repl-thread 21)',
'(:write-string "WARNING: bad remote index\n")',
'(:return (:ok nil) 21)');
request('(:emacs-rex (swank:listener-eval "3 * 10\n") "NODE" :repl-thread 22)',
'(:return (:ok (:values "30")) 22)');
request('(:emacs-rex (js:select-remote 1 nil) "NODE" :repl-thread 23)',
'(:write-string "WARNING: remote already selected: (direct) node.js\n")',
'(:return (:ok nil) 23)');
assert.equal(null, cfg.getNow("stickyRemote"));
// test sticky remote selection
expect('(:write-string "Remote attached: (test) test/localhost:8001\n")');
var r3 = new FakeRemote("test/localhost:8001");
executive.attachRemote(r3);
verifyExpectations();
request('(:emacs-rex (js:list-remotes) "NODE" :repl-thread 24)',
'(:return (:ok ((1 :direct "node.js" t) (4 :test "test/localhost:8001" nil))) 24)');
request('(:emacs-rex (js:select-remote 4 t) "NODE" :repl-thread 25)',
'(:new-package "FAKE" "FAKE")',
'(:write-string "Remote selected (sticky): (test) test/localhost:8001\n")',
'(:return (:ok nil) 25)');
assert.equal("(test) test/localhost:8001", cfg.getNow("stickyRemote"));
expect('(:write-string "Remote detached: (test) test/localhost:8001\n")',
'(:new-package "NODE" "NODE")',
'(:write-string "Remote selected (auto): (direct) node.js\n")');
r3.disconnect();
verifyExpectations();
expect('(:write-string "Remote attached: (test) test/localhost:8001\n")',
'(:new-package "FAKE" "FAKE")',
'(:write-string "Remote selected (auto): (test) test/localhost:8001\n")');
var r5 = new FakeRemote("test/localhost:8001");
executive.attachRemote(r5);
verifyExpectations();
assert.equal("(test) test/localhost:8001", cfg.getNow("stickyRemote"));
request('(:emacs-rex (js:select-remote 1 nil) "NODE" :repl-thread 26)',
'(:new-package "NODE" "NODE")',
'(:write-string "Remote selected: (direct) node.js\n")',
'(:return (:ok nil) 26)');
request('(:emacs-rex (js:select-remote 5 nil) "NODE" :repl-thread 27)',
'(:new-package "FAKE" "FAKE")',
'(:write-string "Remote selected: (test) test/localhost:8001\n")',
'(:return (:ok nil) 27)');
assert.equal(null, cfg.getNow("stickyRemote"));
expect('(:write-string "Remote detached: (test) test/localhost:8001\n")',
'(:new-package "NODE" "NODE")',
'(:write-string "Remote selected (auto): (direct) node.js\n")');
r5.disconnect();
verifyExpectations();
expect('(:write-string "Remote attached: (test) test/localhost:8001\n")');
var r6 = new FakeRemote("test/localhost:8001");
executive.attachRemote(r6);
verifyExpectations();
assert.equal(null, cfg.getNow("stickyRemote"));
request('(:emacs-rex (js:set-target-url "http://localhost:1234/") "NODE" :repl-thread 28)',
'(:return (:ok nil) 28)');
assert.equal("http://localhost:1234/", cfg.getNow("targetUrl"));
request('(:emacs-rex (js:set-target-url "zzz") "NODE" :repl-thread 29)',
'(:write-string "WARNING: the URL must contain host and port\n")',
'(:return (:ok nil) 29)');
assert.equal("http://localhost:1234/", cfg.getNow("targetUrl"));
assert.equal(null, cfg.getNow("slimeVersion"));
request('(:emacs-rex (js:set-slime-version "2010-11-28") "NODE" :repl-thread 30)',
'(:return (:ok nil) 30)');
assert.equal("2010-11-28", cfg.getNow("slimeVersion"));
// TBD: use ## instead of numbers in the tests above (request() should take care of it)
// TBD: test output from an inactive remote
// TBD: are out-of-order results for :emacs-rex ok? look at slime sources
/*
list/select remotes along the lines of
catching errors on the client: window.onerror
http://stackoverflow.com/questions/951791/javascript-global-error-handling
*/
// TBD: add \n to messages from remotes / executive