-
-
Save phpnode/2bf86b9633032a51d036 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
### | |
# Assertations | |
Extremely simple (and fast) runtime assertions. | |
This implementation exposes an [[assert()]] function | |
that takes another function as its first argument. | |
If that function doesn't return a truthy value, | |
an [[assert.Error] AssertionError] error will be thrown with a message | |
indicating the source of the function that failed. | |
If the [[assert()]] function recieves two arguments, the first should | |
contain an informative message that provides more context about the failure, | |
and the assertion function should be passed as the second argument. | |
Assertions are enabled by default, but can be disabled | |
globally by setting [[assert.enabled]] to false. | |
Runtime assertions are not a substitute for proper unit tests. Instead | |
they can be thought of as a final layer of sanity checking. | |
It's also important to note that assertions are not a substitute | |
for user input validation. Assertions should be used to validate the | |
_developer's_ assumptions about the state of the program at a given point. | |
By liberally sprinkling assertions in your code, you can help ensure that | |
faulty assumptions - bugs, are found at their source. The alternative is | |
waiting (perhaps months or years!) for another function somewhere down the | |
stack to trigger the bug, something that might only occur under very specific, | |
hard to replicate circumstances. Assertions help expose these bugs early and | |
help you write more robust software as a result. | |
@see http://en.wikipedia.org/wiki/Assertion_(computing) | |
@name Assert | |
@example Assert that a function argument is the correct type. | |
class MyClass | |
# Initialize our example class | |
constructor: -> | |
@children = [] | |
# Add a child but only if it is an instance of MyClass | |
addChild: (child) -> | |
assert -> child instanceof MyClass | |
@children.push child | |
this | |
parent = new MyClass | |
child1 = new MyClass | |
child2 = {} | |
parent.addChild child1 # ok | |
parent.addChild child2 # throws an AssertionError | |
@it should let successful assertions pass | |
fn = -> | |
assert -> true | |
true | |
expect(fn()).to.be.true | |
@it should throw an error on unsuccessful assertions | |
fn = -> | |
assert -> false | |
true | |
expect(fn).to.throw assert.Error | |
@it should let me disable and re-enable assertions globally | |
assert.enabled = false | |
fn = -> | |
assert -> false | |
true | |
expect(fn()).to.be.true | |
# now re-enable | |
assert.enabled = true | |
expect(fn).to.throw assert.Error | |
### | |
module.exports = do (assert = null) -> | |
### | |
Declare our custom error class that will be thrown | |
when an assertion fails | |
### | |
class AssertionError extends Error | |
### | |
Initializes the assertion error. | |
@param {String} message the assertion message | |
@optional @param {Function} caller the original caller of [[assert()]] | |
this is optional but can really improve the quality of the stack | |
traces in some environments. | |
@it should do something correctly | |
true | |
### | |
constructor: (message, caller = arguments.callee) -> | |
@name = 'AssertionError' | |
@message = message | |
Error.call this, message | |
# Not all environments support captureStackTrace | |
Error.captureStackTrace? this, caller | |
### | |
Our main assert function. Takes | |
a function as its sole argument. | |
That function should return something | |
truthy or the assertion will fail. | |
@param {Function} assertion the function that should return a truthy value | |
@throws {AssertionError} the assertion error if the assertion fails | |
### | |
assert = (args...) -> | |
return true unless assert.enabled | |
if args.length is 2 | |
assertion = args[1] | |
message = args[0] | |
else | |
assertion = args[0] | |
message = assert.stringify assertion | |
throw new AssertionError message, arguments.callee if not assertion() | |
### | |
Track whether assertions are enabled or disabled | |
@var {Boolean} | |
### | |
assert.enabled = true | |
### | |
Make our error class available to the outside so that | |
it's possible to check for failed assertions. | |
This is mostly useful for unit testing. You should not | |
try and catch assertion errors in your application code, | |
if you're doing that, you're probably using assertions incorrectly. | |
@var {AssertionError} | |
### | |
assert.Error = AssertionError | |
### | |
Take an assertion function and return a nicer | |
human readable version of it. If the function | |
contains a single return expression, that expression | |
will be used as the string representation. | |
@param {Function} fn the function to stringify | |
@it should return only the last return expression for simple assertions | |
fn = -> | |
foo = "something irrelevant" | |
true | |
assert.stringify(fn).should.equal "true" | |
@it should return all the source if there are multiple returns | |
fn = -> | |
if true | |
true | |
else | |
false | |
result = assert.stringify(fn).replace /(\s+)/g, '' | |
result.should.equal """ | |
if (true) { | |
return true; | |
} | |
else { | |
return false; | |
} | |
""".replace /(\s+)/g, '' | |
### | |
assert.stringify = (fn) -> | |
contents = fn.toString() | |
contents = (contents.substring contents.indexOf("{") + 1, contents.lastIndexOf("}")).trim() | |
regex = /^(\s+)?return(\s+)(.*)/mg | |
returns = [] | |
while (statement = regex.exec contents) | |
if statement[3].substr(-1) is ';' | |
returns.push statement[3].substr 0, statement[3].length - 1 | |
else | |
returns.push statement[3] | |
if returns.length is 1 | |
returns[0] | |
else | |
contents | |
### | |
Return the assert function to be exported | |
### | |
assert |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment