Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

331 lines (265 sloc) 9.842 kb
###
Copyright (c) 2011 Niclas Hoyer
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
###
# This file exports some general nodeunit testcases for the onion.
# First, we define a wrapper for simpler handling of nodeunit test cases in
# coffeescript. It takes a name and a testcase as function and exports it as
# a nodeunit test.
test = (name, testcase) ->
exports[name] = (test) ->
testcase.call test
test.done()
# Require local Onion prototype.
Onion = require "../lib/Onion"
# # Naming #
# Test if all methods and public attributes have correct names.
test "signature", ->
onion = new Onion
@ok onion.stack instanceof Function, "stack method"
@ok onion.construct instanceof Function, "construct method"
@ok onion.peel instanceof Function, "peel method"
@ok onion.peelFor instanceof Function, "peelFor method"
@ok onion.innermost instanceof Function, "innermost function"
@ok onion.skins instanceof Object, "skin stack"
# # Simple stacking #
# Add a function as skin and check if it occurs in the skin array afterwards.
test "simple stacking", ->
onion = new Onion
# We add a skin, that just prints out `42` to the console.
bar = -> console.log 42
# After adding the skin, the array of skins should contain our skin.
skins = _all:[], foo: [bar]
# So, let's stack our function on event `foo` and
onion.stack "foo", bar
# check for equality.
@deepEqual onion.skins, skins, "skins of onion after stacking one skin"
# # Simple peeling #
# Add a function as skin and call it afterwards.
# Peeling without a given event should use the `_all` event.
test "simple peeling", ->
onion = new Onion
# We define an object that should be set to true, after executing the
# middleware. If it is still false, after we peeled the onion, we know
# that something went wrong.
obj = false
# The middleware that gets stacked
f = ->
# sets the object to true and
obj = true
# returns 42.
42
# So let's stack the middleware and
onion.stack f
# peel the onion (Should use the `_all` event).
val = onion.peel()
# We've got to check if the object has been changed and
@ok obj, "executing simple middleware (_all event)"
# if the correct value from middleware is returned.
@equal val, 42, "return value of simple middleware (_all event)"
# # Next function #
# Extensive testing on the `next()` function.
test "next function", ->
onion = new Onion
# We first define 4 objects set to false. Each middleware should set one
# object to true.
obj1 = false
obj2 = false
obj3 = false
obj4 = false
# The first three middlewares set the corresponding object to true and call
# `next()`.
f1 = (next) ->
obj1 = true
next()
f2 = (next) ->
obj2 = true
next()
f3 = (next) ->
obj3 = true
next()
# The last middleware sets the last object to true and returns `23`.
f4 = (next) ->
obj4 = true
return 23
# We now stack all four middlewares at once and
onion.construct ->
return [f1,f2,f3,f4]
# peel the onion.
val = onion.peel()
# We first check if all middlewares got executed.
@ok obj1, "first middlewre executed"
@ok obj2, "second middlewre executed"
@ok obj3, "third middlewre executed"
@ok obj4, "last middlewre executed"
# Then we check if the return value is correct.
@equal val, 23, "return value of middleware, that does not call next"
# # Innermost function #
# If all middlewares call `next()` the innermost function will be called.
# The default innermost function should do nothing and return nothing. If
# we override the innermost function, it should be called.
test "innermost function", ->
onion = new Onion
# Our single middleware should just call `next()`.
f = (next) ->
next()
# We stack and
onion.stack f
# peel the onion.
val = onion.peel()
# The standard return value should be nothing (`undefined`).
@equal val, undefined, "return value of standard innermost skin"
# Now we try to replace the standard innermost skin with our own function
# that returns `42`.
onion.innermost = ->
return 42
# Peel the onion and
val = onion.peel()
# check if `42` is returned.
@equal val, 42, "return value of self defined innermost skin"
# # Peeling with arguments #
# Peeling is also possible with arguments that are passed to every
# middleware. We'll now test some simple cases.
test "peeling with arguments", ->
onion = new Onion
# We define two objects that will be set to true if the corresponding
# middleware is executed.
obj1 = false
obj2 = false
# Our first middleware will return `42` if the given value is `42` and
# otherwise will call `next()`.
f42 = (val,next) ->
obj1 = true
if val is 42
return 42
else
next()
# Our second middleware will do the same, but with `23`.
f23 = (val,next) ->
obj2 = true
if val is 23
return 23
else
next()
# We now stack both middlewares.
onion.stack f42
onion.stack f23
# First check if we peel with a value that is not 42 or 23 that nothing is
# returned, but both middlewares were executed.
@equal onion.peel(12), undefined, "value not matched"
@ok obj1, "first middleware executed"
@ok obj2, "second middleware executed"
# We set our objects to false again and test with `42` as value.
obj1 = false
obj2 = false
# Now the return value should be 42 and the second middleware should't been
# executed.
@equal onion.peel(42), 42, "first middleware returns a value"
@ok obj1, "first middleware executed"
@equal obj2, false, "second middleware is not executed"
# We reset our objects again and try to peel with `23`.
obj1 = true
obj2 = true
# Now both middlewares should be executed, but 23 returned.
@equal onion.peel(23), 23, "second middleware returns a value"
@ok obj1, "first middleware executed"
@ok obj2, "second middleware executed"
# # Advanced Stacking #
# Stacking can be tricky sometimes. Onion gives you several ways how you can
# add a middleware to an event. Mostly all of them are tested here.
test "advanced stacking", ->
# Our first simple middleware `foo` will just return the string `'foo'`.
foo = ->
return 'foo'
# Out second middleware will do the same, but as we named it `bar` it
# will return `'bar'`.
bar = ->
return 'bar'
# ## One middleware, one event ##
# We now try to stack one middleware on one event. Actually we stack foo
# on foo and bar on bar.
onion = new Onion
onion.construct ->
{event: 'foo', skin: foo}
onion.construct ->
{event: 'bar', skin: bar}
@equal onion.peelFor('foo'), 'foo', "peel for foo event"
@equal onion.peelFor('bar'), 'bar', "peel for bar event"
skins = _all: [], foo: [foo], bar: [bar]
@deepEqual skins, onion.skins, "foo and bar events in skins array"
# ## One middleware, multiple events ##
# Here we try to stack one middleware `foo` on the events `foo` and `bar`.
onion = new Onion
onion.construct ->
{event: ['foo', 'bar'], skin: foo}
@equal onion.peelFor('foo'), 'foo', "peel for foo event"
@equal onion.peelFor('bar'), 'foo', "peel for bar event"
skins = _all: [], foo: [foo], bar: [foo]
@deepEqual skins, onion.skins, "foo and bar events in skins array"
# ## Multiple middlewares, multiple events ##
# Of course it is also possible to combine both. So we now try to stack
# multiple middlewares on multiple events. If we now peel for `foo` or
# `bar`, both return values should be the same.
onion = new Onion
onion.construct ->
{event: ['foo', 'bar'], skin: [foo, bar]}
@equal onion.peelFor('foo'), 'foo', "peel for foo event"
@equal onion.peelFor('bar'), 'foo', "peerl for bar event"
skins = _all: [], foo: [foo,bar], bar: [foo,bar]
@deepEqual skins, onion.skins, "foo and bar events in skins array"
# # Double peeling #
# Usually you peel an onion just once. This test just ensures that the onion
# really just gets peeled once, that means that every middleware is just called
# once.
test "double peeling", ->
onion = new Onion
# We start with zero eggs.
eggs = 0
# We stack a skin to the onion that gives us exactly one egg.
onion.stack (next) ->
eggs++
next()
# We peel the onion and
onion.peel()
# ensure that we got exactly one egg.
@equal eggs, 1, "middleware executed once"
# # Error Handling #
# Just test the error handling, in case there is an error with the errors.
test "error handling", ->
onion = new Onion
# With start with zero eggs.
eggs = 0
# We stack a skin that throws an exception, the first egg.
onion.stack (next) ->
throw new Error 'One egg please!'
next()
# We stack a skin that returns an error to the next funtion, the second egg.
onion.stack (next) ->
next new Error 'Another egg please!'
# Our error handler counts the eggs.
onion.error = (next, err) ->
# Add one egg and
eggs++
# ignore the error.
next()
# We peel the onion and
onion.peel()
# ensure that there are exactly two eggs.
@equal eggs, 2, "two errors catched"
Jump to Line
Something went wrong with that request. Please try again.