1
0
mirror of https://github.com/fcwu/docker-ubuntu-vnc-desktop synced 2026-08-05 16:12:41 +02:00

feat: upgrade noVNC

This commit is contained in:
Doro Wu
2017-02-25 12:55:24 +08:00
parent 394c340688
commit 0c04c5ec3b
489 changed files with 18241 additions and 54521 deletions
-39
View File
@@ -1,39 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Javascript Arrays Performance Test</title>
<!--
<script type='text/javascript'
src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
-->
<script src="../include/util.js"></script>
<script src="../include/webutil.js"></script>
<script src="browser.js"></script>
<script src="stats.js"></script>
<script src="arrays.js"></script>
</head>
<body>
<h3>Javascript Arrays Performance Test</h3>
Iterations: <input id='iterations' style='width:50'>&nbsp;
Array Size: <input id='arraySize' style='width:40'>*1024&nbsp;
<input id='startButton' type='button' value='Run Tests'
onclick="begin();">&nbsp;
<br><br>
Results:<br>
<textarea id="messages" style="font-size: 9;" cols=80 rows=50></textarea>
</br>
<canvas id="canvas" style="display: none;"></canvas>
</body>
<script>
var verbose = true;
window.onload = function() {
vmessage("in onload");
init();
}
</script>
</html>
-375
View File
@@ -1,375 +0,0 @@
/*
* Javascript binary array performance tests
* Copyright (C) 2012 Joel Martin
* Licensed under MPL 2.0 (see LICENSE.txt)
*/
var ctx, i, j, randlist,
new_normal, new_imageData, new_arrayBuffer,
browser = Browser.browser + " " +
Browser.version + " on " +
Browser.OS,
do_imageData = false,
do_arrayBuffer = false,
conf = {
'create_cnt' : 2000,
'read_cnt' : 5000000,
'write_cnt' : 5000000,
'iterations' : 0,
'order_l1' : [browser],
'order_l2' : ['normal',
'imageData',
'arrayBuffer'],
'order_l3' : ['create',
'sequentialRead',
'randomRead',
'sequentialWrite']
},
stats = {},
testFunc = {},
iteration, arraySize;
var newline = "\n";
if (Util.Engine.trident) {
var newline = "<br>\n";
}
function message(str) {
//console.log(str);
cell = $D('messages');
cell.innerHTML += str + newline;
cell.scrollTop = cell.scrollHeight;
}
function vmessage(str) {
if (verbose) {
message(str);
} else {
console.log(str);
}
}
new_normal = function() {
var arr = [], i;
for (i = 0; i < arraySize; i++) {
arr[i] = 0;
}
return arr;
}
/* Will be overridden with real function */
new_imageData = function() {
throw("imageData not supported");
};
new_imageData_createImageData = function() {
var imageData = ctx.createImageData(1024/4, arraySize / 1024);
return imageData.data;
};
new_imageData_getImageData = function() {
var imageData = ctx.getImageData(0, 0, 1024/4, arraySize / 1024),
arr = imageData.data;
for (i = 0; i < arraySize; i++) {
arr[i] = 0;
}
return arr;
};
new_arrayBuffer = function() {
var arr = new ArrayBuffer(arraySize);
return new Uint8Array(arr);
}
function init_randlist() {
randlist = [];
for (var i=0; i < arraySize; i++) {
randlist[i] = parseInt(Math.random() * 256, 10);
}
}
function copy_randlist(arr) {
for (var i=0; i < arraySize; i++) {
arr[i] = randlist[i];
}
}
function begin() {
var i, j;
conf.iterations = parseInt($D('iterations').value, 10);
arraySize = parseInt($D('arraySize').value, 10) * 1024;
init_randlist();
// TODO: randomize test_list
stats = {};
for (i = 0; i < conf.order_l2.length; i++) {
stats[conf.order_l2[i]] = {};
for (j = 0; j < conf.order_l3.length; j++) {
stats[conf.order_l2[i]][conf.order_l3[j]] = [];
}
}
$D('startButton').value = "Running";
$D('startButton').disabled = true;
message("running " + conf.iterations + " test iterations");
iteration = 1;
setTimeout(run_next_iteration, 250);
}
function finish() {
var totalTime, arrayType, testType, times;
message("tests finished");
for (j = 0; j < conf.order_l3.length; j++) {
testType = conf.order_l3[j];
message("Test '" + testType + "'");
for (i = 0; i < conf.order_l2.length; i++) {
arrayType = conf.order_l2[i];
message(" Array Type '" + arrayType);
times = stats[arrayType][testType];
message(" Average : " + times.mean() + "ms" +
" (Total: " + times.sum() + "ms)");
message(" Min/Max : " + times.min() + "ms/" +
times.max() + "ms");
message(" StdDev : " + times.stdDev() + "ms");
}
}
vmessage("array_chart.py JSON data:");
chart_data = {'conf' : conf, 'stats' : { } };
chart_data.stats[browser] = stats;
chart_data.stats['next_browser'] = {};
vmessage(JSON.stringify(chart_data, null, 2));
$D('startButton').disabled = false;
$D('startButton').value = "Run Tests";
}
function run_next_iteration() {
var arrayType, testType, deltaTime;
for (i = 0; i < conf.order_l2.length; i++) {
arrayType = conf.order_l2[i];
if (arrayType === 'imageData' && (!do_imageData)) {
continue;
}
if (arrayType === 'arrayBuffer' && (!do_arrayBuffer)) {
continue;
}
for (j = 0; j < conf.order_l3.length; j++) {
testType = conf.order_l3[j];
deltaTime = testFunc[arrayType + "_" + testType]();
stats[arrayType][testType].push(deltaTime);
vmessage("test " + (arrayType + "_" + testType) +
" time: " + (deltaTime) + "ms");
}
}
message("finished test iteration " + iteration);
if (iteration >= conf.iterations) {
setTimeout(finish, 1);
return;
}
iteration++;
setTimeout(run_next_iteration, 1);
}
/*
* Test functions
*/
testFunc["normal_create"] = function() {
var cnt, arrNormal, startTime, endTime;
vmessage("create normal array " + conf.create_cnt + "x, initialized to 0");
startTime = (new Date()).getTime();
for (cnt = 0; cnt < conf.create_cnt; cnt++) {
arrNormal = new_normal();
}
endTime = (new Date()).getTime();
return endTime - startTime;
};
testFunc["imageData_create"] = function() {
var cnt, arrImage, startTime, endTime;
vmessage("create imageData array " + conf.create_cnt + "x, initialized to 0");
startTime = (new Date()).getTime();
for (cnt = 0; cnt < conf.create_cnt; cnt++) {
arrImage = new_imageData();
}
endTime = (new Date()).getTime();
if (arrImage[103] !== 0) {
message("Initialization failed, arrImage[103] is: " + arrImage[103]);
throw("Initialization failed, arrImage[103] is: " + arrImage[103]);
}
return endTime - startTime;
};
testFunc["arrayBuffer_create"] = function() {
var cnt, arrBuffer, startTime, endTime;
vmessage("create arrayBuffer array " + conf.create_cnt + "x, initialized to 0");
startTime = (new Date()).getTime();
for (cnt = 0; cnt < conf.create_cnt; cnt++) {
arrBuffer = new_arrayBuffer();
}
endTime = (new Date()).getTime();
if (arrBuffer[103] !== 0) {
message("Initialization failed, arrBuffer[103] is: " + arrBuffer[103]);
throw("Initialization failed, arrBuffer[103] is: " + arrBuffer[103]);
}
return endTime - startTime;
};
function test_sequentialRead(arr) {
var i, j, cnt, startTime, endTime;
/* Initialize the array */
copy_randlist(arr);
startTime = (new Date()).getTime();
i = 0;
j = 0;
for (cnt = 0; cnt < conf.read_cnt; cnt++) {
j = arr[i];
i++;
if (i >= arraySize) {
i = 0;
}
}
endTime = (new Date()).getTime();
return endTime - startTime;
}
function test_randomRead(arr) {
var i, cnt, startTime, endTime;
/* Initialize the array */
copy_randlist(arr); // used as jumplist
startTime = (new Date()).getTime();
i = 0;
for (cnt = 0; cnt < conf.read_cnt; cnt++) {
i = (arr[i] + cnt) % arraySize;
}
endTime = (new Date()).getTime();
return endTime - startTime;
}
function test_sequentialWrite(arr) {
var i, cnt, startTime, endTime;
/* Initialize the array */
copy_randlist(arr);
startTime = (new Date()).getTime();
i = 0;
for (cnt = 0; cnt < conf.write_cnt; cnt++) {
arr[i] = (cnt % 256);
i++;
if (i >= arraySize) {
i = 0;
}
}
endTime = (new Date()).getTime();
return endTime - startTime;
}
/* Sequential Read Tests */
testFunc["normal_sequentialRead"] = function() {
vmessage("read normal array " + conf.read_cnt + "x");
return test_sequentialRead(new_normal());
};
testFunc["imageData_sequentialRead"] = function() {
vmessage("read imageData array " + conf.read_cnt + "x");
return test_sequentialRead(new_imageData());
};
testFunc["arrayBuffer_sequentialRead"] = function() {
vmessage("read arrayBuffer array " + conf.read_cnt + "x");
return test_sequentialRead(new_arrayBuffer());
};
/* Random Read Tests */
testFunc["normal_randomRead"] = function() {
vmessage("read normal array " + conf.read_cnt + "x");
return test_randomRead(new_normal());
};
testFunc["imageData_randomRead"] = function() {
vmessage("read imageData array " + conf.read_cnt + "x");
return test_randomRead(new_imageData());
};
testFunc["arrayBuffer_randomRead"] = function() {
vmessage("read arrayBuffer array " + conf.read_cnt + "x");
return test_randomRead(new_arrayBuffer());
};
/* Sequential Write Tests */
testFunc["normal_sequentialWrite"] = function() {
vmessage("write normal array " + conf.write_cnt + "x");
return test_sequentialWrite(new_normal());
};
testFunc["imageData_sequentialWrite"] = function() {
vmessage("write imageData array " + conf.write_cnt + "x");
return test_sequentialWrite(new_imageData());
};
testFunc["arrayBuffer_sequentialWrite"] = function() {
vmessage("write arrayBuffer array " + conf.write_cnt + "x");
return test_sequentialWrite(new_arrayBuffer());
};
init = function() {
vmessage(">> init");
$D('iterations').value = 10;
$D('arraySize').value = 10;
arraySize = parseInt($D('arraySize').value, 10) * 1024;
message("Browser: " + browser);
/* Determine browser binary array support */
try {
ctx = $D('canvas').getContext('2d');
new_imageData = new_imageData_createImageData;
new_imageData();
do_imageData = true;
} catch (exc) {
vmessage("createImageData not supported: " + exc);
try {
ctx = $D('canvas').getContext('2d');
new_imageData = new_imageData_getImageData;
blah = new_imageData();
do_imageData = true;
} catch (exc) {
vmessage("getImageData not supported: " + exc);
}
}
if (! do_imageData) {
message("imageData arrays not supported");
}
try {
new_arrayBuffer();
do_arrayBuffer = true;
} catch (exc) {
vmessage("Typed Arrays not supported: " + exc);
}
if (! do_arrayBuffer) {
message("Typed Arrays (ArrayBuffers) not suppoted");
}
vmessage("<< init");
}
+84 -5
View File
@@ -2,10 +2,26 @@
chai.use(function (_chai, utils) {
_chai.Assertion.addMethod('displayed', function (target_data) {
var obj = this._obj;
var data_cl = obj._drawCtx.getImageData(0, 0, obj._viewportLoc.w, obj._viewportLoc.h).data;
var ctx = obj._target.getContext('2d');
var data_cl = ctx.getImageData(0, 0, obj._target.width, obj._target.height).data;
// NB(directxman12): PhantomJS 1.x doesn't implement Uint8ClampedArray, so work around that
var data = new Uint8Array(data_cl);
this.assert(utils.eql(data, target_data),
var same = true;
var len = data_cl.length;
if (len != target_data.length) {
same = false;
} else {
for (var i = 0; i < len; i++) {
if (data[i] != target_data[i]) {
same = false;
break;
}
}
}
if (!same) {
console.log("expected data: %o, actual data: %o", target_data, data);
}
this.assert(same,
"expected #{this} to have displayed the image #{exp}, but instead it displayed #{act}",
"expected #{this} not to have displayed the image #{act}",
target_data,
@@ -14,11 +30,74 @@ chai.use(function (_chai, utils) {
_chai.Assertion.addMethod('sent', function (target_data) {
var obj = this._obj;
obj.inspect = function () {
var res = { _websocket: obj._websocket, rQi: obj._rQi, _rQ: new Uint8Array(obj._rQ.buffer, 0, obj._rQlen),
_sQ: new Uint8Array(obj._sQ.buffer, 0, obj._sQlen) };
res.prototype = obj;
return res;
};
var data = obj._websocket._get_sent_data();
this.assert(utils.eql(data, target_data),
var same = true;
if (data.length != target_data.length) {
same = false;
} else {
for (var i = 0; i < data.length; i++) {
if (data[i] != target_data[i]) {
same = false;
break;
}
}
}
if (!same) {
console.log("expected data: %o, actual data: %o", target_data, data);
}
this.assert(same,
"expected #{this} to have sent the data #{exp}, but it actually sent #{act}",
"expected #{this} not to have sent the data #{act}",
target_data,
data);
Array.prototype.slice.call(target_data),
Array.prototype.slice.call(data));
});
_chai.Assertion.addProperty('array', function () {
utils.flag(this, 'array', true);
});
_chai.Assertion.overwriteMethod('equal', function (_super) {
return function assertArrayEqual(target) {
if (utils.flag(this, 'array')) {
var obj = this._obj;
var i;
var same = true;
if (utils.flag(this, 'deep')) {
for (i = 0; i < obj.length; i++) {
if (!utils.eql(obj[i], target[i])) {
same = false;
break;
}
}
this.assert(same,
"expected #{this} to have elements deeply equal to #{exp}",
"expected #{this} not to have elements deeply equal to #{exp}",
Array.prototype.slice.call(target));
} else {
for (i = 0; i < obj.length; i++) {
if (obj[i] != target[i]) {
same = false;
break;
}
}
this.assert(same,
"expected #{this} to have elements equal to #{exp}",
"expected #{this} not to have elements equal to #{exp}",
Array.prototype.slice.call(target));
}
} else {
_super.apply(this, arguments);
}
};
});
});
-91
View File
@@ -1,91 +0,0 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Native Base64 Tests</title>
<script src="../include/util.js"></script>
<script src="../include/webutil.js"></script>
<script src="../include/base64.js"></script>
</head>
<body>
<h1>Native Base64 Tests</h1>
<br>
Messages:<br>
<textarea id="debug" style="font-size: 9px;" cols=80 rows=25></textarea>
<br>
</body>
<script>
function debug(str) {
console.log(str);
cell = $D('debug');
cell.innerHTML += str + "\n";
cell.scrollTop = cell.scrollHeight;
}
function assertRun(code, result) {
try {
var actual = eval(code);
} catch (exc) {
debug("FAIL: '" + code + "' threw an exception");
fail += 1;
return false;
}
if (actual !== result) {
debug("FAIL: '" + code + "' returned '" + actual + "', expected '" + result + "'");
fail += 1;
return false;
}
debug("PASS: '" + code + "' returned expected '" + result +"'");
pass += 1;
return true;
}
function Base64_decode(data) {
var arr = Base64.decode (data);
return arr.map(function (num) {
return String.fromCharCode(num); } ).join('');
}
window.onload = function() {
var str;
debug('onload');
fail = 0;
pass = 0;
assertRun('window.btoa("hello world")', 'aGVsbG8gd29ybGQ=');
assertRun('window.btoa("a")', 'YQ==');
assertRun('window.btoa("ab")', 'YWI=');
assertRun('window.btoa("abc")', 'YWJj');
assertRun('window.btoa("abcd")', 'YWJjZA==');
assertRun('window.btoa("abcde")', 'YWJjZGU=');
assertRun('window.btoa("abcdef")', 'YWJjZGVm');
assertRun('window.btoa("abcdefg")', 'YWJjZGVmZw==');
assertRun('window.btoa("abcdefgh")', 'YWJjZGVmZ2g=');
assertRun('window.atob("aGVsbG8gd29ybGQ=")', 'hello world');
assertRun('Base64_decode("aGVsbG8gd29ybGQ=")', 'hello world');
assertRun('window.atob("YQ==")', 'a');
assertRun('Base64_decode("YQ==")', 'a');
assertRun('window.atob("YWI=")', 'ab');
assertRun('Base64_decode("YWI=")', 'ab');
assertRun('window.atob("YWJj")', 'abc');
assertRun('Base64_decode("YWJj")', 'abc');
assertRun('window.atob("YWJjZA==")', 'abcd');
assertRun('Base64_decode("YWJjZA==")', 'abcd');
assertRun('window.atob("YWJjZGU=")', 'abcde');
assertRun('Base64_decode("YWJjZGU=")', 'abcde');
assertRun('window.atob("YWJjZGVm")', 'abcdef');
assertRun('Base64_decode("YWJjZGVm")', 'abcdef');
assertRun('typeof window.btoa', 'function');
assertRun('window.btoa("")', '');
assertRun('window.btoa(null)', '');
assertRun('window.atob(window.btoa(window))', window.toString()); // "[object DOMWindow]"
assertRun('window.btoa("\\u0080\\u0081")', 'gIE=');
debug("Tests failed: " + fail);
debug("Tests passed: " + pass);
}
</script>
-12
View File
@@ -1,12 +0,0 @@
// The following results in 'hello [MANGLED]'
//
// Filed as https://github.com/ry/node/issues/issue/402
var sys = require("sys"),
buf = new Buffer(1024), len,
str1 = "aGVsbG8g", // 'hello '
str2 = "d29ybGQ=", // 'world'
len = buf.write(str1, 0, 'base64');
len += buf.write(str2, len, 'base64');
sys.log("decoded result: " + buf.toString('binary', 0, len));
-134
View File
@@ -1,134 +0,0 @@
/*
* From:
* http://www.quirksmode.org/js/detect.html
*/
var Browser = {
init: function () {
this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
this.version = this.searchVersion(navigator.userAgent)
|| this.searchVersion(navigator.appVersion)
|| "an unknown version";
this.majorVersion = this.searchMajorVersion(navigator.userAgent)
|| this.searchMajorVersion(navigator.appVersion)
|| "an unknown version";
this.fullVersion = this.searchFullVersion(navigator.userAgent)
|| this.searchFullVersion(navigator.appVersion)
|| "an unknown version";
this.OS = this.searchString(this.dataOS) || "an unknown OS";
},
searchString: function (data) {
for (var i=0;i<data.length;i++) {
var dataString = data[i].string;
var dataProp = data[i].prop;
this.versionSearchString = data[i].versionSearch || data[i].identity;
if (dataString) {
if (dataString.indexOf(data[i].subString) != -1)
return data[i].identity;
}
else if (dataProp)
return data[i].identity;
}
},
searchFullVersion: function (dataString) {
var index = dataString.indexOf(this.versionSearchString);
if (index == -1) return;
return dataString.substring(index+this.versionSearchString.length+1);
},
searchVersion: function (dataString) {
return this.searchFullVersion(dataString).split(" ")[0];
},
searchMajorVersion: function (dataString) {
return parseFloat(this.searchFullVersion(dataString).split(".")[0]);
},
dataBrowser: [
{
string: navigator.userAgent,
subString: "Chrome",
identity: "Chrome"
},
{ string: navigator.userAgent,
subString: "OmniWeb",
versionSearch: "OmniWeb/",
identity: "OmniWeb"
},
{
string: navigator.vendor,
subString: "Apple",
identity: "Safari",
versionSearch: "Version"
},
{
prop: window.opera,
identity: "Opera",
versionSearch: "Version"
},
{
string: navigator.vendor,
subString: "iCab",
identity: "iCab"
},
{
string: navigator.vendor,
subString: "KDE",
identity: "Konqueror"
},
{
string: navigator.userAgent,
subString: "Firefox",
identity: "Firefox"
},
{
string: navigator.vendor,
subString: "Camino",
identity: "Camino"
},
{ // for newer Netscapes (6+)
string: navigator.userAgent,
subString: "Netscape",
identity: "Netscape"
},
{
string: navigator.userAgent,
subString: "MSIE",
identity: "Explorer",
versionSearch: "MSIE"
},
{
string: navigator.userAgent,
subString: "Gecko",
identity: "Mozilla",
versionSearch: "rv"
},
{ // for older Netscapes (4-)
string: navigator.userAgent,
subString: "Mozilla",
identity: "Netscape",
versionSearch: "Mozilla"
}
],
dataOS : [
{
string: navigator.platform,
subString: "Win",
identity: "Windows"
},
{
string: navigator.platform,
subString: "Mac",
identity: "Mac"
},
{
string: navigator.userAgent,
subString: "iPhone",
identity: "iPhone/iPod"
},
{
string: navigator.platform,
subString: "Linux",
identity: "Linux"
}
]
};
Browser.init();
-148
View File
@@ -1,148 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Canvas Performance Test</title>
<!--
<script type='text/javascript'
src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
-->
<script src="../include/util.js"></script>
<script src="../include/webutil.js"></script>
<script src="../include/base64.js"></script>
<script src="../include/display.js"></script>
<script src="face.png.js"></script>
</head>
<body>
Iterations: <input id='iterations' style='width:50' value="100">&nbsp;
Width: <input id='width' style='width:50' value="640">&nbsp;
Height: <input id='height' style='width:50' value="480">&nbsp;
<input id='startButton' type='button' value='Do Performance Test'
style='width:150px' onclick="begin();">&nbsp;
<br><br>
<b>Canvas</b> (should see three squares and two happy faces):<br>
<canvas id="canvas" width="200" height="100"
style="border-style: dotted; border-width: 1px;">
Canvas not supported.
</canvas>
<br>
Results:<br>
<textarea id="messages" style="font-size: 9;" cols=80 rows=25></textarea>
</body>
<script>
var msg_cnt = 0;
var display, start_width = 300, start_height = 100;
var iterations;
function message(str) {
console.log(str);
cell = $D('messages');
cell.innerHTML += msg_cnt + ": " + str + "\n";
cell.scrollTop = cell.scrollHeight;
msg_cnt += 1;
}
function test_functions () {
var img, x, y, w, h, ctx = display.get_context();
w = display.get_width();
h = display.get_height();
display.fillRect(0, 0, w, h, [240,240,240]);
display.blitStringImage("data:image/png;base64," + face64, 150, 10);
var himg = new Image();
himg.onload = function () {
ctx.drawImage(himg, 200, 40); };
himg.src = "face.png";
/* Test array image data */
data = [];
for (y=0; y< 50; y++) {
for (x=0; x< 50; x++) {
data[(y*50 + x)*4 + 0] = 255 - parseInt((255 / 50) * y, 10);
data[(y*50 + x)*4 + 1] = parseInt((255 / 50) * y, 10);
data[(y*50 + x)*4 + 2] = parseInt((255 / 50) * x, 10);
data[(y*50 + x)*4 + 3] = 255;
}
}
display.blitImage(30, 10, 50, 50, data, 0);
img = display.getTile(5,5,16,16,[0,128,128]);
display.putTile(img);
img = display.getTile(90,15,16,16,[0,0,0]);
display.setSubTile(img, 0,0,16,16,[128,128,0]);
display.putTile(img);
}
function begin () {
$D('startButton').value = "Running";
$D('startButton').disabled = true;
setTimeout(start_delayed, 250);
iterations = $D('iterations').value;
}
function start_delayed () {
var ret;
ret = display.set_prefer_js(true);
if (ret) {
message("Running test: prefer Javascript ops");
var time1 = run_test();
message("prefer Javascript ops: " + time1 + "ms total, " +
(time1 / iterations) + "ms per frame");
} else {
message("Could not run: prefer Javascript ops");
}
display.set_prefer_js(false);
message("Running test: prefer Canvas ops");
var time2 = run_test();
message("prefer Canvas ops: " + time2 + "ms total, " +
(time2 / iterations) + "ms per frame");
if (Util.get_logging() !== 'debug') {
display.resize(start_width, start_height, true);
test_functions();
}
$D('startButton').disabled = false;
$D('startButton').value = "Do Performance Test";
}
function run_test () {
var width, height;
width = $D('width').value;
height = $D('height').value;
display.resize(width, height);
var color, start_time = (new Date()).getTime(), w, h;
for (var i=0; i < iterations; i++) {
color = [128, 128, (255 / iterations) * i, 0];
for (var x=0; x < width; x = x + 16) {
for (var y=0; y < height; y = y + 16) {
w = Math.min(16, width - x);
h = Math.min(16, height - y);
var tile = display.getTile(x, y, w, h, color);
display.setSubTile(tile, 0, 0, w, h, color);
display.putTile(tile);
}
}
}
var end_time = (new Date()).getTime();
return (end_time - start_time);
}
window.onload = function() {
message("in onload");
$D('iterations').value = 10;
display = new Display({'target' : $D('canvas')});
display.resize(start_width, start_height, true);
message("Canvas initialized");
test_functions();
}
</script>
</html>
-135
View File
@@ -1,135 +0,0 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Cursor Change test</title>
<meta charset="UTF-8">
<!--
<script type='text/javascript'
src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
-->
<script src="../include/util.js"></script>
<script src="../include/webutil.js"></script>
<script src="../include/base64.js"></script>
<script src="../include/canvas.js"></script>
</head>
<body>
<h1>Roll over the buttons to test cursors</h1>
<br>
<input id=button1 type="button" value="Cursor from file (smiley face)">
<input id=button2 type="button" value="Data URI cursor (crosshair)">
<br>
<br>
<br>
Debug:<br>
<textarea id="debug" style="font-size: 9px;" cols=80 rows=25></textarea>
<br>
<br>
<canvas id="testcanvas" width="100px" height="20px">
Canvas not supported.
</canvas>
</body>
<script>
function debug(str) {
console.log(str);
cell = $D('debug');
cell.innerHTML += str + "\n";
cell.scrollTop = cell.scrollHeight;
}
function makeCursor() {
var arr = [], x, y, w = 32, h = 32, hx = 16, hy = 16;
var IHDRsz = 40;
var ANDsz = w * h * 4;
var XORsz = Math.ceil( (w * h) / 8.0 );
// Push multi-byte little-endian values
arr.push16le = function (num) {
this.push((num ) & 0xFF,
(num >> 8) & 0xFF );
};
arr.push32le = function (num) {
this.push((num ) & 0xFF,
(num >> 8) & 0xFF,
(num >> 16) & 0xFF,
(num >> 24) & 0xFF );
};
// Main header
arr.push16le(0); // Reserved
arr.push16le(2); // .CUR type
arr.push16le(1); // Number of images, 1 for non-animated arr
// Cursor #1
arr.push(w); // width
arr.push(h); // height
arr.push(0); // colors, 0 -> true-color
arr.push(0); // reserved
arr.push16le(hx); // hotspot x coordinate
arr.push16le(hy); // hotspot y coordinate
arr.push32le(IHDRsz + XORsz + ANDsz); // cursor data byte size
arr.push32le(22); // offset of cursor data in the file
// Infoheader for Cursor #1
arr.push32le(IHDRsz); // Infoheader size
arr.push32le(w); // Cursor width
arr.push32le(h*2); // XOR+AND height
arr.push16le(1); // number of planes
arr.push16le(32); // bits per pixel
arr.push32le(0); // type of compression
arr.push32le(XORsz + ANDsz); // Size of Image
arr.push32le(0);
arr.push32le(0);
arr.push32le(0);
arr.push32le(0);
// XOR/color data
for (y = h-1; y >= 0; y--) {
for (x = 0; x < w; x++) {
//if ((x === hx) || (y === (h-hy-1))) {
if ((x === hx) || (y === hy)) {
arr.push(0xe0); // blue
arr.push(0x00); // green
arr.push(0x00); // red
arr.push(0xff); // alpha
} else {
arr.push(0x05); // blue
arr.push(0xe6); // green
arr.push(0x00); // red
arr.push(0x80); // alpha
}
}
}
// AND/bitmask data (seems to be ignored)
for (y = 0; y < h; y++) {
for (x = 0; x < Math.ceil(w / 8); x++) {
arr.push(0x00);
}
}
debug("cursor generated");
return arr;
}
window.onload = function() {
debug("onload");
var canvas, cross, cursor, cursor64;
canvas = new Canvas({'target' : $D("testcanvas")});
debug("canvas indicates Data URI cursor support is: " + canvas.get_cursor_uri());
$D('button1').style.cursor="url(face.png), default";
cursor = makeCursor();
cursor64 = Base64.encode(cursor);
//debug("cursor: " + cursor.slice(0,100) + " (" + cursor.length + ")");
//debug("cursor64: " + cursor64.slice(0,100) + " (" + cursor64.length + ")");
$D('button2').style.cursor="url(data:image/x-icon;base64," + cursor64 + "), default";
debug("onload complete");
}
</script>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

-1
View File
@@ -1 +0,0 @@
var face64 = 'iVBORw0KGgoAAAANSUhEUgAAACMAAAAjCAIAAACRuyQOAAAAA3NCSVQICAjb4U/gAAAAGXRFWHRTb2Z0d2FyZQBnbm9tZS1zY3JlZW5zaG907wO/PgAACJJJREFUSIm1lltsXMUdxr8558zZq9d3OxebJDYhJLhNIAmUWyFKIBUtVaGqSgtUlIJKeahoEahgIZU+VC0oQiVVC60obckDgVIp3KRCQkmhhIhA4oY4wjg2ufmS9drec/bc5vbvw9prJwq85dP/YWfP7Pfb/8w3s8v6339l2fkrbMvGuZQ2mkUTA0bpc4qpyjrX3dTkAATQ5z0WUrqcAwjL/eXirmBqj0yKSTTBwNxMM0+15JuurG/dlClcOH/yWcVEaVBKUR3Eidizr2946Nhr/9q5b//BsudZzDLG5DK4sDt3443XrFm34bkX9x4ZPimkWNBa/+MfrB84+O7rbxz4+JPQD8liljY6n8t9uWfld2/++vp1F3ct6cikU2eSnvr7P7e99OqC9vaTJ0ccMtl8loyJ4igKwzAIK0GglersWv7sM08VCrk4joY/O/rLXz3mTYzmcnnXdZXWcRzHURwEQRCEHUuXdS/vnp4qP/CT2zdvuAKAQwCB4kRse+m1LY//Wojkscd/57opKUQUJ8wyzFaOq7OGGGPcdZ/f/sKbu3YT0YZrr3JT7pq1l3qeH4SBqgRETBljDKXSqXyh/i9PP/W/Q31btz59zVXrUpxb1dYsixUK+c7Fi59/YUdz2yInnbXcLHfTtpu23ZRlu4ZZiRBTp8Z37HjlhW1/evnFZ9/a+VZdLsecFOMpx83ydJanc24q67iuFOr48NC1G6+fKBY7zutIElFNBAC4nN99602XXLzutjvvETqAlcqktVQin0QiLsRxEAUBaRVUfBh1QfcigmzIuw0NTe2LOjNlL07iOArDwA88z0unGWNTk5P1dfkf3XH3BT2r9b23zZKIAHxr81f/uGpF/8G+Fau+VPbKp8ZHpqdKSRiEYWiMMVopJSuVyl+f3UpIQKL34btvvf2BxuZWN5Umo7TWFiNDDHCampob6utLpRKz7Hvv+E5jfR5ELCkNShFXOytOTH7vjrsOfXJ0wcLFF63sXr1mfXtbS6FQB4BZyGYzX7l0TWtrvWVpUGxUMFEa2bv3Q9+bNCaECX2/NFEc3bd/4r19/tR0uLC98c+/3/LVy9fWzhNq56m1pfEPvabnut2OI8EvBMAYAxhgAWz3u3tuvuWeRx/56aYNa0Hy3fc/euiRZx596IZvbF5Dpgw9CdMI0waqaMrEScPgvtdWXH5JzdzC7NElIPQH3GyTk+4ABCgCEpAkMgRGcLb/49WGxqYtTzwNaJDa/tJ7DU1tW558GaYCEwESYGAWwEidTOcWM8tElcGauTP/ivDGd7V3fxv6JGCBIpBDjIMxgIM5B/YfjMJwfGwEMIA40DcQhcn46DGAzX7p6gIwBhj5WUvH8vLYG+nu8+d6qimY2lPXup70GFEEE9baAhRIj5w8cfz4MSESkJw3FLOfnrvSCETqs3xTd2Vyd+1Na/4MmRRt3gBTgfGJKkQhTAQTwgQgv2tpR8X3Vq5YCiiC7lrSXPG9lRe0AmZ2hQxo5jXpspNqEElxPmlOIi5ZThYUgBKYKRgPxgMFMAGM/+D9P2xuLPQ+dBcoAYkHf/bN5sZM74M3gHS1acBUi0gZ4zk8J5NyzdzBGSIJkoANCqsrwgBAg+zN1605Mfw6IIkiUHL9xouODzwBE4ACkKrGBNBkBEgSKSIz39gxRkuRVAduulHLCZtZoARkzybTAFU2m7GjBBSDkmoRJYCc3U5lSBgjAFeJae4Wauan9WSnWlU0aqdtUAXElAicVDNIgfHZaJkZU0pAESgmCJAACUCApJIBKCITg+VVMuWm2+btEwFE1coVLvOKe2HVE8UwUd/OXi0nQZXZ8kH+7HIFoIgoqvKqzWkV9L2zy5jQ6Ig5nX5pOFd/Vc3cmv9zW9eyYfzITmY1giKiMJNtCiYPw1RgPBh/psiHqcAEZAJQBFMlxaDEnyqmc3mjY2NCiy+bHB3Kt2w8I+UzxTPLlAzjygCz6kFBx6qNg/ue84p9M7AZRoWoQhSAqumfacsrnRg6uH9Rd4/RFWafl1RGjLJ5ZknNnIXjh+PQB0BEQkqv9L4sb1t59cMU74GVKxcnhg5sdzN1jQtX5grtqVyj46ZtywIJrUOZeCKYCLxTU+PHkzhZ2vO1XH5MRIfcwvcHP9qRafp5XfN6l3PGGIA5ktJaJEJINXnkvmWrNza0rSBxEFYbnE6veGRq9IPQO54Ep5QItRYAs22Hu1k315QtdDYsuCzf1KHDt0XlbTu3ySuVRo6MNnc/6XLHTbmObc+QotAHIJUSQiSJTKLR4Nh9Pdc+kM44JA+D5RhfBud8ZjeD5WHVMVYHqwAYmGkyUyRPqPDfMnhTxcNW+jKpGj/94NX8eVtTmYWpFHddlzsOABaOzZGkkImQUsrI/1iVfrPq6vszuSyJD0EasGEVmN0KlgXLgYGMT6qkkwEthrQuG53Y2U0icT79YIfb2pup6+Gcp1zOXV4j9VdJxhghpJBSSCmEjL0+XXqsa+0tTYvWQ/aTHJrZW9JEkowwJjYmMjo0OmR8uZ1eNz12+Nih/zgtv0gXVrsur1Jcl1uWNUsK/GoQldZSSCGllEpIGYcndOm36Vyqa/VNmboFRh4ldZR02ZhpMhJwCGnmLGZ8SewXj/bvTkLDW3pT2UUu55w7Lufc5dVNAsCCsf4o8Gqpr8KkUlIqpZRUKim/Y/y/pVLZ1s5V+Zbl3C3Ybp5Iq2RKxhP+xFBxZFAmwi7cmaq/kjuO4zicO9xx5mPOQqrGvYZRWmulldYqGlLBf3X8EfQkSR8A43WMN1nuWid3hZPpcmzbdmzHtmuwarjnkw5FldNIczyljDZKa62NNpoM1QSA1WQx27Jt23Js27It7pzJmLthz/7/nzHOOThcImPoNBIIAMNpJMtiNcBZDZ3PfVIjgtkWsy3riyZ9AaFGMlozhuqCnDsxxv4PC7uS+QV5eeoAAAAASUVORK5CYII=';
+2 -7
View File
@@ -51,14 +51,9 @@ var FakeWebSocket;
},
_get_sent_data: function () {
var arr = [];
for (var i = 0; i < this.bufferedAmount; i++) {
arr[i] = this._send_queue[i];
}
var res = new Uint8Array(this._send_queue.buffer, 0, this.bufferedAmount);
this.bufferedAmount = 0;
return arr;
return res;
},
_open: function (data) {
+26 -25
View File
@@ -20,17 +20,18 @@
</body>
<!--
<script type='text/javascript'
<script type='text/javascript'
src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
-->
<script src="../include/util.js"></script>
<script src="../include/webutil.js"></script>
<script src="../include/base64.js"></script>
<script src="../include/keysym.js"></script>
<script src="../include/keysymdef.js"></script>
<script src="../include/keyboard.js"></script>
<script src="../include/input.js"></script>
<script src="../include/display.js"></script>
<script src="../core/util.js"></script>
<script src="../app/webutil.js"></script>
<script src="../core/base64.js"></script>
<script src="../core/input/keysym.js"></script>
<script src="../core/input/keysymdef.js"></script>
<script src="../core/input/xtscancodes.js"></script>
<script src="../core/input/util.js"></script>
<script src="../core/input/devices.js"></script>
<script src="../core/display.js"></script>
<script>
var msg_cnt = 0, iterations,
width = 400, height = 200,
@@ -43,8 +44,8 @@
function message(str) {
console.log(str);
cell = $D('messages');
cell.innerHTML += msg_cnt + ": " + str + newline;
cell = document.getElementById('messages');
cell.textContent += msg_cnt + ": " + str + newline;
cell.scrollTop = cell.scrollHeight;
msg_cnt++;
}
@@ -93,23 +94,23 @@
for (b = 0; b < blist.length; b++) {
if (blist[b] === num) {
$D('button' + blist[b]).style.backgroundColor = "black";
$D('button' + blist[b]).style.color = "lightgray";
document.getElementById('button' + blist[b]).style.backgroundColor = "black";
document.getElementById('button' + blist[b]).style.color = "lightgray";
} else {
$D('button' + blist[b]).style.backgroundColor = "";
$D('button' + blist[b]).style.color = "";
document.getElementById('button' + blist[b]).style.backgroundColor = "";
document.getElementById('button' + blist[b]).style.color = "";
}
}
}
window.onload = function() {
canvas = new Display({'target' : $D('canvas')});
canvas = new Display({'target' : document.getElementById('canvas')});
keyboard = new Keyboard({'target': document,
'onKeyPress': rfbKeyPress});
Util.addEvent(document, 'keypress', rawKey);
Util.addEvent(document, 'keydown', rawKey);
Util.addEvent(document, 'keyup', rawKey);
mouse = new Mouse({'target': $D('canvas'),
document.addEventListener('keypress', rawKey);
document.addEventListener('keydown', rawKey);
document.addEventListener('keyup', rawKey);
mouse = new Mouse({'target': document.getElementById('canvas'),
'onMouseButton': mouseButton,
'onMouseMove': mouseMove});
@@ -118,12 +119,12 @@
mouse.grab();
message("Display initialized");
if ('ontouchstart' in document.documentElement) {
if (Util.isTouchDevice) {
message("Touch device detected");
$D('button-selection').style.display = "inline";
$D('button1').onclick = function(){ selectButton(1) };
$D('button2').onclick = function(){ selectButton(2) };
$D('button4').onclick = function(){ selectButton(4) };
document.getElementById('button-selection').style.display = "inline";
document.getElementById('button1').onclick = function(){ selectButton(1) };
document.getElementById('button2').onclick = function(){ selectButton(2) };
document.getElementById('button4').onclick = function(){ selectButton(4) };
selectButton();
}
-29
View File
@@ -1,29 +0,0 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Mocha Tests</title>
<link rel="stylesheet" href="node_modules/mocha/mocha.css" />
</head>
<body>
<!--
To run tests
cd .../noVNC/tests
npm install chai mocha
open keyboard-tests.html in a browser
-->
<div id="mocha"></div>
<script src="node_modules/chai/chai.js"></script>
<script src="node_modules/mocha/mocha.js"></script>
<script>mocha.setup('bdd')</script>
<script src="../include/keysymdef.js"></script>
<script src="../include/keyboard.js"></script>
<script src="test.keyboard.js"></script>
<script src="test.helper.js"></script>
<script>
mocha.checkLeaks();
mocha.globals(['navigator']);
mocha.run();
</script>
</body>
</html>
+198
View File
@@ -0,0 +1,198 @@
/*
* noVNC: HTML5 VNC client
* Copyright (C) 2012 Joel Martin
* Licensed under MPL 2.0 (see LICENSE.txt)
*/
"use strict";
/*jslint browser: true, white: false */
/*global Util, VNC_frame_data, finish */
var rfb, mode, test_state, frame_idx, frame_length,
iteration, iterations, istart_time, encoding,
// Pre-declarations for jslint
send_array, next_iteration, end_iteration, queue_next_packet,
do_packet, enable_test_mode;
// Override send_array
send_array = function (arr) {
// Stub out send_array
};
// Immediate polyfill
if (window.setImmediate === undefined) {
var _immediateIdCounter = 1;
var _immediateFuncs = {};
window.setImmediate = function (func) {
var index = Util._immediateIdCounter++;
_immediateFuncs[index] = func;
window.postMessage("noVNC immediate trigger:" + index, "*");
return index;
};
window.clearImmediate = function (id) {
_immediateFuncs[id];
};
var _onMessage = function (event) {
if ((typeof event.data !== "string") ||
(event.data.indexOf("noVNC immediate trigger:") !== 0)) {
return;
}
var index = event.data.slice("noVNC immediate trigger:".length);
var callback = _immediateFuncs[index];
if (callback === undefined) {
return;
}
delete _immediateFuncs[index];
callback();
};
window.addEventListener("message", _onMessage);
}
enable_test_mode = function () {
rfb._sock.send = send_array;
rfb._sock.close = function () {};
rfb._sock.flush = function () {};
rfb._checkEvents = function () {};
rfb.connect = function (host, port, password, path) {
this._rfb_host = host;
this._rfb_port = port;
this._rfb_password = (password !== undefined) ? password : "";
this._rfb_path = (path !== undefined) ? path : "";
this._sock.init('binary', 'ws');
this._rfb_connection_state = 'connecting';
this._rfb_init_state = 'ProtocolVersion';
};
};
next_iteration = function () {
rfb = new RFB({'target': document.getElementById('VNC_canvas'),
'view_only': true,
'onDisconnected': disconnected,
'onNotification': notification});
enable_test_mode();
// Missing in older recordings
if (typeof VNC_frame_encoding === 'undefined') {
var frame = VNC_frame_data[0];
var start = frame.indexOf('{', 1) + 1;
if (frame.slice(start).startsWith('UkZC')) {
encoding = 'base64';
} else {
encoding = 'binary';
}
} else {
encoding = VNC_frame_encoding;
}
if (iteration === 0) {
frame_length = VNC_frame_data.length;
test_state = 'running';
}
if (test_state !== 'running') { return; }
iteration += 1;
if (iteration > iterations) {
finish();
return;
}
frame_idx = 0;
istart_time = (new Date()).getTime();
rfb.connect('test', 0, "bogus");
queue_next_packet();
};
end_iteration = function () {
if (rfb._display.pending()) {
rfb._display.set_onFlush(function () {
if (rfb._flushing) {
rfb._onFlush();
}
end_iteration();
});
rfb._display.flush();
} else {
next_iteration();
}
};
queue_next_packet = function () {
var frame, foffset, toffset, delay;
if (test_state !== 'running') { return; }
frame = VNC_frame_data[frame_idx];
while ((frame_idx < frame_length) && (frame.charAt(0) === "}")) {
//Util.Debug("Send frame " + frame_idx);
frame_idx += 1;
frame = VNC_frame_data[frame_idx];
}
if (frame === 'EOF') {
Util.Debug("Finished, found EOF");
end_iteration();
return;
}
if (frame_idx >= frame_length) {
Util.Debug("Finished, no more frames");
end_iteration();
return;
}
if (mode === 'realtime') {
foffset = frame.slice(1, frame.indexOf('{', 1));
toffset = (new Date()).getTime() - istart_time;
delay = foffset - toffset;
if (delay < 1) {
delay = 1;
}
setTimeout(do_packet, delay);
} else {
window.setImmediate(do_packet);
}
};
var bytes_processed = 0;
do_packet = function () {
// Avoid having an excessive queue buildup
if (rfb._flushing && (mode !== 'realtime')) {
rfb._display.set_onFlush(function () {
rfb._display.set_onFlush(rfb._onFlush.bind(rfb));
rfb._onFlush();
do_packet();
});
return;
}
//Util.Debug("Processing frame: " + frame_idx);
var frame = VNC_frame_data[frame_idx],
start = frame.indexOf('{', 1) + 1;
var u8;
if (encoding === 'base64') {
u8 = Base64.decode(frame.slice(start));
start = 0;
} else {
u8 = new Uint8Array(frame.length - start);
for (var i = 0; i < frame.length - start; i++) {
u8[i] = frame.charCodeAt(start + i);
}
}
bytes_processed += u8.length;
rfb._sock._recv_message({'data' : u8});
frame_idx += 1;
queue_next_packet();
};
+14 -2
View File
@@ -1,7 +1,7 @@
var Spooky = require('spooky');
var path = require('path');
var phantom_path = require('phantomjs').path;
var phantom_path = require('phantomjs-prebuilt').path;
var casper_path = path.resolve(__dirname, '../node_modules/casperjs/bin/casperjs');
process.env.PHANTOMJS_EXECUTABLE = phantom_path;
var casper_opts = {
@@ -15,7 +15,19 @@ var casper_opts = {
}
};
var provide_emitter = function(file_paths) {
var provide_emitter = function(file_paths, debug_port) {
if (debug_port) {
casper_opts.child['remote-debugger-port'] = debug_port;
var debug_url = ('https://localhost:' + debug_port +
'/webkit/inspector/inspector.html?page=');
console.info('[remote-debugger] Navigate to ' + debug_url + '1 and ' +
'run `__run();` in the console to continue loading.' +
'\n[remote-debugger] Navigate to ' + debug_url + '2 to ' +
'view the actual page source.\n' +
'[remote-debugger] Use the `debugger;` statement to ' +
'trigger an initial breakpoint.');
}
var spooky = new Spooky(casper_opts, function(err) {
if (err) {
if (err.stack) console.warn(err.stack);
+23 -5
View File
@@ -20,6 +20,7 @@ program
.option('--output-html', 'Instead of running the tests, just output the generated HTML source to STDOUT (should be used with .js tests)')
.option('-d, --debug', 'Show debug output (the "console" event) from the provider')
.option('-r, --relative', 'Use relative paths in the generated HTML file')
.option('--debugger <port>', 'Enable the remote debugger for CasperJS')
.parse(process.argv);
if (program.tests.length === 0) {
@@ -66,7 +67,7 @@ if (all_js && !program.autoInject) {
var eol = content.indexOf('\n', ind);
var modules = content.slice(ind, eol).split(/,\s*/);
modules.forEach(function (mod) {
all_modules[get_path('include/', mod) + '.js'] = 1;
all_modules[get_path('core/', mod) + '.js'] = 1;
});
}
@@ -91,14 +92,13 @@ if (program.autoInject) {
var template = {
header: "<html>\n<head>\n<meta charset='utf-8' />\n<link rel='stylesheet' href='" + get_path('node_modules/mocha/mocha.css') + "'/>\n</head>\n<body><div id='mocha'></div>",
script_tag: function(p) { return "<script src='" + p + "'></script>"; },
footer: "<script>\nmocha.checkLeaks();\nmocha.globals(['navigator', 'create', 'ClientUtils', '__utils__']);\nmocha.run(function () { window.__mocha_done = true; });\n</script>\n</body>\n</html>"
footer: "<script>\nmocha.checkLeaks();\nmocha.globals(['navigator', 'create', 'ClientUtils', '__utils__', 'requestAnimationFrame', 'WebSocket']);\nmocha.run(function () { window.__mocha_done = true; });\n</script>\n</body>\n</html>"
};
template.header += "\n" + template.script_tag(get_path('node_modules/chai/chai.js'));
template.header += "\n" + template.script_tag(get_path('node_modules/mocha/mocha.js'));
template.header += "\n" + template.script_tag(get_path('node_modules/sinon/pkg/sinon.js'));
template.header += "\n" + template.script_tag(get_path('node_modules/sinon-chai/lib/sinon-chai.js'));
template.header += "\n" + template.script_tag(get_path('node_modules/sinon-chai/lib/sinon-chai.js'));
template.header += "\n<script>mocha.setup('bdd');</script>";
@@ -202,7 +202,7 @@ if (!program.outputHtml && !program.generateHtml) {
.write("\n");
//console.log("Running tests %s using provider %s", program.tests.join(', '), prov.name);
var provider = prov.provide_emitter(file_paths);
var provider = prov.provide_emitter(file_paths, program.debugger);
provider.on('test_ready', function(test_json) {
console.log('');
@@ -249,6 +249,24 @@ if (!program.outputHtml && !program.generateHtml) {
console.log('');
if (test_json.num_fails > 0 || program.printAll) {
var extract_error_lines = function (err) {
// the split is to avoid a weird thing where in PhantomJS where we get a stack trace too
var err_lines = err.split('\n');
if (err_lines.length == 1) {
return err_lines[0];
} else {
var ind;
for (ind = 0; ind < err_lines.length; ind++) {
var at_ind = err_lines[ind].trim().indexOf('at ');
if (at_ind === 0) {
break;
}
}
return err_lines.slice(0, ind).join('\n');
}
};
var traverse_tree = function(indentation, node) {
if (node.type == 'suite') {
if (!node.has_subfailures && !program.printAll) return;
@@ -280,7 +298,7 @@ if (!program.outputHtml && !program.generateHtml) {
cursor.magenta();
console.log('- failed: '+node.text+test_json.replay);
cursor.red();
console.log(' '+node.error.split("\n")[0]); // the split is to avoid a weird thing where in PhantomJS where we get a stack trace too
console.log(' '+extract_error_lines(node.error));
cursor.reset();
console.log('');
}
-53
View File
@@ -1,53 +0,0 @@
/*
* Define some useful statistical functions on arrays of numbers
*/
Array.prototype.sum = function() {
var i, sum = 0;
for (i = 0; i < this.length; i++) {
sum += this[i];
}
return sum;
}
Array.prototype.max = function() {
return Math.max.apply(null, this);
}
Array.prototype.min = function() {
return Math.min.apply(null, this);
}
Array.prototype.mean = function() {
return this.sum() / this.length;
}
Array.prototype.average = Array.prototype.mean;
Array.prototype.median = function() {
var sorted = this.sort( function(a,b) { return a-b; }),
len = sorted.length;
if (len % 2) {
return sorted[Math.floor(len / 2)]; // Odd
} else {
return (sorted[len/2 - 1] + sorted[len/2]) / 2; // Even
}
}
Array.prototype.stdDev = function(sample) {
var i, sumSqr = 0, mean = this.mean(), N;
if (sample) {
// Population correction if this is a sample
N = this.length - 1;
} else {
// Standard deviation of just the array
N = this.length;
}
for (i = 0; i < this.length; i++) {
sumSqr += Math.pow(this[i] - mean, 2);
}
return Math.sqrt(sumSqr / N);
}
+193 -118
View File
@@ -26,6 +26,13 @@ describe('Display/Canvas Helper', function () {
return canvas;
}
function make_image_png (input_data) {
var canvas = make_image_canvas(input_data);
var url = canvas.toDataURL();
var data = url.split(",")[1];
return Base64.decode(data);
}
describe('checking for cursor uri support', function () {
beforeEach(function () {
this._old_browser_supports_cursor_uris = Util.browserSupportsCursorURIs;
@@ -61,14 +68,13 @@ describe('Display/Canvas Helper', function () {
display.resize(5, 5);
display.viewportChangeSize(3, 3);
display.viewportChangePos(1, 1);
display.getCleanDirtyReset();
});
it('should take viewport location into consideration when drawing images', function () {
display.set_width(4);
display.set_height(4);
display.resize(4, 4);
display.viewportChangeSize(2, 2);
display.drawImage(make_image_canvas(basic_data), 1, 1);
display.flip();
var expected = new Uint8Array(16);
var i;
@@ -77,96 +83,82 @@ describe('Display/Canvas Helper', function () {
expect(display).to.have.displayed(expected);
});
it('should redraw the left side when shifted left', function () {
display.viewportChangePos(-1, 0);
var cdr = display.getCleanDirtyReset();
expect(cdr.cleanBox).to.deep.equal({ x: 1, y: 1, w: 2, h: 3 });
expect(cdr.dirtyBoxes).to.have.length(1);
expect(cdr.dirtyBoxes[0]).to.deep.equal({ x: 0, y: 1, w: 2, h: 3 });
it('should resize the target canvas when resizing the viewport', function() {
display.viewportChangeSize(2, 2);
expect(display._target.width).to.equal(2);
expect(display._target.height).to.equal(2);
});
it('should redraw the right side when shifted right', function () {
display.viewportChangePos(1, 0);
var cdr = display.getCleanDirtyReset();
expect(cdr.cleanBox).to.deep.equal({ x: 2, y: 1, w: 2, h: 3 });
expect(cdr.dirtyBoxes).to.have.length(1);
expect(cdr.dirtyBoxes[0]).to.deep.equal({ x: 4, y: 1, w: 1, h: 3 });
it('should move the viewport if necessary', function() {
display.viewportChangeSize(5, 5);
expect(display.absX(0)).to.equal(0);
expect(display.absY(0)).to.equal(0);
expect(display._target.width).to.equal(5);
expect(display._target.height).to.equal(5);
});
it('should redraw the top part when shifted up', function () {
display.viewportChangePos(0, -1);
var cdr = display.getCleanDirtyReset();
expect(cdr.cleanBox).to.deep.equal({ x: 1, y: 1, w: 3, h: 2 });
expect(cdr.dirtyBoxes).to.have.length(1);
expect(cdr.dirtyBoxes[0]).to.deep.equal({ x: 1, y: 0, w: 3, h: 1 });
it('should limit the viewport to the framebuffer size', function() {
display.viewportChangeSize(6, 6);
expect(display._target.width).to.equal(5);
expect(display._target.height).to.equal(5);
});
it('should redraw the bottom part when shifted down', function () {
display.viewportChangePos(0, 1);
var cdr = display.getCleanDirtyReset();
expect(cdr.cleanBox).to.deep.equal({ x: 1, y: 2, w: 3, h: 2 });
expect(cdr.dirtyBoxes).to.have.length(1);
expect(cdr.dirtyBoxes[0]).to.deep.equal({ x: 1, y: 4, w: 3, h: 1 });
it('should redraw when moving the viewport', function () {
display.flip = sinon.spy();
display.viewportChangePos(-1, 1);
expect(display.flip).to.have.been.calledOnce;
});
it('should reset the entire viewport to being clean after calculating the clean/dirty boxes', function () {
display.viewportChangePos(0, 1);
var cdr1 = display.getCleanDirtyReset();
var cdr2 = display.getCleanDirtyReset();
expect(cdr1).to.not.deep.equal(cdr2);
expect(cdr2.cleanBox).to.deep.equal({ x: 1, y: 2, w: 3, h: 3 });
expect(cdr2.dirtyBoxes).to.be.empty;
it('should redraw when resizing the viewport', function () {
display.flip = sinon.spy();
display.viewportChangeSize(2, 2);
expect(display.flip).to.have.been.calledOnce;
});
it('should simply mark the whole display area as dirty if not using viewports', function () {
display = new Display({ target: document.createElement('canvas'), prefer_js: false, viewport: false });
display.resize(5, 5);
var cdr = display.getCleanDirtyReset();
expect(cdr.cleanBox).to.deep.equal({ x: 0, y: 0, w: 0, h: 0 });
expect(cdr.dirtyBoxes).to.have.length(1);
expect(cdr.dirtyBoxes[0]).to.deep.equal({ x: 0, y: 0, w: 5, h: 5 });
});
});
describe('clipping', function () {
var display;
beforeEach(function () {
display = new Display({ target: document.createElement('canvas'), prefer_js: false, viewport: true });
display.resize(4, 3);
});
it('should report true when no max-size and framebuffer > viewport', function () {
display.viewportChangeSize(2,2);
it('should report clipping when framebuffer > viewport', function () {
var clipping = display.clippingDisplay();
expect(clipping).to.be.true;
});
it('should report false when no max-size and framebuffer = viewport', function () {
it('should report not clipping when framebuffer = viewport', function () {
display.viewportChangeSize(5, 5);
var clipping = display.clippingDisplay();
expect(clipping).to.be.false;
});
it('should report true when viewport > max-size and framebuffer > viewport', function () {
display.viewportChangeSize(2,2);
display.set_maxWidth(1);
display.set_maxHeight(2);
var clipping = display.clippingDisplay();
expect(clipping).to.be.true;
it('should show the entire framebuffer when disabling the viewport', function() {
display.set_viewport(false);
expect(display.absX(0)).to.equal(0);
expect(display.absY(0)).to.equal(0);
expect(display._target.width).to.equal(5);
expect(display._target.height).to.equal(5);
});
it('should report true when viewport > max-size and framebuffer = viewport', function () {
display.set_maxWidth(1);
display.set_maxHeight(2);
var clipping = display.clippingDisplay();
expect(clipping).to.be.true;
it('should ignore viewport changes when the viewport is disabled', function() {
display.set_viewport(false);
display.viewportChangeSize(2, 2);
display.viewportChangePos(1, 1);
expect(display.absX(0)).to.equal(0);
expect(display.absY(0)).to.equal(0);
expect(display._target.width).to.equal(5);
expect(display._target.height).to.equal(5);
});
it('should show the entire framebuffer just after enabling the viewport', function() {
display.set_viewport(false);
display.set_viewport(true);
expect(display.absX(0)).to.equal(0);
expect(display.absY(0)).to.equal(0);
expect(display._target.width).to.equal(5);
expect(display._target.height).to.equal(5);
});
});
describe('resizing', function () {
var display;
beforeEach(function () {
display = new Display({ target: document.createElement('canvas'), prefer_js: false, viewport: true });
display.resize(4, 3);
display = new Display({ target: document.createElement('canvas'), prefer_js: false, viewport: false });
display.resize(4, 4);
});
it('should change the size of the logical canvas', function () {
@@ -175,10 +167,49 @@ describe('Display/Canvas Helper', function () {
expect(display._fb_height).to.equal(7);
});
it('should update the viewport dimensions', function () {
sinon.spy(display, 'viewportChangeSize');
it('should keep the framebuffer data', function () {
display.fillRect(0, 0, 4, 4, [0, 0, 0xff]);
display.resize(2, 2);
expect(display.viewportChangeSize).to.have.been.calledOnce;
display.flip();
var expected = [];
for (var i = 0; i < 4 * 2*2; i += 4) {
expected[i] = 0xff;
expected[i+1] = expected[i+2] = 0;
expected[i+3] = 0xff;
}
expect(display).to.have.displayed(new Uint8Array(expected));
});
describe('viewport', function () {
beforeEach(function () {
display.set_viewport(true);
display.viewportChangeSize(3, 3);
display.viewportChangePos(1, 1);
});
it('should keep the viewport position and size if possible', function () {
display.resize(6, 6);
expect(display.absX(0)).to.equal(1);
expect(display.absY(0)).to.equal(1);
expect(display._target.width).to.equal(3);
expect(display._target.height).to.equal(3);
});
it('should move the viewport if necessary', function () {
display.resize(3, 3);
expect(display.absX(0)).to.equal(0);
expect(display.absY(0)).to.equal(0);
expect(display._target.width).to.equal(3);
expect(display._target.height).to.equal(3);
});
it('should shrink the viewport if necessary', function () {
display.resize(2, 2);
expect(display.absX(0)).to.equal(0);
expect(display.absY(0)).to.equal(0);
expect(display._target.width).to.equal(2);
expect(display._target.height).to.equal(2);
});
});
});
@@ -188,7 +219,9 @@ describe('Display/Canvas Helper', function () {
beforeEach(function () {
display = new Display({ target: document.createElement('canvas'), prefer_js: false, viewport: true });
display.resize(4, 3);
display.resize(4, 4);
display.viewportChangeSize(3, 3);
display.viewportChangePos(1, 1);
canvas = display.get_target();
document.body.appendChild(canvas);
});
@@ -198,15 +231,25 @@ describe('Display/Canvas Helper', function () {
});
it('should not change the bitmap size of the canvas', function () {
display.set_scale(0.5);
expect(canvas.width).to.equal(4);
display.set_scale(2.0);
expect(canvas.width).to.equal(3);
expect(canvas.height).to.equal(3);
});
it('should change the effective rendered size of the canvas', function () {
display.set_scale(0.5);
expect(canvas.clientWidth).to.equal(2);
expect(canvas.clientHeight).to.equal(2);
display.set_scale(2.0);
expect(canvas.clientWidth).to.equal(6);
expect(canvas.clientHeight).to.equal(6);
});
it('should not change when resizing', function () {
display.set_scale(2.0);
display.resize(5, 5);
expect(display.get_scale()).to.equal(2.0);
expect(canvas.width).to.equal(3);
expect(canvas.height).to.equal(3);
expect(canvas.clientWidth).to.equal(6);
expect(canvas.clientHeight).to.equal(6);
});
});
@@ -231,13 +274,17 @@ describe('Display/Canvas Helper', function () {
});
it('should use width to determine scale when the current aspect ratio is wider than the target', function () {
expect(display.autoscale(9, 16)).to.equal(9 / 4);
display.autoscale(9, 16);
expect(display.absX(9)).to.equal(4);
expect(display.absY(18)).to.equal(8);
expect(canvas.clientWidth).to.equal(9);
expect(canvas.clientHeight).to.equal(7); // round 9 / (4 / 3)
});
it('should use height to determine scale when the current aspect ratio is taller than the target', function () {
expect(display.autoscale(16, 9)).to.equal(3); // 9 / 3
display.autoscale(16, 9);
expect(display.absX(9)).to.equal(3);
expect(display.absY(18)).to.equal(6);
expect(canvas.clientWidth).to.equal(12); // 16 * (4 / 3)
expect(canvas.clientHeight).to.equal(9);
@@ -250,11 +297,15 @@ describe('Display/Canvas Helper', function () {
});
it('should not upscale when downscaleOnly is true', function () {
expect(display.autoscale(2, 2, true)).to.equal(0.5);
display.autoscale(2, 2, true);
expect(display.absX(9)).to.equal(18);
expect(display.absY(18)).to.equal(36);
expect(canvas.clientWidth).to.equal(2);
expect(canvas.clientHeight).to.equal(2);
expect(display.autoscale(16, 9, true)).to.equal(1.0);
display.autoscale(16, 9, true);
expect(display.absX(9)).to.equal(9);
expect(display.absY(18)).to.equal(18);
expect(canvas.clientWidth).to.equal(4);
expect(canvas.clientHeight).to.equal(3);
});
@@ -282,22 +333,35 @@ describe('Display/Canvas Helper', function () {
});
it('should draw the logo on #clear with a logo set', function (done) {
display._logo = { width: 4, height: 4, data: make_image_canvas(checked_data).toDataURL() };
display._drawCtx._act_drawImg = display._drawCtx.drawImage;
display._drawCtx.drawImage = function (img, x, y) {
this._act_drawImg(img, x, y);
expect(display).to.have.displayed(checked_data);
done();
};
display._logo = { width: 4, height: 4, type: "image/png", data: make_image_png(checked_data) };
display.clear();
expect(display._fb_width).to.equal(4);
expect(display._fb_height).to.equal(4);
display.set_onFlush(function () {
expect(display).to.have.displayed(checked_data);
expect(display._fb_width).to.equal(4);
expect(display._fb_height).to.equal(4);
done();
});
display.flush();
});
it('should not draw directly on the target canvas', function () {
display.fillRect(0, 0, 4, 4, [0, 0, 0xff]);
display.flip();
display.fillRect(0, 0, 4, 4, [0, 0xff, 0]);
var expected = [];
for (var i = 0; i < 4 * display._fb_width * display._fb_height; i += 4) {
expected[i] = 0xff;
expected[i+1] = expected[i+2] = 0;
expected[i+3] = 0xff;
}
expect(display).to.have.displayed(new Uint8Array(expected));
});
it('should support filling a rectangle with particular color via #fillRect', function () {
display.fillRect(0, 0, 4, 4, [0, 0xff, 0]);
display.fillRect(0, 0, 2, 2, [0xff, 0, 0]);
display.fillRect(2, 2, 2, 2, [0xff, 0, 0]);
display.flip();
expect(display).to.have.displayed(checked_data);
});
@@ -305,14 +369,26 @@ describe('Display/Canvas Helper', function () {
display.fillRect(0, 0, 4, 4, [0, 0xff, 0]);
display.fillRect(0, 0, 2, 2, [0xff, 0, 0x00]);
display.copyImage(0, 0, 2, 2, 2, 2);
display.flip();
expect(display).to.have.displayed(checked_data);
});
it('should support drawing images via #imageRect', function (done) {
display.imageRect(0, 0, "image/png", make_image_png(checked_data));
display.flip();
display.set_onFlush(function () {
expect(display).to.have.displayed(checked_data);
done();
});
display.flush();
});
it('should support drawing tile data with a background color and sub tiles', function () {
display.startTile(0, 0, 4, 4, [0, 0xff, 0]);
display.subTile(0, 0, 2, 2, [0xff, 0, 0]);
display.subTile(2, 2, 2, 2, [0xff, 0, 0]);
display.finishTile();
display.flip();
expect(display).to.have.displayed(checked_data);
});
@@ -325,6 +401,7 @@ describe('Display/Canvas Helper', function () {
data[i * 4 + 3] = checked_data[i * 4 + 3];
}
display.blitImage(0, 0, 4, 4, data, 0);
display.flip();
expect(display).to.have.displayed(checked_data);
});
@@ -336,26 +413,17 @@ describe('Display/Canvas Helper', function () {
data[i * 3 + 2] = checked_data[i * 4 + 2];
}
display.blitRgbImage(0, 0, 4, 4, data, 0);
display.flip();
expect(display).to.have.displayed(checked_data);
});
it('should support drawing blit images from a data URL via #blitStringImage', function (done) {
var img_url = make_image_canvas(checked_data).toDataURL();
display._drawCtx._act_drawImg = display._drawCtx.drawImage;
display._drawCtx.drawImage = function (img, x, y) {
this._act_drawImg(img, x, y);
expect(display).to.have.displayed(checked_data);
done();
};
display.blitStringImage(img_url, 0, 0);
});
it('should support drawing solid colors with color maps', function () {
display._true_color = false;
display.set_colourMap({ 0: [0xff, 0, 0], 1: [0, 0xff, 0] });
display.fillRect(0, 0, 4, 4, [1]);
display.fillRect(0, 0, 2, 2, [0]);
display.fillRect(2, 2, 2, 2, [0]);
display.fillRect(0, 0, 4, 4, 1);
display.fillRect(0, 0, 2, 2, 0);
display.fillRect(2, 2, 2, 2, 0);
display.flip();
expect(display).to.have.displayed(checked_data);
});
@@ -364,12 +432,14 @@ describe('Display/Canvas Helper', function () {
display.set_colourMap({ 1: [0xff, 0, 0], 0: [0, 0xff, 0] });
var data = [1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1].map(function (elem) { return [elem]; });
display.blitImage(0, 0, 4, 4, data, 0);
display.flip();
expect(display).to.have.displayed(checked_data);
});
it('should support drawing an image object via #drawImage', function () {
var img = make_image_canvas(checked_data);
display.drawImage(img, 0, 0);
display.flip();
expect(display).to.have.displayed(checked_data);
});
}
@@ -384,30 +454,25 @@ describe('Display/Canvas Helper', function () {
display = new Display({ target: document.createElement('canvas'), prefer_js: false });
display.resize(4, 4);
sinon.spy(display, '_scan_renderQ');
this.old_requestAnimFrame = window.requestAnimFrame;
window.requestAnimFrame = function (cb) {
this.next_frame_cb = cb;
}.bind(this);
this.next_frame = function () { this.next_frame_cb(); };
});
afterEach(function () {
window.requestAnimFrame = this.old_requestAnimFrame;
window.requestAnimationFrame = this.old_requestAnimationFrame;
});
it('should try to process an item when it is pushed on, if nothing else is on the queue', function () {
display.renderQ_push({ type: 'noop' }); // does nothing
display._renderQ_push({ type: 'noop' }); // does nothing
expect(display._scan_renderQ).to.have.been.calledOnce;
});
it('should not try to process an item when it is pushed on if we are waiting for other items', function () {
display._renderQ.length = 2;
display.renderQ_push({ type: 'noop' });
display._renderQ_push({ type: 'noop' });
expect(display._scan_renderQ).to.not.have.been.called;
});
it('should wait until an image is loaded to attempt to draw it and the rest of the queue', function () {
var img = { complete: false };
var img = { complete: false, addEventListener: sinon.spy() }
display._renderQ = [{ type: 'img', x: 3, y: 4, img: img },
{ type: 'fill', x: 1, y: 2, width: 3, height: 4, color: 5 }];
display.drawImage = sinon.spy();
@@ -416,44 +481,54 @@ describe('Display/Canvas Helper', function () {
display._scan_renderQ();
expect(display.drawImage).to.not.have.been.called;
expect(display.fillRect).to.not.have.been.called;
expect(img.addEventListener).to.have.been.calledOnce;
display._renderQ[0].img.complete = true;
this.next_frame();
display._scan_renderQ();
expect(display.drawImage).to.have.been.calledOnce;
expect(display.fillRect).to.have.been.calledOnce;
expect(img.addEventListener).to.have.been.calledOnce;
});
it('should call callback when queue is flushed', function () {
display.set_onFlush(sinon.spy());
display.fillRect(0, 0, 4, 4, [0, 0xff, 0]);
expect(display.get_onFlush()).to.not.have.been.called;
display.flush();
expect(display.get_onFlush()).to.have.been.calledOnce;
});
it('should draw a blit image on type "blit"', function () {
display.blitImage = sinon.spy();
display.renderQ_push({ type: 'blit', x: 3, y: 4, width: 5, height: 6, data: [7, 8, 9] });
display._renderQ_push({ type: 'blit', x: 3, y: 4, width: 5, height: 6, data: [7, 8, 9] });
expect(display.blitImage).to.have.been.calledOnce;
expect(display.blitImage).to.have.been.calledWith(3, 4, 5, 6, [7, 8, 9], 0);
});
it('should draw a blit RGB image on type "blitRgb"', function () {
display.blitRgbImage = sinon.spy();
display.renderQ_push({ type: 'blitRgb', x: 3, y: 4, width: 5, height: 6, data: [7, 8, 9] });
display._renderQ_push({ type: 'blitRgb', x: 3, y: 4, width: 5, height: 6, data: [7, 8, 9] });
expect(display.blitRgbImage).to.have.been.calledOnce;
expect(display.blitRgbImage).to.have.been.calledWith(3, 4, 5, 6, [7, 8, 9], 0);
});
it('should copy a region on type "copy"', function () {
display.copyImage = sinon.spy();
display.renderQ_push({ type: 'copy', x: 3, y: 4, width: 5, height: 6, old_x: 7, old_y: 8 });
display._renderQ_push({ type: 'copy', x: 3, y: 4, width: 5, height: 6, old_x: 7, old_y: 8 });
expect(display.copyImage).to.have.been.calledOnce;
expect(display.copyImage).to.have.been.calledWith(7, 8, 3, 4, 5, 6);
});
it('should fill a rect with a given color on type "fill"', function () {
display.fillRect = sinon.spy();
display.renderQ_push({ type: 'fill', x: 3, y: 4, width: 5, height: 6, color: [7, 8, 9]});
display._renderQ_push({ type: 'fill', x: 3, y: 4, width: 5, height: 6, color: [7, 8, 9]});
expect(display.fillRect).to.have.been.calledOnce;
expect(display.fillRect).to.have.been.calledWith(3, 4, 5, 6, [7, 8, 9]);
});
it('should draw an image from an image object on type "img" (if complete)', function () {
display.drawImage = sinon.spy();
display.renderQ_push({ type: 'img', x: 3, y: 4, img: { complete: true } });
display._renderQ_push({ type: 'img', x: 3, y: 4, img: { complete: true } });
expect(display.drawImage).to.have.been.calledOnce;
expect(display.drawImage).to.have.been.calledWith({ complete: true }, 3, 4);
});
+56 -52
View File
@@ -1,4 +1,4 @@
// requires local modules: keysym, keysymdef, keyboard
// requires local modules: input/keysym, input/keysymdef, input/util
var assert = chai.assert;
var expect = chai.expect;
@@ -7,18 +7,18 @@ describe('Helpers', function() {
"use strict";
describe('keysymFromKeyCode', function() {
it('should map known keycodes to keysyms', function() {
expect(kbdUtil.keysymFromKeyCode(0x41, false), 'a').to.be.equal(0x61);
expect(kbdUtil.keysymFromKeyCode(0x41, true), 'A').to.be.equal(0x41);
expect(kbdUtil.keysymFromKeyCode(0xd, false), 'enter').to.be.equal(0xFF0D);
expect(kbdUtil.keysymFromKeyCode(0x11, false), 'ctrl').to.be.equal(0xFFE3);
expect(kbdUtil.keysymFromKeyCode(0x12, false), 'alt').to.be.equal(0xFFE9);
expect(kbdUtil.keysymFromKeyCode(0xe1, false), 'altgr').to.be.equal(0xFE03);
expect(kbdUtil.keysymFromKeyCode(0x1b, false), 'esc').to.be.equal(0xFF1B);
expect(kbdUtil.keysymFromKeyCode(0x26, false), 'up').to.be.equal(0xFF52);
expect(KeyboardUtil.keysymFromKeyCode(0x41, false), 'a').to.be.equal(0x61);
expect(KeyboardUtil.keysymFromKeyCode(0x41, true), 'A').to.be.equal(0x41);
expect(KeyboardUtil.keysymFromKeyCode(0xd, false), 'enter').to.be.equal(0xFF0D);
expect(KeyboardUtil.keysymFromKeyCode(0x11, false), 'ctrl').to.be.equal(0xFFE3);
expect(KeyboardUtil.keysymFromKeyCode(0x12, false), 'alt').to.be.equal(0xFFE9);
expect(KeyboardUtil.keysymFromKeyCode(0xe1, false), 'altgr').to.be.equal(0xFE03);
expect(KeyboardUtil.keysymFromKeyCode(0x1b, false), 'esc').to.be.equal(0xFF1B);
expect(KeyboardUtil.keysymFromKeyCode(0x26, false), 'up').to.be.equal(0xFF52);
});
it('should return null for unknown keycodes', function() {
expect(kbdUtil.keysymFromKeyCode(0xc0, false), 'DK æ').to.be.null;
expect(kbdUtil.keysymFromKeyCode(0xde, false), 'DK ø').to.be.null;
expect(KeyboardUtil.keysymFromKeyCode(0xc0, false), 'DK æ').to.be.null;
expect(KeyboardUtil.keysymFromKeyCode(0xde, false), 'DK ø').to.be.null;
});
});
@@ -38,67 +38,71 @@ describe('Helpers', function() {
it('should map characters which aren\'t in Latin1 *or* Windows-1252 to keysyms', function() {
expect(keysyms.fromUnicode('ŵ'.charCodeAt())).to.have.property('keysym', 0x1000175);
});
it('should return undefined for unknown codepoints', function() {
expect(keysyms.fromUnicode('\n'.charCodeAt())).to.be.undefined;
expect(keysyms.fromUnicode('\u1F686'.charCodeAt())).to.be.undefined;
it('should map unknown codepoints to the Unicode range', function() {
expect(keysyms.fromUnicode('\n'.charCodeAt())).to.have.property('keysym', 0x100000a);
expect(keysyms.fromUnicode('\u262D'.charCodeAt())).to.have.property('keysym', 0x100262d);
});
// This requires very recent versions of most browsers... skipping for now
it.skip('should map UCS-4 codepoints to the Unicode range', function() {
//expect(keysyms.fromUnicode('\u{1F686}'.codePointAt())).to.have.property('keysym', 0x101f686);
});
});
describe('substituteCodepoint', function() {
it('should replace characters which don\'t have a keysym', function() {
expect(kbdUtil.substituteCodepoint('Ș'.charCodeAt())).to.equal('Ş'.charCodeAt());
expect(kbdUtil.substituteCodepoint('ș'.charCodeAt())).to.equal('ş'.charCodeAt());
expect(kbdUtil.substituteCodepoint('Ț'.charCodeAt())).to.equal('Ţ'.charCodeAt());
expect(kbdUtil.substituteCodepoint('ț'.charCodeAt())).to.equal('ţ'.charCodeAt());
expect(KeyboardUtil.substituteCodepoint('Ș'.charCodeAt())).to.equal('Ş'.charCodeAt());
expect(KeyboardUtil.substituteCodepoint('ș'.charCodeAt())).to.equal('ş'.charCodeAt());
expect(KeyboardUtil.substituteCodepoint('Ț'.charCodeAt())).to.equal('Ţ'.charCodeAt());
expect(KeyboardUtil.substituteCodepoint('ț'.charCodeAt())).to.equal('ţ'.charCodeAt());
});
it('should pass other characters through unchanged', function() {
expect(kbdUtil.substituteCodepoint('T'.charCodeAt())).to.equal('T'.charCodeAt());
expect(KeyboardUtil.substituteCodepoint('T'.charCodeAt())).to.equal('T'.charCodeAt());
});
});
describe('nonCharacterKey', function() {
it('should recognize the right keys', function() {
expect(kbdUtil.nonCharacterKey({keyCode: 0xd}), 'enter').to.be.defined;
expect(kbdUtil.nonCharacterKey({keyCode: 0x08}), 'backspace').to.be.defined;
expect(kbdUtil.nonCharacterKey({keyCode: 0x09}), 'tab').to.be.defined;
expect(kbdUtil.nonCharacterKey({keyCode: 0x10}), 'shift').to.be.defined;
expect(kbdUtil.nonCharacterKey({keyCode: 0x11}), 'ctrl').to.be.defined;
expect(kbdUtil.nonCharacterKey({keyCode: 0x12}), 'alt').to.be.defined;
expect(kbdUtil.nonCharacterKey({keyCode: 0xe0}), 'meta').to.be.defined;
expect(KeyboardUtil.nonCharacterKey({keyCode: 0xd}), 'enter').to.be.defined;
expect(KeyboardUtil.nonCharacterKey({keyCode: 0x08}), 'backspace').to.be.defined;
expect(KeyboardUtil.nonCharacterKey({keyCode: 0x09}), 'tab').to.be.defined;
expect(KeyboardUtil.nonCharacterKey({keyCode: 0x10}), 'shift').to.be.defined;
expect(KeyboardUtil.nonCharacterKey({keyCode: 0x11}), 'ctrl').to.be.defined;
expect(KeyboardUtil.nonCharacterKey({keyCode: 0x12}), 'alt').to.be.defined;
expect(KeyboardUtil.nonCharacterKey({keyCode: 0xe0}), 'meta').to.be.defined;
});
it('should not recognize character keys', function() {
expect(kbdUtil.nonCharacterKey({keyCode: 'A'}), 'A').to.be.null;
expect(kbdUtil.nonCharacterKey({keyCode: '1'}), '1').to.be.null;
expect(kbdUtil.nonCharacterKey({keyCode: '.'}), '.').to.be.null;
expect(kbdUtil.nonCharacterKey({keyCode: ' '}), 'space').to.be.null;
expect(KeyboardUtil.nonCharacterKey({keyCode: 'A'}), 'A').to.be.null;
expect(KeyboardUtil.nonCharacterKey({keyCode: '1'}), '1').to.be.null;
expect(KeyboardUtil.nonCharacterKey({keyCode: '.'}), '.').to.be.null;
expect(KeyboardUtil.nonCharacterKey({keyCode: ' '}), 'space').to.be.null;
});
});
describe('getKeysym', function() {
it('should prefer char', function() {
expect(kbdUtil.getKeysym({char : 'a', charCode: 'Š'.charCodeAt(), keyCode: 0x42, which: 0x43})).to.have.property('keysym', 0x61);
expect(KeyboardUtil.getKeysym({char : 'a', charCode: 'Š'.charCodeAt(), keyCode: 0x42, which: 0x43})).to.have.property('keysym', 0x61);
});
it('should use charCode if no char', function() {
expect(kbdUtil.getKeysym({char : '', charCode: 'Š'.charCodeAt(), keyCode: 0x42, which: 0x43})).to.have.property('keysym', 0x01a9);
expect(kbdUtil.getKeysym({charCode: 'Š'.charCodeAt(), keyCode: 0x42, which: 0x43})).to.have.property('keysym', 0x01a9);
expect(kbdUtil.getKeysym({char : 'hello', charCode: 'Š'.charCodeAt(), keyCode: 0x42, which: 0x43})).to.have.property('keysym', 0x01a9);
expect(KeyboardUtil.getKeysym({char : '', charCode: 'Š'.charCodeAt(), keyCode: 0x42, which: 0x43})).to.have.property('keysym', 0x01a9);
expect(KeyboardUtil.getKeysym({charCode: 'Š'.charCodeAt(), keyCode: 0x42, which: 0x43})).to.have.property('keysym', 0x01a9);
expect(KeyboardUtil.getKeysym({char : 'hello', charCode: 'Š'.charCodeAt(), keyCode: 0x42, which: 0x43})).to.have.property('keysym', 0x01a9);
});
it('should use keyCode if no charCode', function() {
expect(kbdUtil.getKeysym({keyCode: 0x42, which: 0x43, shiftKey: false})).to.have.property('keysym', 0x62);
expect(kbdUtil.getKeysym({keyCode: 0x42, which: 0x43, shiftKey: true})).to.have.property('keysym', 0x42);
expect(KeyboardUtil.getKeysym({keyCode: 0x42, which: 0x43, shiftKey: false})).to.have.property('keysym', 0x62);
expect(KeyboardUtil.getKeysym({keyCode: 0x42, which: 0x43, shiftKey: true})).to.have.property('keysym', 0x42);
});
it('should use which if no keyCode', function() {
expect(kbdUtil.getKeysym({which: 0x43, shiftKey: false})).to.have.property('keysym', 0x63);
expect(kbdUtil.getKeysym({which: 0x43, shiftKey: true})).to.have.property('keysym', 0x43);
expect(KeyboardUtil.getKeysym({which: 0x43, shiftKey: false})).to.have.property('keysym', 0x63);
expect(KeyboardUtil.getKeysym({which: 0x43, shiftKey: true})).to.have.property('keysym', 0x43);
});
it('should substitute where applicable', function() {
expect(kbdUtil.getKeysym({char : 'Ș'})).to.have.property('keysym', 0x1aa);
expect(KeyboardUtil.getKeysym({char : 'Ș'})).to.have.property('keysym', 0x1aa);
});
});
describe('Modifier Sync', function() { // return a list of fake events necessary to fix modifier state
describe('Toggle all modifiers', function() {
var sync = kbdUtil.ModifierSync();
var sync = KeyboardUtil.ModifierSync();
it ('should do nothing if all modifiers are up as expected', function() {
expect(sync.keydown({
keyCode: 0x41,
@@ -141,7 +145,7 @@ describe('Helpers', function() {
});
});
describe('Toggle Ctrl', function() {
var sync = kbdUtil.ModifierSync();
var sync = KeyboardUtil.ModifierSync();
it('should sync if modifier is suddenly down', function() {
expect(sync.keydown({
keyCode: 0x41,
@@ -156,7 +160,7 @@ describe('Helpers', function() {
});
});
describe('Toggle Alt', function() {
var sync = kbdUtil.ModifierSync();
var sync = KeyboardUtil.ModifierSync();
it('should sync if modifier is suddenly down', function() {
expect(sync.keydown({
keyCode: 0x41,
@@ -171,7 +175,7 @@ describe('Helpers', function() {
});
});
describe('Toggle AltGr', function() {
var sync = kbdUtil.ModifierSync();
var sync = KeyboardUtil.ModifierSync();
it('should sync if modifier is suddenly down', function() {
expect(sync.keydown({
keyCode: 0x41,
@@ -186,7 +190,7 @@ describe('Helpers', function() {
});
});
describe('Toggle Shift', function() {
var sync = kbdUtil.ModifierSync();
var sync = KeyboardUtil.ModifierSync();
it('should sync if modifier is suddenly down', function() {
expect(sync.keydown({
keyCode: 0x41,
@@ -201,7 +205,7 @@ describe('Helpers', function() {
});
});
describe('Toggle Meta', function() {
var sync = kbdUtil.ModifierSync();
var sync = KeyboardUtil.ModifierSync();
it('should sync if modifier is suddenly down', function() {
expect(sync.keydown({
keyCode: 0x41,
@@ -217,17 +221,17 @@ describe('Helpers', function() {
});
describe('Modifier keyevents', function() {
it('should not sync a modifier on its own events', function() {
expect(kbdUtil.ModifierSync().keydown({
expect(KeyboardUtil.ModifierSync().keydown({
keyCode: 0x11,
ctrlKey: false
})).to.be.deep.equal([]);
expect(kbdUtil.ModifierSync().keydown({
expect(KeyboardUtil.ModifierSync().keydown({
keyCode: 0x11,
ctrlKey: true
}), 'B').to.be.deep.equal([]);
})
it('should update state on modifier keyevents', function() {
var sync = kbdUtil.ModifierSync();
var sync = KeyboardUtil.ModifierSync();
sync.keydown({
keyCode: 0x11,
});
@@ -237,7 +241,7 @@ describe('Helpers', function() {
})).to.be.deep.equal([]);
});
it('should sync other modifiers on ctrl events', function() {
expect(kbdUtil.ModifierSync().keydown({
expect(KeyboardUtil.ModifierSync().keydown({
keyCode: 0x11,
altKey: true
})).to.be.deep.equal([{keysym: keysyms.lookup(0xffe9), type: 'keydown'}]);
@@ -245,17 +249,17 @@ describe('Helpers', function() {
});
describe('sync modifiers on non-key events', function() {
it('should generate sync events when receiving non-keyboard events', function() {
expect(kbdUtil.ModifierSync().syncAny({
expect(KeyboardUtil.ModifierSync().syncAny({
altKey: true
})).to.be.deep.equal([{keysym: keysyms.lookup(0xffe9), type: 'keydown'}]);
});
});
describe('do not treat shift as a modifier key', function() {
it('should not treat shift as a shortcut modifier', function() {
expect(kbdUtil.hasShortcutModifier([], {0xffe1 : true})).to.be.false;
expect(KeyboardUtil.hasShortcutModifier([], {0xffe1 : true})).to.be.false;
});
it('should not treat shift as a char modifier', function() {
expect(kbdUtil.hasCharModifier([], {0xffe1 : true})).to.be.false;
expect(KeyboardUtil.hasCharModifier([], {0xffe1 : true})).to.be.false;
});
});
});
+57 -57
View File
@@ -1,4 +1,4 @@
// requires local modules: input, keyboard, keysymdef
// requires local modules: input/devices, input/util, input/keysymdef, input/keysym
var assert = chai.assert;
var expect = chai.expect;
@@ -7,19 +7,19 @@ describe('Key Event Pipeline Stages', function() {
"use strict";
describe('Decode Keyboard Events', function() {
it('should pass events to the next stage', function(done) {
KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
expect(evt).to.be.an.object;
done();
}).keydown({keyCode: 0x41});
});
it('should pass the right keysym through', function(done) {
KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
expect(evt.keysym).to.be.deep.equal(keysyms.lookup(0x61));
done();
}).keypress({keyCode: 0x41});
});
it('should pass the right keyid through', function(done) {
KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
expect(evt).to.have.property('keyId', 0x41);
done();
}).keydown({keyCode: 0x41});
@@ -27,14 +27,14 @@ describe('Key Event Pipeline Stages', function() {
it('should not sync modifiers on a keypress', function() {
// Firefox provides unreliable modifier state on keypress events
var count = 0;
KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
++count;
}).keypress({keyCode: 0x41, ctrlKey: true});
expect(count).to.be.equal(1);
});
it('should sync modifiers if necessary', function(done) {
var count = 0;
KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
switch (count) {
case 0: // fake a ctrl keydown
expect(evt).to.be.deep.equal({keysym: keysyms.lookup(0xffe3), type: 'keydown'});
@@ -48,26 +48,26 @@ describe('Key Event Pipeline Stages', function() {
}).keydown({keyCode: 0x41, ctrlKey: true});
});
it('should forward keydown events with the right type', function(done) {
KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
expect(evt).to.be.deep.equal({keyId: 0x41, type: 'keydown'});
done();
}).keydown({keyCode: 0x41});
});
it('should forward keyup events with the right type', function(done) {
KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
expect(evt).to.be.deep.equal({keyId: 0x41, keysym: keysyms.lookup(0x61), type: 'keyup'});
done();
}).keyup({keyCode: 0x41});
});
it('should forward keypress events with the right type', function(done) {
KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
expect(evt).to.be.deep.equal({keyId: 0x41, keysym: keysyms.lookup(0x61), type: 'keypress'});
done();
}).keypress({keyCode: 0x41});
});
it('should generate stalls if a char modifier is down while a key is pressed', function(done) {
var count = 0;
KeyEventDecoder(kbdUtil.ModifierSync([0xfe03]), function(evt) {
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync([0xfe03]), function(evt) {
switch (count) {
case 0: // fake altgr
expect(evt).to.be.deep.equal({keysym: keysyms.lookup(0xfe03), type: 'keydown'});
@@ -92,7 +92,7 @@ describe('Key Event Pipeline Stages', function() {
});
describe('suppress the right events at the right time', function() {
it('should suppress anything while a shortcut modifier is down', function() {
var obj = KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {});
var obj = KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {});
obj.keydown({keyCode: 0x11}); // press ctrl
expect(obj.keydown({keyCode: 'A'.charCodeAt()})).to.be.true;
@@ -102,7 +102,7 @@ describe('Key Event Pipeline Stages', function() {
expect(obj.keydown({keyCode: 0xde})).to.be.true; // Ø key on DK
});
it('should suppress non-character keys', function() {
var obj = KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {});
var obj = KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {});
expect(obj.keydown({keyCode: 0x08}), 'a').to.be.true;
expect(obj.keydown({keyCode: 0x09}), 'b').to.be.true;
@@ -110,20 +110,20 @@ describe('Key Event Pipeline Stages', function() {
expect(obj.keydown({keyCode: 0x12}), 'e').to.be.true;
});
it('should not suppress shift', function() {
var obj = KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {});
var obj = KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {});
expect(obj.keydown({keyCode: 0x10}), 'd').to.be.false;
});
it('should generate event for shift keydown', function() {
var called = false;
var obj = KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
var obj = KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
expect(evt).to.have.property('keysym');
called = true;
}).keydown({keyCode: 0x10});
expect(called).to.be.true;
});
it('should not suppress character keys', function() {
var obj = KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {});
var obj = KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {});
expect(obj.keydown({keyCode: 'A'.charCodeAt()})).to.be.false;
expect(obj.keydown({keyCode: ' '.charCodeAt()})).to.be.false;
@@ -132,7 +132,7 @@ describe('Key Event Pipeline Stages', function() {
expect(obj.keydown({keyCode: 0xde})).to.be.false; // Ø key on DK
});
it('should not suppress if a char modifier is down', function() {
var obj = KeyEventDecoder(kbdUtil.ModifierSync([0xfe03]), function(evt) {});
var obj = KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync([0xfe03]), function(evt) {});
obj.keydown({keyCode: 0xe1}); // press altgr
expect(obj.keydown({keyCode: 'A'.charCodeAt()})).to.be.false;
@@ -144,7 +144,7 @@ describe('Key Event Pipeline Stages', function() {
});
describe('Keypress and keyup events', function() {
it('should always suppress event propagation', function() {
var obj = KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {});
var obj = KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {});
expect(obj.keypress({keyCode: 'A'.charCodeAt()})).to.be.true;
expect(obj.keypress({keyCode: 0x3c})).to.be.true; // < key on DK Windows
@@ -155,7 +155,7 @@ describe('Key Event Pipeline Stages', function() {
expect(obj.keyup({keyCode: 0x11})).to.be.true;
});
it('should never generate stalls', function() {
var obj = KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
var obj = KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
expect(evt.type).to.not.be.equal('stall');
});
@@ -171,7 +171,7 @@ describe('Key Event Pipeline Stages', function() {
describe('mark events if a char modifier is down', function() {
it('should not mark modifiers on a keydown event', function() {
var times_called = 0;
var obj = KeyEventDecoder(kbdUtil.ModifierSync([0xfe03]), function(evt) {
var obj = KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync([0xfe03]), function(evt) {
switch (times_called++) {
case 0: //altgr
break;
@@ -187,7 +187,7 @@ describe('Key Event Pipeline Stages', function() {
it('should indicate on events if a single-key char modifier is down', function(done) {
var times_called = 0;
var obj = KeyEventDecoder(kbdUtil.ModifierSync([0xfe03]), function(evt) {
var obj = KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync([0xfe03]), function(evt) {
switch (times_called++) {
case 0: //altgr
break;
@@ -208,7 +208,7 @@ describe('Key Event Pipeline Stages', function() {
});
it('should indicate on events if a multi-key char modifier is down', function(done) {
var times_called = 0;
var obj = KeyEventDecoder(kbdUtil.ModifierSync([0xffe9, 0xffe3]), function(evt) {
var obj = KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync([0xffe9, 0xffe3]), function(evt) {
switch (times_called++) {
case 0: //ctrl
break;
@@ -231,7 +231,7 @@ describe('Key Event Pipeline Stages', function() {
obj.keypress({keyCode: 'A'.charCodeAt()});
});
it('should not consider a char modifier to be down on the modifier key itself', function() {
var obj = KeyEventDecoder(kbdUtil.ModifierSync([0xfe03]), function(evt) {
var obj = KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync([0xfe03]), function(evt) {
expect(evt).to.not.have.property('escape');
});
@@ -241,13 +241,13 @@ describe('Key Event Pipeline Stages', function() {
});
describe('add/remove keysym', function() {
it('should remove keysym from keydown if a char key and no modifier', function() {
KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
expect(evt).to.be.deep.equal({keyId: 0x41, type: 'keydown'});
}).keydown({keyCode: 0x41});
});
it('should not remove keysym from keydown if a shortcut modifier is down', function() {
var times_called = 0;
KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
switch (times_called++) {
case 1:
expect(evt).to.be.deep.equal({keyId: 0x41, keysym: keysyms.lookup(0x61), type: 'keydown'});
@@ -258,7 +258,7 @@ describe('Key Event Pipeline Stages', function() {
});
it('should not remove keysym from keydown if a char modifier is down', function() {
var times_called = 0;
KeyEventDecoder(kbdUtil.ModifierSync([0xfe03]), function(evt) {
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync([0xfe03]), function(evt) {
switch (times_called++) {
case 2:
expect(evt).to.be.deep.equal({keyId: 0x41, keysym: keysyms.lookup(0x61), type: 'keydown'});
@@ -268,21 +268,21 @@ describe('Key Event Pipeline Stages', function() {
expect(times_called).to.be.equal(3);
});
it('should not remove keysym from keydown if key is noncharacter', function() {
KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
expect(evt, 'bacobjpace').to.be.deep.equal({keyId: 0x09, keysym: keysyms.lookup(0xff09), type: 'keydown'});
}).keydown({keyCode: 0x09});
KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
expect(evt, 'ctrl').to.be.deep.equal({keyId: 0x11, keysym: keysyms.lookup(0xffe3), type: 'keydown'});
}).keydown({keyCode: 0x11});
});
it('should never remove keysym from keypress', function() {
KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
expect(evt).to.be.deep.equal({keyId: 0x41, keysym: keysyms.lookup(0x61), type: 'keypress'});
}).keypress({keyCode: 0x41});
});
it('should never remove keysym from keyup', function() {
KeyEventDecoder(kbdUtil.ModifierSync(), function(evt) {
KeyboardUtil.KeyEventDecoder(KeyboardUtil.ModifierSync(), function(evt) {
expect(evt).to.be.deep.equal({keyId: 0x41, keysym: keysyms.lookup(0x61), type: 'keyup'});
}).keyup({keyCode: 0x41});
});
@@ -293,25 +293,25 @@ describe('Key Event Pipeline Stages', function() {
describe('Verify that char modifiers are active', function() {
it('should pass keydown events through if there is no stall', function(done) {
var obj = VerifyCharModifier(function(evt){
var obj = KeyboardUtil.VerifyCharModifier(function(evt){
expect(evt).to.deep.equal({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x41)});
done();
})({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x41)});
});
it('should pass keyup events through if there is no stall', function(done) {
var obj = VerifyCharModifier(function(evt){
var obj = KeyboardUtil.VerifyCharModifier(function(evt){
expect(evt).to.deep.equal({type: 'keyup', keyId: 0x41, keysym: keysyms.lookup(0x41)});
done();
})({type: 'keyup', keyId: 0x41, keysym: keysyms.lookup(0x41)});
});
it('should pass keypress events through if there is no stall', function(done) {
var obj = VerifyCharModifier(function(evt){
var obj = KeyboardUtil.VerifyCharModifier(function(evt){
expect(evt).to.deep.equal({type: 'keypress', keyId: 0x41, keysym: keysyms.lookup(0x41)});
done();
})({type: 'keypress', keyId: 0x41, keysym: keysyms.lookup(0x41)});
});
it('should not pass stall events through', function(done){
var obj = VerifyCharModifier(function(evt){
var obj = KeyboardUtil.VerifyCharModifier(function(evt){
// should only be called once, for the keydown
expect(evt).to.deep.equal({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x41)});
done();
@@ -322,7 +322,7 @@ describe('Key Event Pipeline Stages', function() {
});
it('should merge keydown and keypress events if they come after a stall', function(done) {
var next_called = false;
var obj = VerifyCharModifier(function(evt){
var obj = KeyboardUtil.VerifyCharModifier(function(evt){
// should only be called once, for the keydown
expect(next_called).to.be.false;
next_called = true;
@@ -337,7 +337,7 @@ describe('Key Event Pipeline Stages', function() {
});
it('should preserve modifier attribute when merging if keysyms differ', function(done) {
var next_called = false;
var obj = VerifyCharModifier(function(evt){
var obj = KeyboardUtil.VerifyCharModifier(function(evt){
// should only be called once, for the keydown
expect(next_called).to.be.false;
next_called = true;
@@ -351,7 +351,7 @@ describe('Key Event Pipeline Stages', function() {
expect(next_called).to.be.false;
});
it('should not preserve modifier attribute when merging if keysyms are the same', function() {
var obj = VerifyCharModifier(function(evt){
var obj = KeyboardUtil.VerifyCharModifier(function(evt){
expect(evt).to.not.have.property('escape');
});
@@ -361,7 +361,7 @@ describe('Key Event Pipeline Stages', function() {
});
it('should not merge keydown and keypress events if there is no stall', function(done) {
var times_called = 0;
var obj = VerifyCharModifier(function(evt){
var obj = KeyboardUtil.VerifyCharModifier(function(evt){
switch(times_called) {
case 0:
expect(evt).to.deep.equal({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)});
@@ -380,7 +380,7 @@ describe('Key Event Pipeline Stages', function() {
});
it('should not merge keydown and keypress events if separated by another event', function(done) {
var times_called = 0;
var obj = VerifyCharModifier(function(evt){
var obj = KeyboardUtil.VerifyCharModifier(function(evt){
switch(times_called) {
case 0:
expect(evt,1).to.deep.equal({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)});
@@ -406,7 +406,7 @@ describe('Key Event Pipeline Stages', function() {
describe('Track Key State', function() {
it('should do nothing on keyup events if no keys are down', function() {
var obj = TrackKeyState(function(evt) {
var obj = KeyboardUtil.TrackKeyState(function(evt) {
expect(true).to.be.false;
});
obj({type: 'keyup', keyId: 0x41});
@@ -415,7 +415,7 @@ describe('Key Event Pipeline Stages', function() {
var times_called = 0;
var elem = null;
var keysymsdown = {};
var obj = TrackKeyState(function(evt) {
var obj = KeyboardUtil.TrackKeyState(function(evt) {
++times_called;
if (elem.type == 'keyup') {
expect(evt).to.have.property('keysym');
@@ -443,7 +443,7 @@ describe('Key Event Pipeline Stages', function() {
var times_called = 0;
var elem = null;
var keysymsdown = {};
var obj = TrackKeyState(function(evt) {
var obj = KeyboardUtil.TrackKeyState(function(evt) {
++times_called;
if (elem.type == 'keyup') {
expect(evt).to.have.property('keysym');
@@ -472,7 +472,7 @@ describe('Key Event Pipeline Stages', function() {
var times_called = 0;
var elem = null;
var keysymsdown = {};
var obj = TrackKeyState(function(evt) {
var obj = KeyboardUtil.TrackKeyState(function(evt) {
++times_called;
if (elem.type == 'keyup') {
expect(evt).to.have.property('keysym');
@@ -504,7 +504,7 @@ describe('Key Event Pipeline Stages', function() {
var times_called = 0;
var elem = null;
var keysymsdown = {};
var obj = TrackKeyState(function(evt) {
var obj = KeyboardUtil.TrackKeyState(function(evt) {
++times_called;
if (elem.type == 'keyup') {
expect(evt).to.have.property('keysym');
@@ -540,7 +540,7 @@ describe('Key Event Pipeline Stages', function() {
var times_called = 0;
var elem = null;
var keysymsdown = {};
var obj = TrackKeyState(function(evt) {
var obj = KeyboardUtil.TrackKeyState(function(evt) {
++times_called;
if (elem.type == 'keyup') {
expect(evt).to.have.property('keysym');
@@ -573,7 +573,7 @@ describe('Key Event Pipeline Stages', function() {
var times_called = 0;
var elem = null;
var keysymsdown = {};
var obj = TrackKeyState(function(evt) {
var obj = KeyboardUtil.TrackKeyState(function(evt) {
++times_called;
if (elem.type == 'keyup') {
expect(evt).to.have.property('keysym');
@@ -608,7 +608,7 @@ describe('Key Event Pipeline Stages', function() {
var times_called = 0;
var elem = null;
var keysymsdown = {};
var obj = TrackKeyState(function(evt) {
var obj = KeyboardUtil.TrackKeyState(function(evt) {
++times_called;
if (elem.type == 'keyup') {
expect(evt).to.have.property('keysym');
@@ -644,7 +644,7 @@ describe('Key Event Pipeline Stages', function() {
var times_called = 0;
var elem = null;
var keysymsdown = {};
var obj = TrackKeyState(function(evt) {
var obj = KeyboardUtil.TrackKeyState(function(evt) {
++times_called;
if (elem.type == 'keyup') {
expect(evt).to.have.property('keysym');
@@ -676,7 +676,7 @@ describe('Key Event Pipeline Stages', function() {
});
it('should pop matching key event on keyup', function() {
var times_called = 0;
var obj = TrackKeyState(function(evt) {
var obj = KeyboardUtil.TrackKeyState(function(evt) {
switch (times_called++) {
case 0:
case 1:
@@ -697,7 +697,7 @@ describe('Key Event Pipeline Stages', function() {
});
it('should pop the first zero keyevent on keyup with zero keyId', function() {
var times_called = 0;
var obj = TrackKeyState(function(evt) {
var obj = KeyboardUtil.TrackKeyState(function(evt) {
switch (times_called++) {
case 0:
case 1:
@@ -718,7 +718,7 @@ describe('Key Event Pipeline Stages', function() {
});
it('should pop the last keyevents keysym if no match is found for keyId', function() {
var times_called = 0;
var obj = TrackKeyState(function(evt) {
var obj = KeyboardUtil.TrackKeyState(function(evt) {
switch (times_called++) {
case 0:
case 1:
@@ -740,7 +740,7 @@ describe('Key Event Pipeline Stages', function() {
describe('Firefox sends keypress even when keydown is suppressed', function() {
it('should discard the keypress', function() {
var times_called = 0;
var obj = TrackKeyState(function(evt) {
var obj = KeyboardUtil.TrackKeyState(function(evt) {
expect(times_called).to.be.equal(0);
++times_called;
});
@@ -753,7 +753,7 @@ describe('Key Event Pipeline Stages', function() {
describe('releaseAll', function() {
it('should do nothing if no keys have been pressed', function() {
var times_called = 0;
var obj = TrackKeyState(function(evt) {
var obj = KeyboardUtil.TrackKeyState(function(evt) {
++times_called;
});
obj({type: 'releaseall'});
@@ -761,7 +761,7 @@ describe('Key Event Pipeline Stages', function() {
});
it('should release the keys that have been pressed', function() {
var times_called = 0;
var obj = TrackKeyState(function(evt) {
var obj = KeyboardUtil.TrackKeyState(function(evt) {
switch (times_called++) {
case 2:
expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0, keysym: keysyms.lookup(0x41)});
@@ -787,7 +787,7 @@ describe('Key Event Pipeline Stages', function() {
describe('Keydown', function() {
it('should pass through when a char modifier is not down', function() {
var times_called = 0;
EscapeModifiers(function(evt) {
KeyboardUtil.EscapeModifiers(function(evt) {
expect(times_called).to.be.equal(0);
++times_called;
expect(evt).to.be.deep.equal({type: 'keydown', keyId: 0x41, keysym: keysyms.lookup(0x42)});
@@ -796,7 +796,7 @@ describe('Key Event Pipeline Stages', function() {
});
it('should generate fake undo/redo events when a char modifier is down', function() {
var times_called = 0;
EscapeModifiers(function(evt) {
KeyboardUtil.EscapeModifiers(function(evt) {
switch(times_called++) {
case 0:
expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0, keysym: keysyms.lookup(0xffe9)});
@@ -821,7 +821,7 @@ describe('Key Event Pipeline Stages', function() {
describe('Keyup', function() {
it('should pass through when a char modifier is down', function() {
var times_called = 0;
EscapeModifiers(function(evt) {
KeyboardUtil.EscapeModifiers(function(evt) {
expect(times_called).to.be.equal(0);
++times_called;
expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0x41, keysym: keysyms.lookup(0x42), escape: [0xfe03]});
@@ -830,7 +830,7 @@ describe('Key Event Pipeline Stages', function() {
});
it('should pass through when a char modifier is not down', function() {
var times_called = 0;
EscapeModifiers(function(evt) {
KeyboardUtil.EscapeModifiers(function(evt) {
expect(times_called).to.be.equal(0);
++times_called;
expect(evt).to.be.deep.equal({type: 'keyup', keyId: 0x41, keysym: keysyms.lookup(0x42)});
+625 -404
View File
File diff suppressed because it is too large Load Diff
+77 -48
View File
@@ -7,61 +7,21 @@ var expect = chai.expect;
describe('Utils', function() {
"use strict";
describe('Array instance methods', function () {
describe('push8', function () {
it('should push a byte on to the array', function () {
var arr = [1];
arr.push8(128);
expect(arr).to.deep.equal([1, 128]);
});
it('should only use the least significant byte of any number passed in', function () {
var arr = [1];
arr.push8(0xABCD);
expect(arr).to.deep.equal([1, 0xCD]);
});
});
describe('push16', function () {
it('should push two bytes on to the array', function () {
var arr = [1];
arr.push16(0xABCD);
expect(arr).to.deep.equal([1, 0xAB, 0xCD]);
});
it('should only use the two least significant bytes of any number passed in', function () {
var arr = [1];
arr.push16(0xABCDEF);
expect(arr).to.deep.equal([1, 0xCD, 0xEF]);
});
});
describe('push32', function () {
it('should push four bytes on to the array', function () {
var arr = [1];
arr.push32(0xABCDEF12);
expect(arr).to.deep.equal([1, 0xAB, 0xCD, 0xEF, 0x12]);
});
it('should only use the four least significant bytes of any number passed in', function () {
var arr = [1];
arr.push32(0xABCDEF1234);
expect(arr).to.deep.equal([1, 0xCD, 0xEF, 0x12, 0x34]);
});
});
});
describe('logging functions', function () {
beforeEach(function () {
sinon.spy(console, 'log');
sinon.spy(console, 'debug');
sinon.spy(console, 'warn');
sinon.spy(console, 'error');
sinon.spy(console, 'info');
});
afterEach(function () {
console.log.restore();
console.debug.restore();
console.warn.restore();
console.error.restore();
console.info.restore();
});
it('should use noop for levels lower than the min level', function () {
@@ -71,12 +31,16 @@ describe('Utils', function() {
expect(console.log).to.not.have.been.called;
});
it('should use console.log for Debug and Info', function () {
it('should use console.debug for Debug', function () {
Util.init_logging('debug');
Util.Debug('dbg');
expect(console.debug).to.have.been.calledWith('dbg');
});
it('should use console.info for Info', function () {
Util.init_logging('debug');
Util.Info('inf');
expect(console.log).to.have.been.calledWith('dbg');
expect(console.log).to.have.been.calledWith('inf');
expect(console.info).to.have.been.calledWith('inf');
});
it('should use console.warn for Warn', function () {
@@ -94,6 +58,72 @@ describe('Utils', function() {
});
});
describe('language selection', function () {
var origNavigator;
beforeEach(function () {
// window.navigator is a protected read-only property in many
// environments, so we need to redefine it whilst running these
// tests.
origNavigator = Object.getOwnPropertyDescriptor(window, "navigator");
if (origNavigator === undefined) {
// Object.getOwnPropertyDescriptor() doesn't work
// properly in any version of IE
this.skip();
}
Object.defineProperty(window, "navigator", {value: {}});
if (window.navigator.languages !== undefined) {
// Object.defineProperty() doesn't work properly in old
// versions of Chrome
this.skip();
}
window.navigator.languages = [];
});
afterEach(function () {
Object.defineProperty(window, "navigator", origNavigator);
});
it('should use English by default', function() {
expect(Util.Localisation.language).to.equal('en');
});
it('should use English if no user language matches', function() {
window.navigator.languages = ["nl", "de"];
Util.Localisation.setup(["es", "fr"]);
expect(Util.Localisation.language).to.equal('en');
});
it('should use the most preferred user language', function() {
window.navigator.languages = ["nl", "de", "fr"];
Util.Localisation.setup(["es", "fr", "de"]);
expect(Util.Localisation.language).to.equal('de');
});
it('should prefer sub-languages languages', function() {
window.navigator.languages = ["pt-BR"];
Util.Localisation.setup(["pt", "pt-BR"]);
expect(Util.Localisation.language).to.equal('pt-BR');
});
it('should fall back to language "parents"', function() {
window.navigator.languages = ["pt-BR"];
Util.Localisation.setup(["fr", "pt", "de"]);
expect(Util.Localisation.language).to.equal('pt');
});
it('should not use specific language when user asks for a generic language', function() {
window.navigator.languages = ["pt", "de"];
Util.Localisation.setup(["fr", "pt-BR", "de"]);
expect(Util.Localisation.language).to.equal('de');
});
it('should handle underscore as a separator', function() {
window.navigator.languages = ["pt-BR"];
Util.Localisation.setup(["pt_BR"]);
expect(Util.Localisation.language).to.equal('pt_BR');
});
it('should handle difference in case', function() {
window.navigator.languages = ["pt-br"];
Util.Localisation.setup(["pt-BR"]);
expect(Util.Localisation.language).to.equal('pt-BR');
});
});
// TODO(directxman12): test the conf_default and conf_defaults methods
// TODO(directxman12): test decodeUTF8
// TODO(directxman12): test the event methods (addEvent, removeEvent, stopEvent)
@@ -101,5 +131,4 @@ describe('Utils', function() {
// TODO(directxman12): figure out how to test the browser detection functions properly
// (we can't really test them against the browsers, except for Gecko
// via PhantomJS, the default test driver)
// TODO(directxman12): figure out how to test Util.Flash
});
+56 -111
View File
@@ -1,5 +1,5 @@
// requires local modules: websock, base64, util
// requires test modules: fake.websocket
// requires local modules: websock, util
// requires test modules: fake.websocket, assertions
/* jshint expr: true */
var assert = chai.assert;
var expect = chai.expect;
@@ -9,13 +9,14 @@ describe('Websock', function() {
describe('Queue methods', function () {
var sock;
var RQ_TEMPLATE = [0, 1, 2, 3, 4, 5, 6, 7];
var RQ_TEMPLATE = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7]);
beforeEach(function () {
sock = new Websock();
for (var i = RQ_TEMPLATE.length - 1; i >= 0; i--) {
sock.rQunshift8(RQ_TEMPLATE[i]);
}
// skip init
sock._allocate_buffers();
sock._rQ.set(RQ_TEMPLATE);
sock._rQlen = RQ_TEMPLATE.length;
});
describe('rQlen', function () {
it('should return the length of the receive queue', function () {
@@ -49,14 +50,6 @@ describe('Websock', function() {
});
});
describe('rQunshift8', function () {
it('should place a byte at the front of the queue', function () {
sock.rQunshift8(255);
expect(sock.rQpeek8()).to.equal(255);
expect(sock.rQlen()).to.equal(RQ_TEMPLATE.length + 1);
});
});
describe('rQshift16', function () {
it('should pop two bytes from the receive queue and return a single number', function () {
var bef_len = sock.rQlen();
@@ -84,7 +77,7 @@ describe('Websock', function() {
var bef_rQi = sock.get_rQi();
var shifted = sock.rQshiftStr(3);
expect(shifted).to.be.a('string');
expect(shifted).to.equal(String.fromCharCode.apply(null, RQ_TEMPLATE.slice(bef_rQi, bef_rQi + 3)));
expect(shifted).to.equal(String.fromCharCode.apply(null, Array.prototype.slice.call(new Uint8Array(RQ_TEMPLATE.buffer, bef_rQi, 3))));
expect(sock.rQlen()).to.equal(bef_len - 3);
});
@@ -99,8 +92,8 @@ describe('Websock', function() {
var bef_len = sock.rQlen();
var bef_rQi = sock.get_rQi();
var shifted = sock.rQshiftBytes(3);
expect(shifted).to.be.an.instanceof(Array);
expect(shifted).to.deep.equal(RQ_TEMPLATE.slice(bef_rQi, bef_rQi + 3));
expect(shifted).to.be.an.instanceof(Uint8Array);
expect(shifted).to.array.equal(new Uint8Array(RQ_TEMPLATE.buffer, bef_rQi, 3));
expect(sock.rQlen()).to.equal(bef_len - 3);
});
@@ -123,19 +116,19 @@ describe('Websock', function() {
it('should return an array containing the given slice of the receive queue', function () {
var sl = sock.rQslice(0, 2);
expect(sl).to.be.an.instanceof(Array);
expect(sl).to.deep.equal(RQ_TEMPLATE.slice(0, 2));
expect(sl).to.be.an.instanceof(Uint8Array);
expect(sl).to.array.equal(new Uint8Array(RQ_TEMPLATE.buffer, 0, 2));
});
it('should use the rest of the receive queue if no end is given', function () {
var sl = sock.rQslice(1);
expect(sl).to.have.length(RQ_TEMPLATE.length - 1);
expect(sl).to.deep.equal(RQ_TEMPLATE.slice(1));
expect(sl).to.array.equal(new Uint8Array(RQ_TEMPLATE.buffer, 1));
});
it('should take the current rQi in to account', function () {
sock.set_rQi(1);
expect(sock.rQslice(0, 2)).to.deep.equal(RQ_TEMPLATE.slice(1, 3));
expect(sock.rQslice(0, 2)).to.array.equal(new Uint8Array(RQ_TEMPLATE.buffer, 1, 2));
});
});
@@ -177,10 +170,11 @@ describe('Websock', function() {
};
});
it('should actually send on the websocket if the websocket does not have too much buffered', function () {
sock.maxBufferedAmount = 10;
it('should actually send on the websocket', function () {
sock._websocket.bufferedAmount = 8;
sock._sQ = [1, 2, 3];
sock._websocket.readyState = WebSocket.OPEN
sock._sQ = new Uint8Array([1, 2, 3]);
sock._sQlen = 3;
var encoded = sock._encode_message();
sock.flush();
@@ -188,30 +182,14 @@ describe('Websock', function() {
expect(sock._websocket.send).to.have.been.calledWith(encoded);
});
it('should return true if the websocket did not have too much buffered', function () {
sock.maxBufferedAmount = 10;
sock._websocket.bufferedAmount = 8;
expect(sock.flush()).to.be.true;
});
it('should not call send if we do not have anything queued up', function () {
sock._sQ = [];
sock.maxBufferedAmount = 10;
sock._sQlen = 0;
sock._websocket.bufferedAmount = 8;
sock.flush();
expect(sock._websocket.send).not.to.have.been.called;
});
it('should not send and return false if the websocket has too much buffered', function () {
sock.maxBufferedAmount = 10;
sock._websocket.bufferedAmount = 12;
expect(sock.flush()).to.be.false;
expect(sock._websocket.send).to.not.have.been.called;
});
});
describe('send', function () {
@@ -222,7 +200,7 @@ describe('Websock', function() {
it('should add to the send queue', function () {
sock.send([1, 2, 3]);
var sq = sock.get_sQ();
expect(sock.get_sQ().slice(sq.length - 3)).to.deep.equal([1, 2, 3]);
expect(new Uint8Array(sq.buffer, sock._sQlen - 3, 3)).to.array.equal(new Uint8Array([1, 2, 3]));
});
it('should call flush', function () {
@@ -257,6 +235,8 @@ describe('Websock', function() {
WebSocket.CONNECTING = old_WS.CONNECTING;
WebSocket.CLOSING = old_WS.CLOSING;
WebSocket.CLOSED = old_WS.CLOSED;
WebSocket.prototype.binaryType = 'arraybuffer';
});
describe('opening', function () {
@@ -265,22 +245,10 @@ describe('Websock', function() {
});
it('should open the actual websocket', function () {
sock.open('ws://localhost:8675', 'base64');
expect(WebSocket).to.have.been.calledWith('ws://localhost:8675', 'base64');
sock.open('ws://localhost:8675', 'binary');
expect(WebSocket).to.have.been.calledWith('ws://localhost:8675', 'binary');
});
it('should fail if we try to use binary but do not support it', function () {
expect(function () { sock.open('ws:///', 'binary'); }).to.throw(Error);
});
it('should fail if we specified an array with only binary and we do not support it', function () {
expect(function () { sock.open('ws:///', ['binary']); }).to.throw(Error);
});
it('should skip binary if we have multiple options for encoding and do not support binary', function () {
sock.open('ws:///', ['binary', 'base64']);
expect(WebSocket).to.have.been.calledWith('ws:///', ['base64']);
});
// it('should initialize the event handlers')?
});
@@ -340,18 +308,6 @@ describe('Websock', function() {
expect(sock._recv_message).to.have.been.calledOnce;
});
it('should copy the mode over upon opening', function () {
sock._websocket.protocol = 'cheese';
sock._websocket.onopen();
expect(sock._mode).to.equal('cheese');
});
it('should assume base64 if no protocol was available on opening', function () {
sock._websocket.protocol = null;
sock._websocket.onopen();
expect(sock._mode).to.equal('base64');
});
it('should call the open event handler on opening', function () {
sock._websocket.onopen();
expect(sock._eventHandlers.open).to.have.been.calledOnce;
@@ -377,13 +333,7 @@ describe('Websock', function() {
var sock;
beforeEach(function () {
sock = new Websock();
});
it('should support decoding base64 string data to add it to the receive queue', function () {
var msg = { data: Base64.encode([1, 2, 3]) };
sock._mode = 'base64';
sock._recv_message(msg);
expect(sock.rQshiftStr(3)).to.equal('\x01\x02\x03');
sock._allocate_buffers();
});
it('should support adding binary Uint8Array data to the receive queue', function () {
@@ -395,16 +345,16 @@ describe('Websock', function() {
it('should call the message event handler if present', function () {
sock._eventHandlers.message = sinon.spy();
var msg = { data: Base64.encode([1, 2, 3]) };
sock._mode = 'base64';
var msg = { data: new Uint8Array([1, 2, 3]).buffer };
sock._mode = 'binary';
sock._recv_message(msg);
expect(sock._eventHandlers.message).to.have.been.calledOnce;
});
it('should not call the message event handler if there is nothing in the receive queue', function () {
sock._eventHandlers.message = sinon.spy();
var msg = { data: Base64.encode([]) };
sock._mode = 'base64';
var msg = { data: new Uint8Array([]).buffer };
sock._mode = 'binary';
sock._recv_message(msg);
expect(sock._eventHandlers.message).not.to.have.been.called;
});
@@ -412,21 +362,36 @@ describe('Websock', function() {
it('should compact the receive queue', function () {
// NB(sross): while this is an internal implementation detail, it's important to
// test, otherwise the receive queue could become very large very quickly
sock._rQ = [0, 1, 2, 3, 4, 5];
sock._rQ = new Uint8Array([0, 1, 2, 3, 4, 5, 0, 0, 0, 0]);
sock._rQlen = 6;
sock.set_rQi(6);
sock._rQmax = 3;
var msg = { data: Base64.encode([1, 2, 3]) };
sock._mode = 'base64';
var msg = { data: new Uint8Array([1, 2, 3]).buffer };
sock._mode = 'binary';
sock._recv_message(msg);
expect(sock._rQ.length).to.equal(3);
expect(sock._rQlen).to.equal(3);
expect(sock.get_rQi()).to.equal(0);
});
it('should automatically resize the receive queue if the incoming message is too large', function () {
sock._rQ = new Uint8Array(20);
sock._rQlen = 0;
sock.set_rQi(0);
sock._rQbufferSize = 20;
sock._rQmax = 2;
var msg = { data: new Uint8Array(30).buffer };
sock._mode = 'binary';
sock._recv_message(msg);
expect(sock._rQlen).to.equal(30);
expect(sock.get_rQi()).to.equal(0);
expect(sock._rQ.length).to.equal(240); // keep the invariant that rQbufferSize / 8 >= rQlen
});
it('should call the error event handler on an exception', function () {
sock._eventHandlers.error = sinon.spy();
sock._eventHandlers.message = sinon.stub().throws();
var msg = { data: Base64.encode([1, 2, 3]) };
sock._mode = 'base64';
var msg = { data: new Uint8Array([1, 2, 3]).buffer };
sock._mode = 'binary';
sock._recv_message(msg);
expect(sock._eventHandlers.error).to.have.been.calledOnce;
});
@@ -444,37 +409,17 @@ describe('Websock', function() {
sock._websocket._open();
});
it('should convert the send queue into an ArrayBuffer', function () {
sock._sQ = [1, 2, 3];
var res = sock._encode_message(); // An ArrayBuffer
expect(new Uint8Array(res)).to.deep.equal(new Uint8Array(res));
it('should only send the send queue up to the send queue length', function () {
sock._sQ = new Uint8Array([1, 2, 3, 4, 5]);
sock._sQlen = 3;
var res = sock._encode_message();
expect(res).to.array.equal(new Uint8Array([1, 2, 3]));
});
it('should properly pass the encoded data off to the actual WebSocket', function () {
sock.send([1, 2, 3]);
expect(sock._websocket._get_sent_data()).to.deep.equal([1, 2, 3]);
expect(sock._websocket._get_sent_data()).to.array.equal(new Uint8Array([1, 2, 3]));
});
});
describe('as Base64 data', function () {
var sock;
beforeEach(function () {
sock = new Websock();
sock.open('ws://', 'base64');
sock._websocket._open();
});
it('should convert the send queue into a Base64-encoded string', function () {
sock._sQ = [1, 2, 3];
expect(sock._encode_message()).to.equal(Base64.encode([1, 2, 3]));
});
it('should properly pass the encoded data off to the actual WebSocket', function () {
sock.send([1, 2, 3]);
expect(sock._websocket._get_sent_data()).to.deep.equal([1, 2, 3]);
});
});
});
});
-43
View File
@@ -1,43 +0,0 @@
html,body {
margin: 0px;
padding: 0px;
width: 100%;
height: 100%;
}
.flex-layout {
width: 100%;
height: 100%;
display: box;
display: -webkit-box;
display: -moz-box;
display: -ms-box;
box-orient: vertical;
-webkit-box-orient: vertical;
-moz-box-orient: vertical;
-ms-box-orient: vertical;
box-align: stretch;
-webkit-box-align: stretch;
-moz-box-align: stretch;
-ms-box-align: stretch;
}
.flex-box {
box-flex: 1;
-webkit-box-flex: 1;
-moz-box-flex: 1;
-ms-box-flex: 1;
}
.container {
margin: 0px;
padding: 0px;
}
.canvas {
position: absolute;
border-style: dotted;
border-width: 1px;
}
-203
View File
@@ -1,203 +0,0 @@
<!DOCTYPE html>
<html>
<head><title>Viewport Test</title>
<link rel="stylesheet" href="viewport.css">
<!--
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
-->
<meta name=viewport content="width=device-width, initial-scale=1.0, user-scalable=no">
</head>
<body>
<div class="flex-layout">
<div>
Canvas:
<input id="move-selector" type="button" value="Move"
onclick="toggleMove();">
<br>
</div>
<div class="container flex-box">
<canvas id="canvas" class="canvas">
Canvas not supported.
</canvas>
<br>
</div>
<div>
<br>
Results:<br>
<textarea id="messages" style="font-size: 9;" cols=80 rows=8></textarea>
</div>
</div>
</body>
<!--
<script type='text/javascript'
src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
-->
<script src="../include/util.js"></script>
<script src="../include/webutil.js"></script>
<script src="../include/base64.js"></script>
<script src="../include/keysymdef.js"></script>
<script src="../include/keyboard.js"></script>
<script src="../include/input.js"></script>
<script src="../include/display.js"></script>
<script>
var msg_cnt = 0, iterations,
penDown = false, doMove = false,
inMove = false, lastPos = {},
padW = 0, padH = 0,
display, ctx, keyboard, mouse;
var newline = "\n";
if (Util.Engine.trident) {
var newline = "<br>\n";
}
function message(str) {
console.log(str);
cell = $D('messages');
cell.innerHTML += msg_cnt + ": " + str + newline;
cell.scrollTop = cell.scrollHeight;
msg_cnt++;
}
function mouseButton(x, y, down, bmask) {
//msg = 'mouse x,y: ' + x + ',' + y + ' down: ' + down;
//msg += ' bmask: ' + bmask;
//message(msg);
if (doMove) {
if (down && !inMove) {
inMove = true;
lastPos = {'x': x, 'y': y};
} else if (!down && inMove) {
inMove = false;
//dirtyRedraw();
}
return;
}
if (down && ! penDown) {
penDown = true;
ctx.beginPath();
ctx.moveTo(x, y);
} else if (!down && penDown) {
penDown = false;
ctx.closePath();
}
}
function mouseMove(x, y) {
var deltaX, deltaY;
if (inMove) {
//deltaX = x - lastPos.x; // drag viewport
deltaX = lastPos.x - x; // drag frame buffer
//deltaY = y - lastPos.y; // drag viewport
deltaY = lastPos.y - y; // drag frame buffer
lastPos = {'x': x, 'y': y};
display.viewportChangePos(deltaX, deltaY);
return;
}
if (penDown) {
ctx.lineTo(x, y);
ctx.stroke();
}
}
function dirtyRedraw() {
if (inMove) {
// Wait for user to stop moving viewport
return;
}
var d = display.getCleanDirtyReset();
for (i = 0; i < d.dirtyBoxes.length; i++) {
//showBox(d.dirtyBoxes[i], "dirty[" + i + "]: ");
drawArea(d.dirtyBoxes[i]);
}
}
function drawArea(b) {
var data = [], pixel, x, y;
//message("draw "+b.x+","+b.y+" ("+b.w+","+b.h+")");
for (var i = 0; i < b.w; i++) {
x = b.x + i;
for (var j = 0; j < b.h; j++) {
y = b.y + j;
pixel = (j * b.w * 4 + i * 4);
data[pixel + 0] = ((x * y) / 13) % 256;
data[pixel + 1] = ((x * y) + 392) % 256;
data[pixel + 2] = ((x + y) + 256) % 256;
data[pixel + 3] = 255;
}
}
//message("i: " + i + ", j: " + j + ", pixel: " + pixel);
display.blitImage(b.x, b.y, b.w, b.h, data, 0);
}
function toggleMove() {
if (doMove) {
doMove = false;
$D('move-selector').style.backgroundColor = "";
$D('move-selector').style.color = "";
} else {
doMove = true;
$D('move-selector').style.backgroundColor = "black";
$D('move-selector').style.color = "lightgray";
}
}
function detectPad() {
var c = $D('canvas'), p = c.parentNode;
c.width = 10;
c.height = 10;
padW = c.offsetWidth - 10;
padH = c.offsetHeight - 10;
message("padW: " + padW + ", padH: " + padH);
}
function doResize() {
var p = $D('canvas').parentNode;
message("doResize1: [" + (p.offsetWidth - padW) +
"," + (p.offsetHeight - padH) + "]");
display.viewportChangeSize(p.offsetWidth - padW, p.offsetHeight - padH);
/*
var pos, new_w, new_h;pos
pos = Util.getPosition($D('canvas').parentNode);
new_w = window.innerWidth - pos.x;
new_h = window.innerHeight - pos.y;
display.viewportChangeSize(new_w, new_h);
*/
}
window.onload = function() {
detectPad();
display = new Display({'target': $D('canvas')});
display.resize(1600, 1024);
display.set_viewport(true);
ctx = display.get_context();
mouse = new Mouse({'target': $D('canvas'),
'onMouseButton': mouseButton,
'onMouseMove': mouseMove});
mouse.grab();
Util.addEvent(window, 'resize', doResize);
// Shrink viewport for first resize call so that the
// scrollbars are disabled
display.viewportChangeSize(10, 10);
setTimeout(doResize, 1);
setInterval(dirtyRedraw, 50);
message("Display initialized");
};
</script>
</html>
+38 -38
View File
@@ -31,24 +31,31 @@
</body>
<!--
<script type='text/javascript'
<script type='text/javascript'
src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
-->
<script type="text/javascript">
var INCLUDE_URI= "../include/";
// TODO: Data file should override
var VNC_frame_encoding = "base64";
var INCLUDE_URI= "../";
</script>
<script src="../include/util.js"></script>
<script src="../include/playback.js"></script>
<script src="../data/multi.js"></script>
<script src="../core/util.js"></script>
<script src="../app/webutil.js"></script>
<script>
// Load supporting scripts
Util.load_scripts(["webutil.js", "base64.js", "websock.js", "des.js",
"keysymdef.js", "keyboard.js", "input.js", "display.js",
"jsunzip.js", "rfb.js"]);
var fname = WebUtil.getQueryVar('data', null);
if (fname) {
msg("Loading " + fname);
// Load supporting scripts
WebUtil.load_scripts({
'core': ["base64.js", "websock.js", "des.js", "input/keysym.js",
"input/keysymdef.js", "input/xtscancodes.js", "input/util.js",
"input/devices.js", "display.js", "rfb.js", "inflator.js"],
'tests': ["playback.js"],
'recordings': [fname]});
} else {
msg("Must specifiy data=FOO.js in query string.");
}
var start_time, VNC_frame_data, pass, passes, encIdx,
encOrder = ['raw', 'rre', 'hextile', 'tightpng', 'copyrect'],
@@ -57,8 +64,8 @@
function msg(str) {
console.log(str);
var cell = $D('messages');
cell.innerHTML += str + "\n";
var cell = document.getElementById('messages');
cell.textContent += str + "\n";
cell.scrollTop = cell.scrollHeight;
}
function dbgmsg(str) {
@@ -67,31 +74,26 @@
}
}
updateState = function (rfb, state, oldstate, mesg) {
switch (state) {
case 'failed':
case 'fatal':
msg("noVNC sent '" + state +
"' state during pass " + pass +
", iteration " + iteration +
" frame " + frame_idx);
test_state = 'failed';
break;
case 'loaded':
$D('startButton').disabled = false;
break;
}
if (typeof mesg !== 'undefined') {
$D('VNC_status').innerHTML = mesg;
disconnected = function (rfb, reason) {
if (reason) {
msg("noVNC sent '" + state +
"' state during pass " + pass +
", iteration " + iteration +
" frame " + frame_idx);
test_state = 'failed';
}
}
notification = function (rfb, mesg, level, options) {
document.getElementById('VNC_status').textContent = mesg;
}
function do_test() {
$D('startButton').value = "Running";
$D('startButton').disabled = true;
document.getElementById('startButton').value = "Running";
document.getElementById('startButton').disabled = true;
mode = 'perftest'; // full-speed
passes = $D('passes').value;
passes = document.getElementById('passes').value;
pass = 1;
encIdx = 0;
@@ -135,8 +137,8 @@
// Shut-off event interception
rfb.get_mouse().ungrab();
rfb.get_keyboard().ungrab();
$D('startButton').disabled = false;
$D('startButton').value = "Start";
document.getElementById('startButton').disabled = false;
document.getElementById('startButton').value = "Start";
finish_passes();
return; // We are finished, terminate
}
@@ -183,7 +185,7 @@
enc = encOrder[i];
avg = (encTot[i] / passes).toFixed(1);
msg(" " + enc + ": " + encTot[i] + " ms, " +
encMin[i] + "/" + avg + "/" + encMax[i] +
encMin[i] + "/" + avg + "/" + encMax[i] +
" (min/avg/max)");
}
@@ -201,9 +203,7 @@
enc = encOrder[i];
dbgmsg(" " + enc + ": " + VNC_frame_data_multi[enc].length);
}
rfb = new RFB({'target': $D('VNC_canvas'),
'onUpdateState': updateState});
rfb.testMode(send_array, VNC_frame_encoding);
document.getElementById('startButton').disabled = false;
}
</script>
</html>
+33 -37
View File
@@ -33,25 +33,23 @@
</body>
<!--
<script type='text/javascript'
<script type='text/javascript'
src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
-->
<script type="text/javascript">
var INCLUDE_URI= "../include/";
// TODO: Data file should override
var VNC_frame_encoding = "base64";
var INCLUDE_URI= "../";
</script>
<script src="../include/util.js"></script>
<script src="../include/webutil.js"></script>
<script src="../core/util.js"></script>
<script src="../app/webutil.js"></script>
<script>
var fname, start_time;
function message(str) {
console.log(str);
var cell = $D('messages');
cell.innerHTML += str + "\n";
var cell = document.getElementById('messages');
cell.textContent += str + "\n";
cell.scrollTop = cell.scrollHeight;
}
@@ -59,39 +57,37 @@
if (fname) {
message("Loading " + fname);
// Load supporting scripts
Util.load_scripts(["base64.js", "websock.js", "des.js",
"keysymdef.js", "keyboard.js", "input.js", "display.js",
"jsunzip.js", "rfb.js", "playback.js", fname]);
WebUtil.load_scripts({
'core': ["base64.js", "websock.js", "des.js", "input/keysym.js",
"input/keysymdef.js", "input/xtscancodes.js", "input/util.js",
"input/devices.js", "display.js", "rfb.js", "inflator.js"],
'tests': ["playback.js"],
'recordings': [fname]});
} else {
message("Must specify data=FOO in query string.");
}
updateState = function (rfb, state, oldstate, msg) {
switch (state) {
case 'failed':
case 'fatal':
message("noVNC sent '" + state + "' state during iteration " + iteration + " frame " + frame_idx);
test_state = 'failed';
break;
case 'loaded':
$D('startButton').disabled = false;
break;
}
if (typeof msg !== 'undefined') {
$D('VNC_status').innerHTML = msg;
disconnected = function (rfb, reason) {
if (reason) {
message("noVNC sent '" + state + "' state during iteration " + iteration + " frame " + frame_idx);
test_state = 'failed';
}
}
function start() {
$D('startButton').value = "Running";
$D('startButton').disabled = true;
notification = function (rfb, mesg, level, options) {
document.getElementById('VNC_status').textContent = mesg;
}
iterations = $D('iterations').value;
function start() {
document.getElementById('startButton').value = "Running";
document.getElementById('startButton').disabled = true;
iterations = document.getElementById('iterations').value;
iteration = 0;
start_time = (new Date()).getTime();
if ($D('mode1').checked) {
if (document.getElementById('mode1').checked) {
message("Starting performance playback (fullspeed) [" + iterations + " iteration(s)]");
mode = 'perftest';
} else {
@@ -99,7 +95,8 @@
mode = 'realtime';
}
recv_message = rfb.testMode(send_array, VNC_frame_encoding);
//recv_message = rfb.testMode(send_array, VNC_frame_encoding);
next_iteration();
}
@@ -114,25 +111,24 @@
// Shut-off event interception
rfb.get_mouse().ungrab();
rfb.get_keyboard().ungrab();
$D('startButton').disabled = false;
$D('startButton').value = "Start";
document.getElementById('startButton').disabled = false;
document.getElementById('startButton').value = "Start";
}
window.onscriptsload = function () {
iterations = WebUtil.getQueryVar('iterations', 3);
$D('iterations').value = iterations;
document.getElementById('iterations').value = iterations;
mode = WebUtil.getQueryVar('mode', 3);
if (mode === 'realtime') {
$D('mode2').checked = true;
document.getElementById('mode2').checked = true;
} else {
$D('mode1').checked = true;
document.getElementById('mode1').checked = true;
}
if (fname) {
message("VNC_frame_data.length: " + VNC_frame_data.length);
rfb = new RFB({'target': $D('VNC_canvas'),
'onUpdateState': updateState});
}
document.getElementById('startButton').disabled = false;
}
</script>
</html>