branch: master commit 86156882943ac3a70c46990c8cd66216e5cd1d51 Author: Jackson Ray Hamilton <jack...@jacksonrayhamilton.com> Commit: Jackson Ray Hamilton <jack...@jacksonrayhamilton.com>
Create tests. --- test/context-coloring-test.el | 46 ++++++- test/fixtures/nested.el | 34 +++++ test/fixtures/{nest.js => nested.js} | 2 +- test/fixtures/scopes.el | 10 ++ test/fixtures/vow.el | 272 ++++++++++++++++++++++++++++++++++ 5 files changed, 360 insertions(+), 4 deletions(-) diff --git a/test/context-coloring-test.el b/test/context-coloring-test.el index 7bd0b2c..a8588fb 100644 --- a/test/context-coloring-test.el +++ b/test/context-coloring-test.el @@ -1,3 +1,43 @@ -(ert-deftest context-coloring-test-color () - "Tests something. Not sure what yet." - (should (equal t t))) +(defconst context-coloring-path + (file-name-directory (or load-file-name buffer-file-name))) + +(defun context-coloring-test-resolve-path (path) + (expand-file-name path context-coloring-path)) + +;; Load expected output constants. +(load-file (context-coloring-test-resolve-path "./fixtures/scopes.el")) +(load-file (context-coloring-test-resolve-path "./fixtures/nested.el")) +(load-file (context-coloring-test-resolve-path "./fixtures/vow.el")) + +(defun get-string-from-file (path) + (with-temp-buffer + (insert-file-contents path) + (buffer-string))) + +(defun context-coloring-test-read-file (path) + (get-string-from-file (context-coloring-test-resolve-path path))) + +(defmacro context-coloring-test-with-fixture (fixture &rest body) + "Evaluate BODY in a temporary buffer with the relative +FIXTURE." + `(with-temp-buffer + (insert (context-coloring-test-read-file ,fixture)) + (context-coloring-mode) + ,@body)) + +(ert-deftest context-coloring-test-scopes () + (context-coloring-test-with-fixture "./fixtures/scopes.js" + (should (equal (buffer-substring (point-min) (point-max)) + context-coloring-test-expected-scopes)))) + +(ert-deftest context-coloring-test-nested () + (context-coloring-test-with-fixture "./fixtures/nested.js" + (should (equal (buffer-substring (point-min) (point-max)) + context-coloring-test-expected-nested)))) + +(ert-deftest context-coloring-test-vow () + (context-coloring-test-with-fixture "./fixtures/vow.js" + (should (equal (buffer-substring (point-min) (point-max)) + context-coloring-test-expected-vow)))) + +(provide 'context-coloring-test) diff --git a/test/fixtures/nested.el b/test/fixtures/nested.el new file mode 100644 index 0000000..076e6ac --- /dev/null +++ b/test/fixtures/nested.el @@ -0,0 +1,34 @@ +(defconst context-coloring-test-expected-nested + #("function a() { + var A = a; + function b() { + var B = b; + function c() { + var C = c; + function d() { + var D = d; + function e() { + var E = e; + function f() { + var F = f; + function g() { + var G = g; + function h() { + var H = [ + A, + B, + C, + D, + E, + F, + G + ]; + } + } + } + } + } + } + } +} +" 0 8 (font-lock-face font-lock-keyword-face fontified nil face context-coloring-depth-1-face rear-nonsticky t) 8 9 (fontified nil face context-coloring-depth-1-face rear-nonsticky t) 9 10 (font-lock-face font-lock-function-name-face fontified nil face context-coloring-depth-0-bold-face rear-nonsticky t) 10 19 (fontified nil face context-coloring-depth-1-face rear-nonsticky t) 19 22 (font-lock-face font-lock-keyword-face fontified nil face context-coloring-depth-1-face rear-nonsticky t) [...] diff --git a/test/fixtures/nest.js b/test/fixtures/nested.js similarity index 98% rename from test/fixtures/nest.js rename to test/fixtures/nested.js index 2e79213..1621e06 100644 --- a/test/fixtures/nest.js +++ b/test/fixtures/nested.js @@ -1,5 +1,5 @@ function a() { - var A = a(); + var A = a; function b() { var B = b; function c() { diff --git a/test/fixtures/scopes.el b/test/fixtures/scopes.el new file mode 100644 index 0000000..eb94b6e --- /dev/null +++ b/test/fixtures/scopes.el @@ -0,0 +1,10 @@ +(defconst context-coloring-test-expected-scopes + #("(function () { + var a; + var b = 0; +}()); +var A; +var B = 1; +window.setTimeout(); +ooga = 2; +" 0 1 (fontified nil face context-coloring-depth-0-face rear-nonsticky t) 1 9 (font-lock-face font-lock-keyword-face fontified nil face context-coloring-depth-1-face rear-nonsticky t) 9 19 (fontified nil face context-coloring-depth-1-face rear-nonsticky t) 19 22 (font-lock-face font-lock-keyword-face fontified nil face context-coloring-depth-1-face rear-nonsticky t) 22 23 (fontified nil face context-coloring-depth-1-face rear-nonsticky t) 23 24 (font-lock-face font-lock-variable-name-fac [...] diff --git a/test/fixtures/vow.el b/test/fixtures/vow.el new file mode 100644 index 0000000..37c3440 --- /dev/null +++ b/test/fixtures/vow.el @@ -0,0 +1,272 @@ +(defconst context-coloring-test-expected-vow + #("// vow.js +// Douglas Crockford +// 2013-09-20 + +// Public Domain + +/*global setImmediate */ + + +var VOW = (function () { + 'use strict'; + +// The VOW object contains a .make function that is used to make vows. +// It may also contain other useful functions. +// In some mythologies, 'VOW' is called 'deferrer'. + + function enlighten(queue, fate) { + +// enlighten is a helper function of herald and .when. It schedules the +// processing of all of the resolution functions in either the keepers queue +// or the breakers queue in later turns with the promise's fate. + + queue.forEach(function (func) { + setImmediate(func, fate); + }); + } + + return { + make: function make() { + +// The make function makes new vows. A vow contains a promise object and the +// two resolution functions (break and keep) that determine the fate of the +// promise. + + var breakers = [], // .when's broken queue + fate, // The promise's ultimate value + keepers = [], // .when's kept queue + status = 'pending'; // 'broken', 'kept', or 'pending' + + function enqueue( + resolution, // 'keep' or 'break' + func, // A function that was registered with .when + vow // A vow that provides the resolution functions + ) { + +// enqueue is a helper function used by .when. It will append a function to +// either the keepers queue or the breakers queue. + + var queue = resolution === 'keep' ? keepers : breakers; + queue[queue.length] = typeof func !== 'function' + +// If func is not a function, push the resolver so that the value passes to +// the next cascaded .when. + + ? vow[resolution] + +// If the func is a function, push a function that calls func with a value. +// The result can be a promise, or not a promise, or an exception. + + : function (value) { + try { + var result = func(value); + +// If the result is a promise, then register our resolver with that promise. + + if (result && result.is_promise === true) { + result.when(vow.keep, vow.break); + +// But if it is not a promise, then use the result to resolve our promise. + + } else { + vow.keep(result); + } + +// But if func throws an exception, then break our promise. + + } catch (e) { + vow.break(e); + } + }; + } + + function herald(state, value, queue) { + +// The herald function is a helper function of break and keep. +// It seals the promise's fate, updates its status, enlightens +// one of the queues, and empties both queues. + + if (status !== 'pending') { + throw \"overpromise\"; + } + fate = value; + status = state; + enlighten(queue, fate); + keepers.length = 0; + breakers.length = 0; + } + +// Construct and return the vow object. + + return { + 'break': function (value) { + +// The break method breaks the promise. + + herald('broken', value, breakers); + }, + keep: function keep(value) { + +// The keep method keeps the promise. + + herald('kept', value, keepers); + }, + promise: { + +// The promise is an object with a .when method. + + is_promise: true, + +// The .when method is the promise monad's bind. The .when method can take two +// optional functions. One of those functions may be called, depending on the +// promise's resolution. Both could be called if the the kept function throws. + + when: function (kept, broken) { + +// Make a new vow. Return the new promise. + + var vow = make(); + switch (status) { + +// If this promise is still pending, then enqueue both kept and broken. + + case 'pending': + enqueue('keep', kept, vow); + enqueue('break', broken, vow); + break; + +// If the promise has already been kept, then enqueue only the kept function, +// and enlighten it. + + case 'kept': + enqueue('keep', kept, vow); + enlighten(keepers, fate); + break; + +// If the promise has already been broken, then enqueue only the broken +// function, and enlighten it. + + case 'broken': + enqueue('break', broken, vow); + enlighten(breakers, fate); + break; + } + return vow.promise; + } + } + }; + }, + every: function every(array) { + +// The every function takes an array of promises and returns a promise that +// will deliver an array of results only if every promise is kept. + + var remaining = array.length, results = [], vow = VOW.make(); + + if (!remaining) { + vow.break(array); + } else { + array.forEach(function (promise, i) { + promise.when(function (value) { + results[i] = value; + remaining -= 1; + if (remaining === 0) { + vow.keep(results); + } + }, function (reason) { + remaining = NaN; + vow.break(reason); + }); + }); + } + return vow.promise; + }, + first: function first(array) { + +// The first function takes an array of promises and returns a promise to +// deliver the first observed kept promise, or a broken promise if all of +// the promises are broken. + + var found = false, remaining = array.length, vow = VOW.make(); + + function check() { + remaining -= 1; + if (remaining === 0 && !found) { + vow.break(); + } + } + + if (remaining === 0) { + vow.break(array); + } else { + array.forEach(function (promise) { + promise.when(function (value) { + if (!found) { + found = true; + vow.keep(value); + } + check(); + }, check); + }); + } + return vow.promise; + }, + any: function any(array) { + +// The any function takes an array of promises and returns a promise that +// will deliver a possibly sparse array of results of any kept promises. +// The result will contain an undefined element for each broken promise. + + var remaining = array.length, results = [], vow = VOW.make(); + + function check() { + remaining -= 1; + if (remaining === 0) { + vow.keep(results); + } + } + + if (!remaining) { + vow.keep(results); + } else { + array.forEach(function (promise, i) { + promise.when(function (value) { + results[i] = value; + check(); + }, check); + }); + } + return vow.promise; + }, + kept: function (value) { + +// Returns a new kept promise. + + var vow = VOW.make(); + vow.keep(value); + return vow.promise; + }, + broken: function (reason) { + +// Returns a new broken promise. + + var vow = VOW.make(); + vow.break(reason); + return vow.promise; + } + }; +}()); + + +// If your system does not have setImmediate, then simulate it with setTimeout. + +if (typeof setImmediate !== 'function') { + setImmediate = function setImmediate(func, param) { + 'use strict'; + return setTimeout(function () { + func(param); + }, 0); + }; +} +" 0 9 (font-lock-face font-lock-comment-face fontified nil face context-coloring-depth--1-italic-face rear-nonsticky t) 9 10 (font-lock-face font-lock-comment-face fontified nil) 10 30 (font-lock-face font-lock-comment-face fontified nil face context-coloring-depth--1-italic-face rear-nonsticky t) 30 31 (font-lock-face font-lock-comment-face fontified nil) 31 44 (font-lock-face font-lock-comment-face fontified nil face context-coloring-depth--1-italic-face rear-nonsticky t) 44 45 (font-l [...]