diff options
author | Solly Ross <sross@redhat.com> | 2014-05-21 14:54:28 -0400 |
---|---|---|
committer | Solly Ross <sross@redhat.com> | 2014-09-15 16:46:02 -0400 |
commit | d21cd6c16453eec8ec4b218dff6dffecf55aa518 (patch) | |
tree | 70e4b8add3fa4a7f07ed862394d338a551d4c75b | |
parent | fb64ed213584423475a262631b6be2e2a157c628 (diff) | |
download | novnc-d21cd6c16453eec8ec4b218dff6dffecf55aa518.tar.gz |
Cleanup: Util code
File: util.js
Tests Added: True (partial -- for logging and array push methods)
Changes:
- Fixed JSHint Errors (indentation, semicolons, global "use strict")
- Made browser detection methods more readable
- added some newline characters when appropriate for readability
- throw Errors not strings!
- Removed conf_defaults, and added make_properties and set_defaults
instead (see below)
The removal of conf_defaults and switch to make_properties and
set_defaults is to facilitate the switch over to normal Javascript
constructors instead of Crockford-style constructors. Now, methods
are added to the objects prototype (and thus make properties is called
outside the constructor).
-rw-r--r-- | include/util.js | 595 | ||||
-rw-r--r-- | tests/test.util.js | 105 |
2 files changed, 471 insertions, 229 deletions
diff --git a/include/util.js b/include/util.js index ea14b5b..c145d5a 100644 --- a/include/util.js +++ b/include/util.js @@ -6,9 +6,8 @@ * See README.md for usage and integration instructions. */ -"use strict"; -/*jslint bitwise: false, white: false */ -/*global window, console, document, navigator, ActiveXObject */ +/* jshint white: false, nonstandard: true */ +/*global window, console, document, navigator, ActiveXObject, INCLUDE_URI */ // Globals defined here var Util = {}; @@ -19,129 +18,161 @@ var Util = {}; */ Array.prototype.push8 = function (num) { + "use strict"; this.push(num & 0xFF); }; Array.prototype.push16 = function (num) { + "use strict"; this.push((num >> 8) & 0xFF, - (num ) & 0xFF ); + num & 0xFF); }; Array.prototype.push32 = function (num) { + "use strict"; this.push((num >> 24) & 0xFF, (num >> 16) & 0xFF, (num >> 8) & 0xFF, - (num ) & 0xFF ); + num & 0xFF); }; // IE does not support map (even in IE9) //This prototype is provided by the Mozilla foundation and //is distributed under the MIT license. //http://www.ibiblio.org/pub/Linux/LICENSES/mit.license -if (!Array.prototype.map) -{ - Array.prototype.map = function(fun /*, thisp*/) - { - var len = this.length; - if (typeof fun != "function") - throw new TypeError(); - - var res = new Array(len); - var thisp = arguments[1]; - for (var i = 0; i < len; i++) - { - if (i in this) - res[i] = fun.call(thisp, this[i], i, this); - } +if (!Array.prototype.map) { + Array.prototype.map = function (fun /*, thisp*/) { + "use strict"; + var len = this.length; + if (typeof fun != "function") { + throw new TypeError(); + } - return res; - }; + var res = new Array(len); + var thisp = arguments[1]; + for (var i = 0; i < len; i++) { + if (i in this) { + res[i] = fun.call(thisp, this[i], i, this); + } + } + + return res; + }; } // IE <9 does not support indexOf //This prototype is provided by the Mozilla foundation and //is distributed under the MIT license. //http://www.ibiblio.org/pub/Linux/LICENSES/mit.license -if (!Array.prototype.indexOf) -{ - Array.prototype.indexOf = function(elt /*, from*/) - { - var len = this.length >>> 0; - - var from = Number(arguments[1]) || 0; - from = (from < 0) - ? Math.ceil(from) - : Math.floor(from); - if (from < 0) - from += len; - - for (; from < len; from++) - { - if (from in this && - this[from] === elt) - return from; - } - return -1; - }; +if (!Array.prototype.indexOf) { + Array.prototype.indexOf = function (elt /*, from*/) { + "use strict"; + var len = this.length >>> 0; + + var from = Number(arguments[1]) || 0; + from = (from < 0) ? Math.ceil(from) : Math.floor(from); + if (from < 0) { + from += len; + } + + for (; from < len; from++) { + if (from in this && + this[from] === elt) { + return from; + } + } + return -1; + }; } // From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys if (!Object.keys) { - Object.keys = (function () { - 'use strict'; - var hasOwnProperty = Object.prototype.hasOwnProperty, - hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), - dontEnums = [ - 'toString', - 'toLocaleString', - 'valueOf', - 'hasOwnProperty', - 'isPrototypeOf', - 'propertyIsEnumerable', - 'constructor' - ], - dontEnumsLength = dontEnums.length; + Object.keys = (function () { + 'use strict'; + var hasOwnProperty = Object.prototype.hasOwnProperty, + hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), + dontEnums = [ + 'toString', + 'toLocaleString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'constructor' + ], + dontEnumsLength = dontEnums.length; + + return function (obj) { + if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) { + throw new TypeError('Object.keys called on non-object'); + } - return function (obj) { - if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) { - throw new TypeError('Object.keys called on non-object'); - } + var result = [], prop, i; - var result = [], prop, i; + for (prop in obj) { + if (hasOwnProperty.call(obj, prop)) { + result.push(prop); + } + } - for (prop in obj) { - if (hasOwnProperty.call(obj, prop)) { - result.push(prop); - } - } + if (hasDontEnumBug) { + for (i = 0; i < dontEnumsLength; i++) { + if (hasOwnProperty.call(obj, dontEnums[i])) { + result.push(dontEnums[i]); + } + } + } + return result; + }; + })(); +} - if (hasDontEnumBug) { - for (i = 0; i < dontEnumsLength; i++) { - if (hasOwnProperty.call(obj, dontEnums[i])) { - result.push(dontEnums[i]); - } +// PhantomJS 1.x doesn't support bind, +// so leave this in until PhantomJS 2.0 is released +//This prototype is provided by the Mozilla foundation and +//is distributed under the MIT license. +//http://www.ibiblio.org/pub/Linux/LICENSES/mit.license +if (!Function.prototype.bind) { + Function.prototype.bind = function (oThis) { + if (typeof this !== "function") { + // closest thing possible to the ECMAScript 5 + // internal IsCallable function + throw new TypeError("Function.prototype.bind - " + + "what is trying to be bound is not callable"); } - } - return result; + + var aArgs = Array.prototype.slice.call(arguments, 1), + fToBind = this, + fNOP = function () {}, + fBound = function () { + return fToBind.apply(this instanceof fNOP && oThis ? this + : oThis, + aArgs.concat(Array.prototype.slice.call(arguments))); + }; + + fNOP.prototype = this.prototype; + fBound.prototype = new fNOP(); + + return fBound; }; - }()); } -// +// // requestAnimationFrame shim with setTimeout fallback // -window.requestAnimFrame = (function(){ - return window.requestAnimationFrame || - window.webkitRequestAnimationFrame || - window.mozRequestAnimationFrame || - window.oRequestAnimationFrame || - window.msRequestAnimationFrame || - function(callback){ +window.requestAnimFrame = (function () { + "use strict"; + return window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function (callback) { window.setTimeout(callback, 1000 / 60); }; })(); -/* +/* * ------------------------------------------------------ * Namespaced in Util * ------------------------------------------------------ @@ -153,6 +184,7 @@ window.requestAnimFrame = (function(){ Util._log_level = 'warn'; Util.init_logging = function (level) { + "use strict"; if (typeof level === 'undefined') { level = Util._log_level; } else { @@ -163,26 +195,34 @@ Util.init_logging = function (level) { window.console = { 'log' : window.opera.postError, 'warn' : window.opera.postError, - 'error': window.opera.postError }; + 'error': window.opera.postError + }; } else { window.console = { - 'log' : function(m) {}, - 'warn' : function(m) {}, - 'error': function(m) {}}; + 'log' : function (m) {}, + 'warn' : function (m) {}, + 'error': function (m) {} + }; } } Util.Debug = Util.Info = Util.Warn = Util.Error = function (msg) {}; + /* jshint -W086 */ switch (level) { - case 'debug': Util.Debug = function (msg) { console.log(msg); }; - case 'info': Util.Info = function (msg) { console.log(msg); }; - case 'warn': Util.Warn = function (msg) { console.warn(msg); }; - case 'error': Util.Error = function (msg) { console.error(msg); }; + case 'debug': + Util.Debug = function (msg) { console.log(msg); }; + case 'info': + Util.Info = function (msg) { console.log(msg); }; + case 'warn': + Util.Warn = function (msg) { console.warn(msg); }; + case 'error': + Util.Error = function (msg) { console.error(msg); }; case 'none': break; default: - throw("invalid logging type '" + level + "'"); + throw new Error("invalid logging type '" + level + "'"); } + /* jshint +W086 */ }; Util.get_logging = function () { return Util._log_level; @@ -190,93 +230,133 @@ Util.get_logging = function () { // Initialize logging level Util.init_logging(); +Util.make_property = function (proto, name, mode, type) { + "use strict"; -// Set configuration default for Crockford style function namespaces -Util.conf_default = function(cfg, api, defaults, v, mode, type, defval, desc) { - var getter, setter; + var getter; + if (type === 'arr') { + getter = function (idx) { + if (typeof idx !== 'undefined') { + return this['_' + name][idx]; + } else { + return this['_' + name]; + } + }; + } else { + getter = function () { + return this['_' + name]; + }; + } - // Default getter function - getter = function (idx) { - if ((type in {'arr':1, 'array':1}) && - (typeof idx !== 'undefined')) { - return cfg[v][idx]; + var make_setter = function (process_val) { + if (process_val) { + return function (val, idx) { + if (typeof idx !== 'undefined') { + this['_' + name][idx] = process_val(val); + } else { + this['_' + name] = process_val(val); + } + }; } else { - return cfg[v]; + return function (val, idx) { + if (typeof idx !== 'undefined') { + this['_' + name][idx] = val; + } else { + this['_' + name] = val; + } + }; } }; - // Default setter function - setter = function (val, idx) { - if (type in {'boolean':1, 'bool':1}) { - if ((!val) || (val in {'0':1, 'no':1, 'false':1})) { - val = false; + var setter; + if (type === 'bool') { + setter = make_setter(function (val) { + if (!val || (val in {'0': 1, 'no': 1, 'false': 1})) { + return false; } else { - val = true; + return true; } - } else if (type in {'integer':1, 'int':1}) { - val = parseInt(val, 10); - } else if (type === 'str') { - val = String(val); - } else if (type === 'func') { + }); + } else if (type === 'int') { + setter = make_setter(function (val) { return parseInt(val, 10); }); + } else if (type === 'float') { + setter = make_setter(parseFloat); + } else if (type === 'str') { + setter = make_setter(String); + } else if (type === 'func') { + setter = make_setter(function (val) { if (!val) { - val = function () {}; + return function () {}; + } else { + return val; } - } - if (typeof idx !== 'undefined') { - cfg[v][idx] = val; - } else { - cfg[v] = val; - } - }; - - // Set the description - api[v + '_description'] = desc; + }); + } else if (type === 'arr' || type === 'dom' || type == 'raw') { + setter = make_setter(); + } else { + throw new Error('Unknown property type ' + type); // some sanity checking + } - // Set the getter function - if (typeof api['get_' + v] === 'undefined') { - api['get_' + v] = getter; + // set the getter + if (typeof proto['get_' + name] === 'undefined') { + proto['get_' + name] = getter; } - // Set the setter function with extra sanity checks - if (typeof api['set_' + v] === 'undefined') { - api['set_' + v] = function (val, idx) { - if (mode in {'RO':1, 'ro':1}) { - throw(v + " is read-only"); - } else if ((mode in {'WO':1, 'wo':1}) && - (typeof cfg[v] !== 'undefined')) { - throw(v + " can only be set once"); - } - setter(val, idx); - }; + // set the setter if needed + if (typeof proto['set_' + name] === 'undefined') { + if (mode === 'rw') { + proto['set_' + name] = setter; + } else if (mode === 'wo') { + proto['set_' + name] = function (val, idx) { + if (typeof this['_' + name] !== 'undefined') { + throw new Error(name + " can only be set once"); + } + setter.call(this, val, idx); + }; + } } - // Set the default value - if (typeof defaults[v] !== 'undefined') { - defval = defaults[v]; - } else if ((type in {'arr':1, 'array':1}) && - (! (defval instanceof Array))) { - defval = []; + // make a special setter that we can use in set defaults + proto['_raw_set_' + name] = function (val, idx) { + setter.call(this, val, idx); + //delete this['_init_set_' + name]; // remove it after use + }; +}; + +Util.make_properties = function (constructor, arr) { + "use strict"; + for (var i = 0; i < arr.length; i++) { + Util.make_property(constructor.prototype, arr[i][0], arr[i][1], arr[i][2]); } - // Coerce existing setting to the right type - //Util.Debug("v: " + v + ", defval: " + defval + ", defaults[v]: " + defaults[v]); - setter(defval); }; -// Set group of configuration defaults -Util.conf_defaults = function(cfg, api, defaults, arr) { +Util.set_defaults = function (obj, conf, defaults) { + var defaults_keys = Object.keys(defaults); + var conf_keys = Object.keys(conf); + var keys_obj = {}; var i; - for (i = 0; i < arr.length; i++) { - Util.conf_default(cfg, api, defaults, arr[i][0], arr[i][1], - arr[i][2], arr[i][3], arr[i][4]); + for (i = 0; i < defaults_keys.length; i++) { keys_obj[defaults_keys[i]] = 1; } + for (i = 0; i < conf_keys.length; i++) { keys_obj[conf_keys[i]] = 1; } + var keys = Object.keys(keys_obj); + + for (i = 0; i < keys.length; i++) { + var setter = obj['_raw_set_' + keys[i]]; + + if (conf[keys[i]]) { + setter.call(obj, conf[keys[i]]); + } else { + setter.call(obj, defaults[keys[i]]); + } } }; /* * Decode from UTF-8 */ -Util.decodeUTF8 = function(utf8string) { +Util.decodeUTF8 = function (utf8string) { + "use strict"; return decodeURIComponent(escape(utf8string)); -} +}; @@ -291,42 +371,46 @@ Util.decodeUTF8 = function(utf8string) { // Handles the case where load_scripts is invoked from a script that // itself is loaded via load_scripts. Once all scripts are loaded the // window.onscriptsloaded handler is called (if set). -Util.get_include_uri = function() { +Util.get_include_uri = function () { return (typeof INCLUDE_URI !== "undefined") ? INCLUDE_URI : "include/"; -} +}; Util._loading_scripts = []; Util._pending_scripts = []; -Util.load_scripts = function(files) { +Util.load_scripts = function (files) { + "use strict"; var head = document.getElementsByTagName('head')[0], script, ls = Util._loading_scripts, ps = Util._pending_scripts; - for (var f=0; f<files.length; f++) { + + var loadFunc = function (e) { + while (ls.length > 0 && (ls[0].readyState === 'loaded' || + ls[0].readyState === 'complete')) { + // For IE, append the script to trigger execution + var s = ls.shift(); + //console.log("loaded script: " + s.src); + head.appendChild(s); + } + if (!this.readyState || + (Util.Engine.presto && this.readyState === 'loaded') || + this.readyState === 'complete') { + if (ps.indexOf(this) >= 0) { + this.onload = this.onreadystatechange = null; + //console.log("completed script: " + this.src); + ps.splice(ps.indexOf(this), 1); + + // Call window.onscriptsload after last script loads + if (ps.length === 0 && window.onscriptsload) { + window.onscriptsload(); + } + } + } + }; + + for (var f = 0; f < files.length; f++) { script = document.createElement('script'); script.type = 'text/javascript'; script.src = Util.get_include_uri() + files[f]; //console.log("loading script: " + script.src); - script.onload = script.onreadystatechange = function (e) { - while (ls.length > 0 && (ls[0].readyState === 'loaded' || - ls[0].readyState === 'complete')) { - // For IE, append the script to trigger execution - var s = ls.shift(); - //console.log("loaded script: " + s.src); - head.appendChild(s); - } - if (!this.readyState || - (Util.Engine.presto && this.readyState === 'loaded') || - this.readyState === 'complete') { - if (ps.indexOf(this) >= 0) { - this.onload = this.onreadystatechange = null; - //console.log("completed script: " + this.src); - ps.splice(ps.indexOf(this), 1); - - // Call window.onscriptsload after last script loads - if (ps.length === 0 && window.onscriptsload) { - window.onscriptsload(); - } - } - } - }; + script.onload = script.onreadystatechange = loadFunc; // In-order script execution tricks if (Util.Engine.trident) { // For IE wait until readyState is 'loaded' before @@ -341,20 +425,22 @@ Util.load_scripts = function(files) { } ps.push(script); } -} +}; // Get DOM element position on page // This solution is based based on http://www.greywyvern.com/?post=331 // Thanks to Brian Huisman AKA GreyWyvern! -Util.getPosition = (function() { +Util.getPosition = (function () { + "use strict"; function getStyle(obj, styleProp) { + var y; if (obj.currentStyle) { - var y = obj.currentStyle[styleProp]; + y = obj.currentStyle[styleProp]; } else if (window.getComputedStyle) - var y = window.getComputedStyle(obj, null)[styleProp]; + y = window.getComputedStyle(obj, null)[styleProp]; return y; - }; + } function scrollDist() { var myScrollTop = 0, myScrollLeft = 0; @@ -383,7 +469,7 @@ Util.getPosition = (function() { } return [myScrollLeft, myScrollTop]; - }; + } return function (obj) { var curleft = 0, curtop = 0, scr = obj, fixed = false; @@ -403,7 +489,7 @@ Util.getPosition = (function() { do { curleft += obj.offsetLeft; curtop += obj.offsetTop; - } while (obj = obj.offsetParent); + } while ((obj = obj.offsetParent)); return {'x': curleft, 'y': curtop}; }; @@ -412,6 +498,7 @@ Util.getPosition = (function() { // Get mouse event position in DOM element Util.getEventPosition = function (e, obj, scale) { + "use strict"; var evt, docX, docY, pos; //if (!e) evt = window.event; evt = (e ? e : window.event); @@ -431,38 +518,41 @@ Util.getEventPosition = function (e, obj, scale) { } var realx = docX - pos.x; var realy = docY - pos.y; - var x = Math.max(Math.min(realx, obj.width-1), 0); - var y = Math.max(Math.min(realy, obj.height-1), 0); + var x = Math.max(Math.min(realx, obj.width - 1), 0); + var y = Math.max(Math.min(realy, obj.height - 1), 0); return {'x': x / scale, 'y': y / scale, 'realx': realx / scale, 'realy': realy / scale}; }; // Event registration. Based on: http://www.scottandrew.com/weblog/articles/cbs-events -Util.addEvent = function (obj, evType, fn){ - if (obj.attachEvent){ - var r = obj.attachEvent("on"+evType, fn); +Util.addEvent = function (obj, evType, fn) { + "use strict"; + if (obj.attachEvent) { + var r = obj.attachEvent("on" + evType, fn); return r; - } else if (obj.addEventListener){ - obj.addEventListener(evType, fn, false); + } else if (obj.addEventListener) { + obj.addEventListener(evType, fn, false); return true; } else { - throw("Handler could not be attached"); + throw new Error("Handler could not be attached"); } }; -Util.removeEvent = function(obj, evType, fn){ - if (obj.detachEvent){ - var r = obj.detachEvent("on"+evType, fn); +Util.removeEvent = function (obj, evType, fn) { + "use strict"; + if (obj.detachEvent) { + var r = obj.detachEvent("on" + evType, fn); return r; - } else if (obj.removeEventListener){ + } else if (obj.removeEventListener) { obj.removeEventListener(evType, fn, false); return true; } else { - throw("Handler could not be removed"); + throw new Error("Handler could not be removed"); } }; -Util.stopEvent = function(e) { +Util.stopEvent = function (e) { + "use strict"; if (e.stopPropagation) { e.stopPropagation(); } else { e.cancelBubble = true; } @@ -474,41 +564,88 @@ Util.stopEvent = function(e) { // Set browser engine versions. Based on mootools. Util.Features = {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)}; -Util.Engine = { - // Version detection break in Opera 11.60 (errors on arguments.callee.caller reference) - //'presto': (function() { - // return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925)); }()), - 'presto': (function() { return (!window.opera) ? false : true; }()), - - 'trident': (function() { - return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? ((document.querySelectorAll) ? 6 : 5) : 4); }()), - 'webkit': (function() { - try { return (navigator.taintEnabled) ? false : ((Util.Features.xpath) ? ((Util.Features.query) ? 525 : 420) : 419); } catch (e) { return false; } }()), - //'webkit': (function() { - // return ((typeof navigator.taintEnabled !== "unknown") && navigator.taintEnabled) ? false : ((Util.Features.xpath) ? ((Util.Features.query) ? 525 : 420) : 419); }()), - 'gecko': (function() { - return (!document.getBoxObjectFor && window.mozInnerScreenX == null) ? false : ((document.getElementsByClassName) ? 19 : 18); }()) -}; -if (Util.Engine.webkit) { - // Extract actual webkit version if available - Util.Engine.webkit = (function(v) { - var re = new RegExp('WebKit/([0-9\.]*) '); - v = (navigator.userAgent.match(re) || ['', v])[1]; - return parseFloat(v, 10); - })(Util.Engine.webkit); -} +(function () { + "use strict"; + // 'presto': (function () { return (!window.opera) ? false : true; }()), + var detectPresto = function () { + return !!window.opera; + }; + + // 'trident': (function () { return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? ((document.querySelectorAll) ? 6 : 5) : 4); + var detectTrident = function () { + if (!window.ActiveXObject) { + return false; + } else { + if (window.XMLHttpRequest) { + return (document.querySelectorAll) ? 6 : 5; + } else { + return 4; + } + } + }; + + // 'webkit': (function () { try { return (navigator.taintEnabled) ? false : ((Util.Features.xpath) ? ((Util.Features.query) ? 525 : 420) : 419); } catch (e) { return false; } }()), + var detectInitialWebkit = function () { + try { + if (navigator.taintEnabled) { + return false; + } else { + if (Util.Features.xpath) { + return (Util.Features.query) ? 525 : 420; + } else { + return 419; + } + } + } catch (e) { + return false; + } + }; + + var detectActualWebkit = function (initial_ver) { + var re = /WebKit\/([0-9\.]*) /; + var str_ver = (navigator.userAgent.match(re) || ['', initial_ver])[1]; + return parseFloat(str_ver, 10); + }; + + // 'gecko': (function () { return (!document.getBoxObjectFor && window.mozInnerScreenX == null) ? false : ((document.getElementsByClassName) ? 19ssName) ? 19 : 18 : 18); }()) + var detectGecko = function () { + /* jshint -W041 */ + if (!document.getBoxObjectFor && window.mozInnerScreenX == null) { + return false; + } else { + return (document.getElementsByClassName) ? 19 : 18; + } + /* jshint +W041 */ + }; + + Util.Engine = { + // Version detection break in Opera 11.60 (errors on arguments.callee.caller reference) + //'presto': (function() { + // return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925)); }()), + 'presto': detectPresto(), + 'trident': detectTrident(), + 'webkit': detectInitialWebkit(), + 'gecko': detectGecko(), + }; + + if (Util.Engine.webkit) { + // Extract actual webkit version if available + Util.Engine.webkit = detectActualWebkit(Util.Engine.webkit); + } +})(); -Util.Flash = (function(){ +Util.Flash = (function () { + "use strict"; var v, version; try { v = navigator.plugins['Shockwave Flash'].description; - } catch(err1) { + } catch (err1) { try { v = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version'); - } catch(err2) { + } catch (err2) { v = '0 r0'; } } version = v.match(/\d+/g); return {version: parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build: parseInt(version[2], 10) || 0}; -}()); +}()); diff --git a/tests/test.util.js b/tests/test.util.js new file mode 100644 index 0000000..63f51b7 --- /dev/null +++ b/tests/test.util.js @@ -0,0 +1,105 @@ +// requires local modules: util +/* jshint expr: true */ + +var assert = chai.assert; +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, 'warn'); + sinon.spy(console, 'error'); + }); + + afterEach(function () { + console.log.restore(); + console.warn.restore(); + console.error.restore(); + }); + + it('should use noop for levels lower than the min level', function () { + Util.init_logging('warn'); + Util.Debug('hi'); + Util.Info('hello'); + expect(console.log).to.not.have.been.called; + }); + + it('should use console.log for Debug and Info', function () { + Util.init_logging('debug'); + Util.Debug('dbg'); + Util.Info('inf'); + expect(console.log).to.have.been.calledWith('dbg'); + expect(console.log).to.have.been.calledWith('inf'); + }); + + it('should use console.warn for Warn', function () { + Util.init_logging('warn'); + Util.Warn('wrn'); + expect(console.warn).to.have.been.called; + expect(console.warn).to.have.been.calledWith('wrn'); + }); + + it('should use console.error for Error', function () { + Util.init_logging('error'); + Util.Error('err'); + expect(console.error).to.have.been.called; + expect(console.error).to.have.been.calledWith('err'); + }); + }); + + // TODO(directxman12): test the conf_default and conf_defaults methods + // TODO(directxman12): test decodeUTF8 + // TODO(directxman12): test the event methods (addEvent, removeEvent, stopEvent) + // TODO(directxman12): figure out a good way to test getPosition and getEventPosition + // 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 +}); |