1
0
Fork 0
mirror of https://github.com/jashkenas/coffeescript.git synced 2022-11-09 12:23:24 -05:00
jashkenas--coffeescript/test/function_invocation.coffee

446 lines
8.3 KiB
CoffeeScript
Raw Normal View History

2010-12-29 14:06:57 -05:00
# Function Invocation
# -------------------
# * Function Invocation
# * Splats in Function Invocations
# * Implicit Returns
# * Explicit Returns
# shared identity function
2011-03-11 22:18:22 -05:00
id = (_) -> if arguments.length is 1 then _ else [arguments...]
2010-12-29 14:06:57 -05:00
test "basic argument passing", ->
2011-03-11 22:18:22 -05:00
2010-12-29 14:06:57 -05:00
a = {}
b = {}
c = {}
eq 1, (id 1)
eq 2, (id 1, 2)[1]
eq a, (id a)
eq c, (id a, b, c)[2]
2011-03-11 22:18:22 -05:00
2010-12-29 14:06:57 -05:00
test "passing arguments on separate lines", ->
2011-03-11 22:18:22 -05:00
2010-12-29 14:06:57 -05:00
a = {}
b = {}
c = {}
ok(id(
a
b
c
)[1] is b)
eq(0, id(
0
10
)[0])
eq(a,id(
a
))
eq b,
(id b)
2011-03-11 22:18:22 -05:00
2010-12-29 14:06:57 -05:00
test "optional parens can be used in a nested fashion", ->
2011-03-11 22:18:22 -05:00
2010-12-29 14:06:57 -05:00
call = (func) -> func()
add = (a,b) -> a + b
result = call ->
inner = call ->
add 5, 5
ok result is 10
2011-03-11 22:18:22 -05:00
test "hanging commas and semicolons in argument list", ->
2011-03-11 22:18:22 -05:00
fn = () -> arguments.length
eq 2, fn(0,1,)
eq 3, fn 0, 1,
2
eq 2, fn(0, 1;)
# TODO: this test fails (the string compiles), but should it?
#throws -> CoffeeScript.compile "fn(0,1,;)"
throws -> CoffeeScript.compile "fn(0,1,;;)"
throws -> CoffeeScript.compile "fn(0, 1;,)"
throws -> CoffeeScript.compile "fn(,0)"
throws -> CoffeeScript.compile "fn(;0)"
2010-12-30 22:48:31 -05:00
2011-03-11 22:18:22 -05:00
test "function invocation", ->
func = ->
return if true
eq undefined, func()
result = ("hello".slice) 3
ok result is 'lo'
test "And even with strange things like this:", ->
2010-12-29 14:06:57 -05:00
2011-03-11 22:18:22 -05:00
funcs = [((x) -> x), ((x) -> x * x)]
result = funcs[1] 5
ok result is 25
2010-12-29 14:06:57 -05:00
2011-03-11 22:18:22 -05:00
test "More fun with optional parens.", ->
fn = (arg) -> arg
ok fn(fn {prop: 101}).prop is 101
okFunc = (f) -> ok(f())
okFunc -> true
2010-12-30 22:48:31 -05:00
test "chained function calls", ->
nonce = {}
identityWrap = (x) ->
-> x
eq nonce, identityWrap(identityWrap(nonce))()()
eq nonce, (identityWrap identityWrap nonce)()()
2011-03-11 22:18:22 -05:00
test "Multi-blocks with optional parens.", ->
fn = (arg) -> arg
result = fn( ->
fn ->
"Wrapped"
)
ok result()() is 'Wrapped'
test "method calls", ->
fnId = (fn) -> -> fn.apply this, arguments
math = {
add: (a, b) -> a + b
anonymousAdd: (a, b) -> a + b
fastAdd: fnId (a, b) -> a + b
}
ok math.add(5, 5) is 10
ok math.anonymousAdd(10, 10) is 20
ok math.fastAdd(20, 20) is 40
test "Ensure that functions can have a trailing comma in their argument list", ->
mult = (x, mids..., y) ->
x *= n for n in mids
x *= y
ok mult(1, 2,) is 2
ok mult(1, 2, 3,) is 6
ok mult(10, (i for i in [1..6])...) is 7200
2010-12-29 14:06:57 -05:00
test "`@` and `this` should both be able to invoke a method", ->
nonce = {}
fn = (arg) -> eq nonce, arg
fn.withAt = -> @ nonce
fn.withThis = -> this nonce
fn.withAt()
fn.withThis()
2011-03-11 22:18:22 -05:00
test "Trying an implicit object call with a trailing function.", ->
a = null
meth = (arg, obj, func) -> a = [obj.a, arg, func()].join ' '
meth 'apple', b: 1, a: 13, ->
2011-03-11 22:18:22 -05:00
'orange'
ok a is '13 apple orange'
test "Ensure that empty functions don't return mistaken values.", ->
obj =
func: (@param, @rest...) ->
ok obj.func(101, 102, 103, 104) is undefined
ok obj.param is 101
ok obj.rest.join(' ') is '102 103 104'
test "Passing multiple functions without paren-wrapping is legal, and should compile.", ->
sum = (one, two) -> one() + two()
result = sum ->
7 + 9
, ->
1 + 3
ok result is 20
test "Implicit call with a trailing if statement as a param.", ->
func = -> arguments[1]
result = func 'one', if false then 100 else 13
ok result is 13
test "Test more function passing:", ->
sum = (one, two) -> one() + two()
result = sum( ->
1 + 2
, ->
2 + 1
2010-12-30 22:48:31 -05:00
)
2011-03-11 22:18:22 -05:00
ok result is 6
sum = (a, b) -> a + b
result = sum(1
, 2)
ok result is 3
test "Chained blocks, with proper indentation levels:", ->
counter =
results: []
tick: (func) ->
@results.push func()
this
counter
.tick ->
3
.tick ->
2
.tick ->
1
arrayEq [3,2,1], counter.results
2010-12-30 22:48:31 -05:00
2011-03-11 22:18:22 -05:00
test "This is a crazy one.", ->
x = (obj, func) -> func obj
ident = (x) -> x
result = x {one: ident 1}, (obj) ->
inner = ident(obj)
ident inner
ok result.one is 1
test "More paren compilation tests:", ->
reverse = (obj) -> obj.reverse()
ok reverse([1, 2].concat 3).join(' ') is '3 2 1'
test "Test for inline functions with parentheses and implicit calls.", ->
combine = (func, num) -> func() * num
result = combine (-> 1 + 2), 3
ok result is 9
test "Test for calls/parens/multiline-chains.", ->
f = (x) -> x
result = (f 1).toString()
.length
ok result is 1
test "Test implicit calls in functions in parens:", ->
result = ((val) ->
[].push val
val
)(10)
ok result is 10
test "Ensure that chained calls with indented implicit object literals below are alright.", ->
result = null
obj =
method: (val) -> this
second: (hash) -> result = hash.three
2010-12-30 22:48:31 -05:00
obj
2011-03-11 22:18:22 -05:00
.method(
101
).second(
one:
two: 2
three: 3
)
eq result, 3
test "Test newline-supressed call chains with nested functions.", ->
obj =
call: -> this
func = ->
obj
.call ->
one two
.call ->
three four
101
eq func(), 101
test "Implicit objects with number arguments.", ->
func = (x, y) -> y
obj =
prop: func "a", 1
ok obj.prop is 1
test "Non-spaced unary and binary operators should cause a function call.", ->
func = (val) -> val + 1
ok (func +5) is 6
ok (func -5) is -4
test "Prefix unary assignment operators are allowed in parenless calls.", ->
func = (val) -> val + 1
val = 5
ok (func --val) is 5
2010-12-30 22:48:31 -05:00
test "#855: execution context for `func arr...` should be `null`", ->
2011-05-01 08:28:00 -04:00
contextTest = -> eq @, if window? then window else global
2010-12-30 22:48:31 -05:00
array = []
contextTest array
contextTest.apply null, array
contextTest array...
test "#904: Destructuring function arguments with same-named variables in scope", ->
a = b = nonce = {}
fn = ([a,b]) -> {a:a,b:b}
result = fn([c={},d={}])
eq c, result.a
eq d, result.b
eq nonce, a
eq nonce, b
2011-03-11 22:18:22 -05:00
test "caching base value", ->
obj =
index: 0
0: {method: -> this is obj[0]}
ok obj[obj.index++].method([]...)
2010-12-30 22:48:31 -05:00
test "passing splats to functions", ->
arrayEq [0..4], id id [0..4]...
fn = (a, b, c..., d) -> [a, b, c, d]
range = [0..3]
[first, second, others, last] = fn range..., 4, [5...8]...
eq 0, first
eq 1, second
arrayEq [2..6], others
eq 7, last
test "splat variables are local to the function", ->
outer = "x"
clobber = (avar, outer...) -> outer
clobber "foo", "bar"
eq "x", outer
2011-03-11 22:18:22 -05:00
test "Issue 894: Splatting against constructor-chained functions.", ->
x = null
class Foo
bar: (y) -> x = y
new Foo().bar([101]...)
eq x, 101
test "Functions with splats being called with too few arguments.", ->
pen = null
method = (first, variable..., penultimate, ultimate) ->
pen = penultimate
method 1, 2, 3, 4, 5, 6, 7, 8, 9
ok pen is 8
method 1, 2, 3
ok pen is 2
method 1, 2
ok pen is 2
test "splats with super() within classes.", ->
class Parent
meth: (args...) ->
args
class Child extends Parent
meth: ->
nums = [3, 2, 1]
super nums...
ok (new Child).meth().join(' ') is '3 2 1'
2010-12-30 22:48:31 -05:00
2011-01-06 12:38:40 -05:00
test "#1011: passing a splat to a method of a number", ->
eq '1011', 11.toString [2]...
eq '1011', (31).toString [3]...
eq '1011', 69.0.toString [4]...
eq '1011', (131.0).toString [5]...
2010-12-30 22:48:31 -05:00
2011-03-11 22:18:22 -05:00
test "implicit return", ->
eq ok, new ->
ok
### Should `return` implicitly ###
### even with trailing comments. ###
2010-12-30 22:48:31 -05:00
test "implicit returns with multiple branches", ->
nonce = {}
fn = ->
if false
for a in b
return c if d
else
nonce
eq nonce, fn()
2011-03-11 22:18:22 -05:00
test "implicit returns with switches", ->
nonce = {}
fn = ->
switch nonce
when nonce then nonce
else return undefined
eq nonce, fn()
2011-03-11 22:18:22 -05:00
test "preserve context when generating closure wrappers for expression conversions", ->
nonce = {}
obj =
property: nonce
method: ->
this.result = if false
10
else
"a"
"b"
this.property
eq nonce, obj.method()
eq nonce, obj.property
2011-03-11 22:18:22 -05:00
test "don't wrap 'pure' statements in a closure", ->
nonce = {}
items = [0, 1, 2, 3, nonce, 4, 5]
fn = (items) ->
for item in items
return item if item is nonce
eq nonce, fn items
#### Unusual `new` Usage
test "usage of `new` is careful about where the invocation parens end up", ->
eq 'object', typeof new try Array
eq 'object', typeof new do -> ->