test reorganization waypoint #2

This commit is contained in:
Michael Ficarra 2010-12-29 14:06:57 -05:00
parent a330eda4b6
commit fb201976b8
20 changed files with 371 additions and 317 deletions

View File

@ -1,127 +0,0 @@
# Arguments
# ---------
# shared identity function
id = (_) -> if arguments.length is 1 then _ else Array::slice.call(arguments)
test "basic argument passing tests", ->
a = {}
b = {}
c = {}
eq 1, (id 1)
eq 2, (id 1, 2)[1]
eq a, (id a)
eq c, (id a, b, c)[2]
test "passing arguments on separate lines", ->
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)
test "reference `arguments` inside of functions", ->
sumOfArgs = ->
sum = (a,b) -> a + b
sum = 0
sum += num for num in arguments
sum
eq 10, sumOfArgs(0, 1, 2, 3, 4)
#### Parameter List Features
test "splats", ->
arrayEq [0, 1, 2], (((splat...) -> splat) 0, 1, 2)
arrayEq [2, 3], (((_, _, splat...) -> splat) 0, 1, 2, 3)
arrayEq [0, 1], (((splat..., _, _) -> splat) 0, 1, 2, 3)
arrayEq [2], (((_, _, splat..., _) -> splat) 0, 1, 2, 3)
test "@-parameters: automatically assign an argument's value to a property of the context", ->
nonce = {}
((@prop) ->).call context = {}, nonce
eq nonce, context.prop
# allow splats along side the special argument
((splat..., @prop) ->).apply context = {}, [0, 0, nonce]
eq nonce, context.prop
# allow the argument itself to be a splat
((@prop...) ->).call context = {}, 0, nonce, 0
eq nonce, context.prop[1]
# the argument should still be able to be referenced normally
eq nonce, (((@prop) -> prop).call {}, nonce)
test "@-parameters and splats with constructors", ->
a = {}
b = {}
class Klass
constructor: (@first, splat..., @last) ->
obj = new Klass a, 0, 0, b
eq a, obj.first
eq b, obj.last
test "destructuring in function definition", ->
(([{a: [b], c}]...) ->
eq 1, b
eq 2, c
) {a: [1], c: 2}
test "default values", ->
nonceA = {}
nonceB = {}
a = (_,_,arg=nonceA) -> arg
eq nonceA, a()
eq nonceA, a(0)
eq nonceB, a(0,0,nonceB)
eq nonceA, a(0,0,undefined)
eq nonceA, a(0,0,null)
eq false , a(0,0,false)
eq nonceB, a(undefined,undefined,nonceB,undefined)
b = (_,arg=nonceA,_,_) -> arg
eq nonceA, b()
eq nonceA, b(0)
eq nonceB, b(0,nonceB)
eq nonceA, b(0,undefined)
eq nonceA, b(0,null)
eq false , b(0,false)
eq nonceB, b(undefined,nonceB,undefined)
c = (arg=nonceA,_,_) -> arg
eq nonceA, c()
eq 0, c(0)
eq nonceB, c(nonceB)
eq nonceA, c(undefined)
eq nonceA, c(null)
eq false , c(false)
eq nonceB, c(nonceB,undefined,undefined)
test "default values with @-parameters", ->
a = {}
b = {}
obj = f: (q = a, @p = b) -> q
eq a, obj.f()
eq b, obj.p
test "default values with splatted arguments", ->
withSplats = (a = 2, b..., c = 3, d = 5) -> a * (b.length + 1) * c * d
eq 30, withSplats()
eq 15, withSplats(1)
eq 5, withSplats(1,1)
eq 1, withSplats(1,1,1)
eq 2, withSplats(1,1,1,1)

View File

@ -1,124 +1,13 @@
x = 1
y = {}
y.x = -> 3
ok x is 1
ok typeof(y.x) is 'function'
ok y.x instanceof Function
ok y.x() is 3
# The empty function should not cause a syntax error.
->
() ->
# Multiple nested function declarations mixed with implicit calls should not
# cause a syntax error.
(one) -> (two) -> three four, (five) -> six seven, eight, (nine) ->
obj = {
name: 'Fred'
bound: ->
do (=> eq this, obj)
unbound: ->
do (-> ok this isnt obj)
nested: ->
(=>
do (=>
(=>
eq this, obj
)()
)
)()
}
obj.unbound()
obj.bound()
obj.nested()
# Python decorator style wrapper that memoizes any function
memoize = (fn) ->
cache = {}
self = this
(args...) ->
key = args.toString()
return cache[key] if cache[key]
cache[key] = fn.apply(self, args)
Math = {
Add: (a, b) -> a + b
AnonymousAdd: (a, b) -> a + b
FastAdd: memoize (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
okFunc = (f) -> ok(f())
okFunc -> true
# Optional parens can be used in a nested fashion.
call = (func) -> func()
result = call ->
inner = call ->
Math.Add(5, 5)
ok result is 10
# More fun with optional parens.
fn = (arg) -> arg
ok fn(fn {prop: 101}).prop is 101
# Multi-blocks with optional parens.
result = fn( ->
fn ->
"Wrapped"
)
ok result()() is 'Wrapped'
# And even with strange things like this:
funcs = [((x) -> x), ((x) -> x * x)]
result = funcs[1] 5
ok result is 25
result = ("hello".slice) 3
ok result is 'lo'
# And with multiple single-line functions on the same line.
func = (x) -> (x) -> (x) -> x
ok func(1)(2)(3) is 3
# Ensure that functions with the same name don't clash with helper functions.
del = -> 5
ok del() is 5
# 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
# Test for inline functions with parentheses and implicit calls.
combine = (func, num) -> func() * num
@ -148,83 +37,18 @@ ok result is 10
reverse = (obj) -> obj.reverse()
ok reverse([1, 2].concat 3).join(' ') is '3 2 1'
# 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
# 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 more function passing:
result = sum( ->
1 + 2
, ->
2 + 1
)
ok result is 6
sum = (a, b) -> a + b
result = sum(1
, 2)
ok result is 3
# 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
# Assignment to a Object.prototype-named variable should not leak to outer scope.
# FIXME: fails on IE
(->
constructor = 'word'
)()
ok constructor isnt 'word'
# 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, ->
'orange'
ok a is '13 apple orange'
# 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'
# `@` and `this` should both be able to invoke a method.
func = (arg) -> ok arg is true
func.withAt = -> @ true
func.withThis = -> this true
func.withAt()
func.withThis()
# Ensure that constructors invoked with splats return a new object.
@ -256,7 +80,6 @@ counter =
tick: (func) ->
@results.push func()
this
counter
.tick ->
3
@ -264,19 +87,9 @@ counter
2
.tick ->
1
eq counter.results.join(' '), '3 2 1'
# Make incorrect indentation safe.
func = ->
obj = {
key: 10
}
obj.key - 5
eq func(), 5
# Ensure that chained calls with indented implicit object literals below are
# alright.

View File

@ -0,0 +1,5 @@
# Array Literals
# --------------
# * Array Literals
# * Splats in Array Literals

View File

@ -1,7 +1,14 @@
# Assignment
# ----------
# TODO: organize assignment file
# * Assignment
# * Compound Assignment
# * Destructuring Assignment
# * Context Property (@) Assignment
# * Existential Assignment (?=)
test "context property assignment (using @)", ->
nonce = {}
addMethod = ->

View File

@ -1,6 +1,10 @@
# Classes
# -------
# * Class Definition
# * Class Instantiation
# * Inheritance and Super
# TODO: refactor class tests
# Test classes with a four-level inheritance chain.

0
test/command.coffee Normal file
View File

View File

@ -1,6 +1,9 @@
# Comments
# --------
# * Single-Line Comments
# * Block Comments
# Note: awkward spacing seen in some tests is likely intentional.
test "comments in objects", ->

View File

@ -1,6 +1,11 @@
# Comprehensions
# --------------
# * Array Comprehensions
# * Range Comprehensions
# * Object Comprehensions
# * Comprehensions with Nonstandard Step
# TODO: refactor comprehension tests
# Basic array comprehensions.

View File

@ -1,6 +1,14 @@
# Control Flow
# ------------
# * Conditionals
# * Loops
# * For
# * While
# * Until
# * Loop
# * Switch
# shared identity function
id = (_) -> if arguments.length is 1 then _ else Array::slice.call(arguments)

View File

@ -0,0 +1,7 @@
# Formatting
# ----------
# * Line Continuation (Property Accesss)
# * Line Continuation (Operators)
# * Line Continuation (Arrays)
# * Line Continuation (Function Invocations)

View File

@ -0,0 +1,133 @@
# Function Invocation
# -------------------
# * Function Invocation
# * Splats in Function Invocations
# * Implicit Returns
# * Explicit Returns
# shared identity function
id = (_) -> if arguments.length is 1 then _ else Array::slice.call(arguments)
test "basic argument passing", ->
a = {}
b = {}
c = {}
eq 1, (id 1)
eq 2, (id 1, 2)[1]
eq a, (id a)
eq c, (id a, b, c)[2]
test "passing arguments on separate lines", ->
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)
test "optional parens can be used in a nested fashion", ->
call = (func) -> func()
add = (a,b) -> a + b
result = call ->
inner = call ->
add 5, 5
ok result is 10
result = ("hello".slice) 3
ok result is 'lo'
# And even with strange things like this:
funcs = [((x) -> x), ((x) -> x * x)]
result = funcs[1] 5
ok result is 25
# More fun with optional parens.
fn = (arg) -> arg
ok fn(fn {prop: 101}).prop is 101
# Multi-blocks with optional parens.
result = fn( ->
fn ->
"Wrapped"
)
ok result()() is 'Wrapped'
# 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
# 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
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()
# 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, ->
'orange'
ok a is '13 apple orange'
# 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'
# 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
# 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 more function passing:
result = sum( ->
1 + 2
, ->
2 + 1
)
ok result is 6
sum = (a, b) -> a + b
result = sum(1
, 2)
ok result is 3

View File

@ -0,0 +1,143 @@
# Function Literals
# -----------------
# * Function Definition
# * Bound Function Definition
# * Parameter List Features
# * Splat Parameters
# * Context (@) Parameters
# * Parameter Destructuring
# * Default Parameters
#### Function Definition
x = 1
y = {}
y.x = -> 3
ok x is 1
ok typeof(y.x) is 'function'
ok y.x instanceof Function
ok y.x() is 3
# The empty function should not cause a syntax error.
->
() ->
# Multiple nested function declarations mixed with implicit calls should not
# cause a syntax error.
(one) -> (two) -> three four, (five) -> six seven, eight, (nine) ->
# with multiple single-line functions on the same line.
func = (x) -> (x) -> (x) -> x
ok func(1)(2)(3) is 3
# Make incorrect indentation safe.
func = ->
obj = {
key: 10
}
obj.key - 5
eq func(), 5
#### Bound Function Definition
obj =
bound: ->
(=> this)()
unbound: ->
(-> this)()
nested: ->
(=>
(=>
(=> this)()
)()
)()
eq obj, obj.bound()
ok obj isnt obj.unbound()
eq obj, obj.nested()
#### Parameter List Features
test "splats", ->
arrayEq [0, 1, 2], (((splat...) -> splat) 0, 1, 2)
arrayEq [2, 3], (((_, _, splat...) -> splat) 0, 1, 2, 3)
arrayEq [0, 1], (((splat..., _, _) -> splat) 0, 1, 2, 3)
arrayEq [2], (((_, _, splat..., _) -> splat) 0, 1, 2, 3)
test "@-parameters: automatically assign an argument's value to a property of the context", ->
nonce = {}
((@prop) ->).call context = {}, nonce
eq nonce, context.prop
# allow splats along side the special argument
((splat..., @prop) ->).apply context = {}, [0, 0, nonce]
eq nonce, context.prop
# allow the argument itself to be a splat
((@prop...) ->).call context = {}, 0, nonce, 0
eq nonce, context.prop[1]
# the argument should still be able to be referenced normally
eq nonce, (((@prop) -> prop).call {}, nonce)
test "@-parameters and splats with constructors", ->
a = {}
b = {}
class Klass
constructor: (@first, splat..., @last) ->
obj = new Klass a, 0, 0, b
eq a, obj.first
eq b, obj.last
test "destructuring in function definition", ->
(([{a: [b], c}]...) ->
eq 1, b
eq 2, c
) {a: [1], c: 2}
test "default values", ->
nonceA = {}
nonceB = {}
a = (_,_,arg=nonceA) -> arg
eq nonceA, a()
eq nonceA, a(0)
eq nonceB, a(0,0,nonceB)
eq nonceA, a(0,0,undefined)
eq nonceA, a(0,0,null)
eq false , a(0,0,false)
eq nonceB, a(undefined,undefined,nonceB,undefined)
b = (_,arg=nonceA,_,_) -> arg
eq nonceA, b()
eq nonceA, b(0)
eq nonceB, b(0,nonceB)
eq nonceA, b(0,undefined)
eq nonceA, b(0,null)
eq false , b(0,false)
eq nonceB, b(undefined,nonceB,undefined)
c = (arg=nonceA,_,_) -> arg
eq nonceA, c()
eq 0, c(0)
eq nonceB, c(nonceB)
eq nonceA, c(undefined)
eq nonceA, c(null)
eq false , c(false)
eq nonceB, c(nonceB,undefined,undefined)
test "default values with @-parameters", ->
a = {}
b = {}
obj = f: (q = a, @p = b) -> q
eq a, obj.f()
eq b, obj.p
test "default values with splatted arguments", ->
withSplats = (a = 2, b..., c = 3, d = 5) -> a * (b.length + 1) * c * d
eq 30, withSplats()
eq 15, withSplats(1)
eq 5, withSplats(1,1)
eq 1, withSplats(1,1,1)
eq 2, withSplats(1,1,1,1)

View File

@ -1,6 +1,9 @@
# Interpolation
# -------------
# * String Interpolation
# * Regular Expression Interpolation
#### String Interpolation
# TODO: refactor string interpolation tests

View File

@ -0,0 +1,9 @@
# Number Literals
# ---------------
# * Decimal Integer Literals
# * Octal Integer Literals
# * Hexadecimal Integer Literals
# * Scientific Notation Integer Literals
# * Scientific Notation Non-Integer Literals
# * Non-Integer Literals

View File

@ -1,6 +1,13 @@
# Operators
# ---------
# * Operators
# * Existential Operator (Binary)
# * Existential Operator (Unary)
# * Aliased Operators
# * [not] in/of
# * Chained Comparison
test "binary (2-ary) math operators do not require spaces", ->
a = 1
b = -1
@ -135,7 +142,7 @@ test "`!=` and `isnt` should be interchangeable", ->
ok a isnt b
#### `in`, `of`
#### [not] in/of
# - `in` should check if an array contains a value using `indexOf`
# - `of` should check if a property is defined on an object using `in`
@ -190,7 +197,7 @@ test "#768: `in` should preserve evaluation order", ->
eq 3, share
#### Chainable Operators
#### Chained Comparison
test "chainable operators", ->
ok 100 > 10 > 1 > 0 > -1

View File

@ -1,6 +1,9 @@
# Regular Expression Literals
# ---------------------------
# * Regexen
# * Heregexen
test "basic regular expression literals", ->
ok 'a'.match(/a/)
ok 'a'.match /a/

0
test/repl.coffee Normal file
View File

View File

@ -0,0 +1,22 @@
# Scope
# -----
# * Variable Safety
# * Variable Shadowing
# * Auto-closure (`do`)
# * Global Scope Leaks
test "reference `arguments` inside of functions", ->
sumOfArgs = ->
sum = (a,b) -> a + b
sum = 0
sum += num for num in arguments
sum
eq 10, sumOfArgs(0, 1, 2, 3, 4)
test "assignment to an Object.prototype-named variable should not leak to outer scope", ->
# FIXME: fails on IE
(->
constructor = 'word'
)()
ok constructor isnt 'word'

View File

@ -1,6 +1,9 @@
# Slicing and Splicing
# --------------------
# * Slicing
# * Splicing
# shared array
shared = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

View File

@ -0,0 +1,6 @@
# Soaks
# -----
# * Soaked Property Access
# * Soaked Method Invocation
# * Soaked Function Invocation