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

continuing with the ol' refactorTests

This commit is contained in:
Jeremy Ashkenas 2011-03-11 21:55:26 -05:00
parent 9e2c75b548
commit d30c125ab7
4 changed files with 347 additions and 324 deletions

View file

@ -4,27 +4,27 @@
# * Array Literals
# * Splats in Array Literals
# TODO: refactor array literal tests
# TODO: add indexing and method invocation tests: [1][0] is 1, [].toString()
trailingComma = [1, 2, 3,]
ok (trailingComma[0] is 1) and (trailingComma[2] is 3) and (trailingComma.length is 3)
test "trailing commas", ->
trailingComma = [1, 2, 3,]
ok (trailingComma[0] is 1) and (trailingComma[2] is 3) and (trailingComma.length is 3)
trailingComma = [
1, 2, 3,
4, 5, 6
7, 8, 9,
]
(sum = (sum or 0) + n) for n in trailingComma
trailingComma = [
1, 2, 3,
4, 5, 6
7, 8, 9,
]
(sum = (sum or 0) + n) for n in trailingComma
a = [((x) -> x), ((x) -> x * x)]
ok a.length is 2
a = [((x) -> x), ((x) -> x * x)]
ok a.length is 2
# Funky indentation within non-comma-seperated arrays.
result = [['a']
{b: 'c'}]
ok result[0][0] is 'a'
ok result[1]['b'] is 'c'
test "incorrect indentation without commas", ->
result = [['a']
{b: 'c'}]
ok result[0][0] is 'a'
ok result[1]['b'] is 'c'
# Splats in Array Literals

View file

@ -1,8 +1,6 @@
# Assignment
# ----------
# TODO: organize assignment file
# * Assignment
# * Compound Assignment
# * Destructuring Assignment

View file

@ -3,19 +3,19 @@
# TODO: add method invocation tests: true.toString() is "true"
#764: Boolean should be indexable
toString = Boolean::toString
test "#764 Booleans should be indexable", ->
toString = Boolean::toString
eq toString, true['toString']
eq toString, false['toString']
eq toString, yes['toString']
eq toString, no['toString']
eq toString, on['toString']
eq toString, off['toString']
eq toString, true['toString']
eq toString, false['toString']
eq toString, yes['toString']
eq toString, no['toString']
eq toString, on['toString']
eq toString, off['toString']
eq toString, true.toString
eq toString, false.toString
eq toString, yes.toString
eq toString, no.toString
eq toString, on.toString
eq toString, off.toString
eq toString, true.toString
eq toString, false.toString
eq toString, yes.toString
eq toString, no.toString
eq toString, on.toString
eq toString, off.toString

View file

@ -5,113 +5,119 @@
# * Class Instantiation
# * Inheritance and Super
# TODO: refactor class tests
test "classes with a four-level inheritance chain", ->
# Test classes with a four-level inheritance chain.
class Base
func: (string) ->
"zero/#{string}"
class Base
func: (string) ->
"zero/#{string}"
@static: (string) ->
"static/#{string}"
@static: (string) ->
"static/#{string}"
class FirstChild extends Base
func: (string) ->
class FirstChild extends Base
func: (string) ->
super('one/') + string
SecondChild = class extends FirstChild
func: (string) ->
super('two/') + string
thirdCtor = ->
@array = [1, 2, 3]
class ThirdChild extends SecondChild
constructor: -> thirdCtor.call this
# Gratuitous comment for testing.
func: (string) ->
super('three/') + string
result = (new ThirdChild).func 'four'
ok result is 'zero/one/two/three/four'
ok Base.static('word') is 'static/word'
FirstChild::func = (string) ->
super('one/').length + string
result = (new ThirdChild).func 'four'
ok result is '9two/three/four'
ok (new ThirdChild).array.join(' ') is '1 2 3'
test "constructors with inheritance and super", ->
identity = (f) -> f
class TopClass
constructor: (arg) ->
@prop = 'top-' + arg
class SuperClass extends TopClass
constructor: (arg) ->
identity super 'super-' + arg
class SubClass extends SuperClass
constructor: ->
identity super 'sub'
ok (new SubClass).prop is 'top-super-sub'
test "Overriding the static property new doesn't clobber Function::new", ->
class OneClass
@new: 'new'
function: 'function'
constructor: (name) -> @name = name
class TwoClass extends OneClass
delete TwoClass.new
Function.prototype.new = -> new this arguments...
ok (TwoClass.new('three')).name is 'three'
ok (new OneClass).function is 'function'
ok OneClass.new is 'new'
delete Function.prototype.new
test "basic classes, again, but in the manual prototype style", ->
Base = ->
Base::func = (string) ->
'zero/' + string
Base::['func-func'] = (string) ->
"dynamic-#{string}"
FirstChild = ->
SecondChild = ->
ThirdChild = ->
@array = [1, 2, 3]
this
ThirdChild extends SecondChild extends FirstChild extends Base
FirstChild::func = (string) ->
super('one/') + string
SecondChild = class extends FirstChild
func: (string) ->
SecondChild::func = (string) ->
super('two/') + string
thirdCtor = ->
@array = [1, 2, 3]
class ThirdChild extends SecondChild
constructor: -> thirdCtor.call this
# Gratuitous comment for testing.
func: (string) ->
ThirdChild::func = (string) ->
super('three/') + string
result = (new ThirdChild).func 'four'
result = (new ThirdChild).func 'four'
ok result is 'zero/one/two/three/four'
ok Base.static('word') is 'static/word'
ok result is 'zero/one/two/three/four'
FirstChild::func = (string) ->
super('one/').length + string
result = (new ThirdChild).func 'four'
ok result is '9two/three/four'
ok (new ThirdChild).array.join(' ') is '1 2 3'
ok (new ThirdChild)['func-func']('thing') is 'dynamic-thing'
identity = (f) -> f
class TopClass
constructor: (arg) ->
@prop = 'top-' + arg
class SuperClass extends TopClass
constructor: (arg) ->
identity super 'super-' + arg
class SubClass extends SuperClass
constructor: ->
identity super 'sub'
ok (new SubClass).prop is 'top-super-sub'
class OneClass
@new: 'new'
function: 'function'
constructor: (name) -> @name = name
class TwoClass extends OneClass
delete TwoClass.new
Function.prototype.new = -> new this arguments...
ok (TwoClass.new('three')).name is 'three'
ok (new OneClass).function is 'function'
ok OneClass.new is 'new'
delete Function.prototype.new
# And now the same tests, but written in the manual style:
Base = ->
Base::func = (string) ->
'zero/' + string
Base::['func-func'] = (string) ->
"dynamic-#{string}"
FirstChild = ->
SecondChild = ->
ThirdChild = ->
@array = [1, 2, 3]
this
ThirdChild extends SecondChild extends FirstChild extends Base
FirstChild::func = (string) ->
super('one/') + string
SecondChild::func = (string) ->
super('two/') + string
ThirdChild::func = (string) ->
super('three/') + string
result = (new ThirdChild).func 'four'
ok result is 'zero/one/two/three/four'
ok (new ThirdChild)['func-func']('thing') is 'dynamic-thing'
test "super with plain ol' functions as the original constructors", ->
TopClass = (arg) ->
@prop = 'top-' + arg
@ -131,283 +137,302 @@ SubClass extends SuperClass
ok (new SubClass).prop is 'top-super-sub'
# '@' referring to the current instance, and not being coerced into a call.
class ClassName
amI: ->
@ instanceof ClassName
test "'@' referring to the current instance, and not being coerced into a call", ->
obj = new ClassName
ok obj.amI()
class ClassName
amI: ->
@ instanceof ClassName
obj = new ClassName
ok obj.amI()
# super() calls in constructors of classes that are defined as object properties.
class Hive
constructor: (name) -> @name = name
test "super() calls in constructors of classes that are defined as object properties", ->
class Hive.Bee extends Hive
constructor: (name) -> super
class Hive
constructor: (name) -> @name = name
maya = new Hive.Bee 'Maya'
ok maya.name is 'Maya'
class Hive.Bee extends Hive
constructor: (name) -> super
maya = new Hive.Bee 'Maya'
ok maya.name is 'Maya'
# Class with JS-keyword properties.
class Class
class: 'class'
name: -> @class
test "classes with JS-keyword properties", ->
instance = new Class
ok instance.class is 'class'
ok instance.name() is 'class'
class Class
class: 'class'
name: -> @class
instance = new Class
ok instance.class is 'class'
ok instance.name() is 'class'
# Classes with methods that are pre-bound to the instance.
# ... or statically, to the class.
class Dog
test "Classes with methods that are pre-bound to the instance, or statically, to the class", ->
constructor: (name) ->
@name = name
class Dog
constructor: (name) ->
@name = name
bark: =>
"#{@name} woofs!"
bark: =>
"#{@name} woofs!"
@static = =>
new this('Dog')
@static = =>
new this('Dog')
spark = new Dog('Spark')
fido = new Dog('Fido')
fido.bark = spark.bark
spark = new Dog('Spark')
fido = new Dog('Fido')
fido.bark = spark.bark
ok fido.bark() is 'Spark woofs!'
ok fido.bark() is 'Spark woofs!'
obj = func: Dog.static
obj = func: Dog.static
ok obj.func().name is 'Dog'
ok obj.func().name is 'Dog'
# Testing a bound function in a bound function.
class Mini
num: 10
generate: =>
for i in [1..3]
=>
@num
test "a bound function in a bound function", ->
m = new Mini
eq (func() for func in m.generate()).join(' '), '10 10 10'
class Mini
num: 10
generate: =>
for i in [1..3]
=>
@num
m = new Mini
eq (func() for func in m.generate()).join(' '), '10 10 10'
# Testing a contructor called with varargs.
class Connection
constructor: (one, two, three) ->
[@one, @two, @three] = [one, two, three]
test "contructor called with varargs", ->
out: ->
"#{@one}-#{@two}-#{@three}"
class Connection
constructor: (one, two, three) ->
[@one, @two, @three] = [one, two, three]
list = [3, 2, 1]
conn = new Connection list...
ok conn instanceof Connection
ok conn.out() is '3-2-1'
out: ->
"#{@one}-#{@two}-#{@three}"
list = [3, 2, 1]
conn = new Connection list...
ok conn instanceof Connection
ok conn.out() is '3-2-1'
# Test calling super and passing along all arguments.
class Parent
method: (args...) -> @args = args
test "calling super and passing along all arguments", ->
class Child extends Parent
method: -> super
class Parent
method: (args...) -> @args = args
c = new Child
c.method 1, 2, 3, 4
ok c.args.join(' ') is '1 2 3 4'
class Child extends Parent
method: -> super
c = new Child
c.method 1, 2, 3, 4
ok c.args.join(' ') is '1 2 3 4'
# Test classes wrapped in decorators.
func = (klass) ->
klass::prop = 'value'
klass
test "classes wrapped in decorators", ->
func class Test
prop2: 'value2'
func = (klass) ->
klass::prop = 'value'
klass
ok (new Test).prop is 'value'
ok (new Test).prop2 is 'value2'
func class Test
prop2: 'value2'
ok (new Test).prop is 'value'
ok (new Test).prop2 is 'value2'
# Test anonymous classes.
obj =
klass: class
method: -> 'value'
test "anonymous classes", ->
instance = new obj.klass
ok instance.method() is 'value'
obj =
klass: class
method: -> 'value'
instance = new obj.klass
ok instance.method() is 'value'
# Implicit objects as static properties.
class Static
@static =
one: 1
two: 2
test "Implicit objects as static properties", ->
ok Static.static.one is 1
ok Static.static.two is 2
class Static
@static =
one: 1
two: 2
ok Static.static.one is 1
ok Static.static.two is 2
# Nothing classes.
c = class
ok c instanceof Function
test "nothing classes", ->
c = class
ok c instanceof Function
# Classes with value'd constructors.
counter = 0
classMaker = ->
counter++
inner = counter
->
@value = inner
test "classes with value'd constructors", ->
class One
constructor: classMaker()
counter = 0
classMaker = ->
counter++
inner = counter
->
@value = inner
class Two
constructor: classMaker()
class One
constructor: classMaker()
ok (new One).value is 1
ok (new Two).value is 2
ok (new One).value is 1
ok (new Two).value is 2
class Two
constructor: classMaker()
ok (new One).value is 1
ok (new Two).value is 2
ok (new One).value is 1
ok (new Two).value is 2
# Exectuable class bodies.
class A
if true
b: 'b'
else
c: 'c'
test "exectuable class bodies", ->
a = new A
class A
if true
b: 'b'
else
c: 'c'
eq a.b, 'b'
eq a.c, undefined
a = new A
eq a.b, 'b'
eq a.c, undefined
# Light metaprogramming.
class Base
@attr: (name) ->
@::[name] = (val) ->
if arguments.length > 0
@["_#{name}"] = val
else
@["_#{name}"]
test "mild metaprogramming", ->
class Robot extends Base
@attr 'power'
@attr 'speed'
class Base
@attr: (name) ->
@::[name] = (val) ->
if arguments.length > 0
@["_#{name}"] = val
else
@["_#{name}"]
robby = new Robot
class Robot extends Base
@attr 'power'
@attr 'speed'
ok robby.power() is undefined
robby = new Robot
robby.power 11
robby.speed Infinity
ok robby.power() is undefined
eq robby.power(), 11
eq robby.speed(), Infinity
robby.power 11
robby.speed Infinity
eq robby.power(), 11
eq robby.speed(), Infinity
# Namespaced classes do not reserve their function name in outside scope.
one = {}
two = {}
test "namespaced classes do not reserve their function name in outside scope", ->
class one.Klass
@label = "one"
one = {}
two = {}
class two.Klass
@label = "two"
class one.Klass
@label = "one"
eq typeof Klass, 'undefined'
eq one.Klass.label, 'one'
eq two.Klass.label, 'two'
class two.Klass
@label = "two"
eq typeof Klass, 'undefined'
eq one.Klass.label, 'one'
eq two.Klass.label, 'two'
# Nested classes.
class Outer
constructor: ->
@label = 'outer'
test "nested classes", ->
class @Inner
class Outer
constructor: ->
@label = 'inner'
@label = 'outer'
eq (new Outer).label, 'outer'
eq (new Outer.Inner).label, 'inner'
class @Inner
constructor: ->
@label = 'inner'
eq (new Outer).label, 'outer'
eq (new Outer.Inner).label, 'inner'
# Variables in constructor bodies are correctly scoped.
class A
x = 1
constructor: ->
x = 10
y = 20
y = 2
captured: ->
{x, y}
test "variables in constructor bodies are correctly scoped", ->
a = new A
eq a.captured().x, 10
eq a.captured().y, 2
class A
x = 1
constructor: ->
x = 10
y = 20
y = 2
captured: ->
{x, y}
a = new A
eq a.captured().x, 10
eq a.captured().y, 2
# Issue #924: Static methods in nested classes.
class A
@B: class
@c = -> 5
test "Issue #924: Static methods in nested classes", ->
eq A.B.c(), 5
class A
@B: class
@c = -> 5
eq A.B.c(), 5
# `class extends this` ...
class A
func: -> 'A'
test "`class extends this`", ->
B = null
makeClass = ->
B = class extends this
func: -> super + ' B'
class A
func: -> 'A'
makeClass.call A
B = null
makeClass = ->
B = class extends this
func: -> super + ' B'
eq (new B()).func(), 'A B'
makeClass.call A
eq (new B()).func(), 'A B'
test "ensure that constructors invoked with splats return a new object", ->
args = [1, 2, 3]
Type = (@args) ->
type = new Type args
ok type and type instanceof Type
ok type.args and type.args instanceof Array
ok v is args[i] for v, i in type.args
Type1 = (@a, @b, @c) ->
type1 = new Type1 args...
ok type1 instanceof Type1
eq type1.constructor, Type1
ok type1.a is args[0] and type1.b is args[1] and type1.c is args[2]
# Ensure that constructors invoked with splats cache the function.
called = 0
get = -> if called++ then false else class Type
new get() args...
test "`new` shouldn't add extra parens", ->
ok new Date().constructor is Date
# Ensure that constructors invoked with splats return a new object.
args = [1, 2, 3]
Type = (@args) ->
type = new Type args
test "`new` works against bare function", ->
ok type and type instanceof Type
ok type.args and type.args instanceof Array
ok v is args[i] for v, i in type.args
Type1 = (@a, @b, @c) ->
type1 = new Type1 args...
ok type1 instanceof Type1
eq type1.constructor, Type1
ok type1.a is args[0] and type1.b is args[1] and type1.c is args[2]
# Ensure that constructors invoked with splats cache the function.
called = 0
get = -> if called++ then false else class Type
new get() args...
# `new` shouldn't add extra parens
ok new Date().constructor is Date
# `new` works against bare function
eq Date, new ->
eq this, new => this
Date
eq Date, new ->
eq this, new => this
Date