mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-01-14 01:07:55 -05:00
refactored test_operations.coffee
This commit is contained in:
@@ -1,184 +1,262 @@
|
||||
# CoffeeScript's operations should be chainable, like Python's.
|
||||
ok 500 > 50 > 5 > -5
|
||||
# binary (2-ary) math operators do not require spaces
|
||||
(->
|
||||
a = 1
|
||||
b = -1
|
||||
ok a*-b is 1
|
||||
ok a*+b is -1
|
||||
ok a/-b is 1
|
||||
ok a/+b is -1
|
||||
)()
|
||||
|
||||
# Some chainable operators can be negated by `unless`
|
||||
ok (true unless 0==10!=100)
|
||||
# operators should respect new lines as spaced
|
||||
(->
|
||||
a = 123 +
|
||||
456
|
||||
ok a is 579
|
||||
|
||||
ok true is not false is true is not false
|
||||
b = "1#{2}3" +
|
||||
"456"
|
||||
ok b is '123456'
|
||||
)()
|
||||
|
||||
ok 0 is 0 isnt 50 is 50
|
||||
|
||||
ok 10 < 20 > 10
|
||||
|
||||
ok 50 > 10 > 5 is parseInt('5', 10)
|
||||
|
||||
eq 1, 1 | 2 < 3 < 4
|
||||
|
||||
ok 1 == 1 <= 1, '`x == y <= z` should become `x === y && y <= z`'
|
||||
|
||||
i = 0
|
||||
ok 1 > i++ < 1, 'chained operations should evaluate each value only once'
|
||||
|
||||
|
||||
# `==` and `is` should be interchangeable.
|
||||
a = b = 1
|
||||
|
||||
ok a is 1 and b is 1
|
||||
ok a == b
|
||||
ok a is b
|
||||
|
||||
|
||||
# Allow "if x not in y"
|
||||
obj = {a: true}
|
||||
ok 'a' of obj
|
||||
ok 'b' not of obj
|
||||
|
||||
# And for "a in b" with array presence.
|
||||
ok 200 in [100, 200, 300]
|
||||
array = [100, 200, 300]
|
||||
ok 200 in array
|
||||
ok 1 not in array
|
||||
ok array[0]++ in [99, 100], 'should cache testee'
|
||||
|
||||
# And with array presence on an instance variable.
|
||||
obj = {
|
||||
list: [1, 2, 3, 4, 5]
|
||||
in_list: (value) -> value in @list
|
||||
}
|
||||
ok obj.in_list 4
|
||||
ok not obj.in_list 0
|
||||
|
||||
# Non-spaced values still work.
|
||||
x = 10
|
||||
y = -5
|
||||
|
||||
ok x*-y is 50
|
||||
ok x*+y is -50
|
||||
|
||||
|
||||
# Compound operators.
|
||||
one = 1
|
||||
two = 0
|
||||
one or= 2
|
||||
two or= 2
|
||||
|
||||
eq one, 1
|
||||
eq two, 2
|
||||
|
||||
zero = 0
|
||||
|
||||
zero and= 'one'
|
||||
one and= 'one'
|
||||
|
||||
eq zero, 0
|
||||
eq one , 'one'
|
||||
|
||||
|
||||
# Compound assignment should be careful about caching variables.
|
||||
count = 0
|
||||
list = []
|
||||
|
||||
list[++count] or= 1
|
||||
eq list[1], 1
|
||||
eq count, 1
|
||||
|
||||
list[++count] ?= 2
|
||||
eq list[2], 2
|
||||
eq count, 2
|
||||
|
||||
list[count++] and= 'two'
|
||||
eq list[2], 'two'
|
||||
eq count, 3
|
||||
|
||||
base = -> ++count; base
|
||||
|
||||
base().four or= 4
|
||||
eq base.four, 4
|
||||
eq count, 4
|
||||
|
||||
base().five ?= 5
|
||||
eq base.five, 5
|
||||
eq count, 5
|
||||
|
||||
|
||||
# Ensure that RHS is treated as a group.
|
||||
a = b = false
|
||||
a and= b or true
|
||||
ok a is false
|
||||
|
||||
|
||||
# Bitwise operators:
|
||||
ok (10 & 3) is 2
|
||||
ok (10 | 3) is 11
|
||||
ok (10 ^ 3) is 9
|
||||
ok (10 << 3) is 80
|
||||
ok (10 >> 3) is 1
|
||||
ok (10 >>> 3) is 1
|
||||
|
||||
num = 10; ok (num <<= 3) is 80
|
||||
num = 10; ok (num >>= 3) is 1
|
||||
num = 10; ok (num >>>= 3) is 1
|
||||
num = 10; ok (num &= 3) is 2
|
||||
num = 10; ok (num ^= 3) is 9
|
||||
num = 10; ok (num |= 3) is 11
|
||||
|
||||
|
||||
# Compound assignment with implicit objects.
|
||||
obj = undefined
|
||||
obj ?=
|
||||
one: 1
|
||||
|
||||
ok obj.one is 1
|
||||
|
||||
obj and=
|
||||
two: 2
|
||||
|
||||
ok not obj.one
|
||||
ok obj.two is 2
|
||||
|
||||
|
||||
# Compound assignment as a sub expression.
|
||||
[a, b, c] = [1, 2, 3]
|
||||
ok (a + b += c) is 6
|
||||
ok a is 1
|
||||
ok b is 5
|
||||
ok c is 3
|
||||
|
||||
|
||||
# Instanceof.
|
||||
ok new String instanceof String
|
||||
ok new Number not instanceof String
|
||||
|
||||
|
||||
#737: `in` should have higher precedence than logical operators.
|
||||
eq 1, 1 in [1] and 1
|
||||
|
||||
#768: `in` should preserve evaluation order.
|
||||
share = 0
|
||||
a = -> share++ if share is 0
|
||||
b = -> share++ if share is 1
|
||||
c = -> share++ if share is 2
|
||||
ok a() not in [b(),c()] and share is 3
|
||||
|
||||
# `in` with cache and `__indexOf` should work in commaed lists.
|
||||
eq [Object() in Array()].length, 1
|
||||
|
||||
|
||||
# Operators should respect new lines as spaced.
|
||||
a = (123) +
|
||||
456
|
||||
ok a is 579
|
||||
|
||||
a = "1#{2}3" +
|
||||
"456"
|
||||
ok a is '123456'
|
||||
|
||||
|
||||
# Multiple operators should space themselves.
|
||||
# multiple operators should space themselves
|
||||
ok + +1 is - -1
|
||||
|
||||
#891: incorrect inversion of chained comparisons
|
||||
# bitwise operators
|
||||
(->
|
||||
ok (true unless 0 > 1 > 2)
|
||||
ok (true unless (NaN = 0/0) < 0/0 < NaN)
|
||||
ok (10 & 3) is 2
|
||||
ok (10 | 3) is 11
|
||||
ok (10 ^ 3) is 9
|
||||
ok (10 << 3) is 80
|
||||
ok (10 >> 3) is 1
|
||||
ok (10 >>> 3) is 1
|
||||
|
||||
num = 10; ok (num <<= 3) is 80
|
||||
num = 10; ok (num >>= 3) is 1
|
||||
num = 10; ok (num >>>= 3) is 1
|
||||
num = 10; ok (num &= 3) is 2
|
||||
num = 10; ok (num ^= 3) is 9
|
||||
num = 10; ok (num |= 3) is 11
|
||||
)()
|
||||
|
||||
# `instanceof`
|
||||
(->
|
||||
ok new String instanceof String
|
||||
ok new Boolean instanceof Boolean
|
||||
# `instanceof` supports negation by prefixing the operator with `not`
|
||||
ok new Number not instanceof String
|
||||
ok new Array not instanceof Boolean
|
||||
)()
|
||||
|
||||
|
||||
## compound assignment operators
|
||||
(->
|
||||
|
||||
# boolean operators
|
||||
(->
|
||||
a = 0
|
||||
a or= 2
|
||||
eq a, 2
|
||||
|
||||
b = 1
|
||||
b or= 2
|
||||
eq b, 1
|
||||
|
||||
c = 0
|
||||
c and= 2
|
||||
eq c, 0
|
||||
|
||||
d = 1
|
||||
d and= 2
|
||||
eq d, 2
|
||||
|
||||
# ensure that RHS is treated as a group
|
||||
e = f = false
|
||||
e and= f or true
|
||||
ok e is false
|
||||
)()
|
||||
|
||||
# compound assignment as a sub expression
|
||||
(->
|
||||
[a, b, c] = [1, 2, 3]
|
||||
ok (a + b += c) is 6
|
||||
ok a is 1
|
||||
ok b is 5
|
||||
ok c is 3
|
||||
)()
|
||||
|
||||
# compound assignment should be careful about caching variables
|
||||
(->
|
||||
count = 0
|
||||
list = []
|
||||
|
||||
list[++count] or= 1
|
||||
eq list[1], 1
|
||||
eq count, 1
|
||||
|
||||
list[++count] ?= 2
|
||||
eq list[2], 2
|
||||
eq count, 2
|
||||
|
||||
list[count++] and= 'two'
|
||||
eq list[2], 'two'
|
||||
eq count, 3
|
||||
|
||||
base = ->
|
||||
++count
|
||||
base
|
||||
|
||||
base().four or= 4
|
||||
eq base.four, 4
|
||||
eq count, 4
|
||||
|
||||
base().five ?= 5
|
||||
eq base.five, 5
|
||||
eq count, 5
|
||||
)()
|
||||
|
||||
# compound assignment with implicit objects
|
||||
(->
|
||||
obj = undefined
|
||||
obj ?=
|
||||
one: 1
|
||||
|
||||
ok obj.one is 1
|
||||
|
||||
obj and=
|
||||
two: 2
|
||||
|
||||
ok not obj.one
|
||||
ok obj.two is 2
|
||||
)()
|
||||
|
||||
)()
|
||||
|
||||
|
||||
## `is`,`isnt`,`==`,`!=`
|
||||
(->
|
||||
|
||||
# `==` and `is` should be interchangeable.
|
||||
(->
|
||||
a = b = 1
|
||||
ok a is 1 and b == 1
|
||||
ok a == b
|
||||
ok a is b
|
||||
)()
|
||||
|
||||
# `!=` and `isnt` should be interchangeable.
|
||||
(->
|
||||
a = 0
|
||||
b = 1
|
||||
ok a isnt 1 and b != 0
|
||||
ok a != b
|
||||
ok a isnt b
|
||||
)()
|
||||
|
||||
)()
|
||||
|
||||
|
||||
## `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`
|
||||
(->
|
||||
arr = [1]
|
||||
ok 0 of arr
|
||||
ok 1 in arr
|
||||
# prefixing `not` to `in and `of` should negate them
|
||||
ok 1 not of arr
|
||||
ok 0 not in arr
|
||||
)()
|
||||
|
||||
# `in` should be able to operate on an array literal
|
||||
(->
|
||||
ok 2 in [0, 1, 2, 3]
|
||||
ok 4 not in [0, 1, 2, 3]
|
||||
arr = [0, 1, 2, 3]
|
||||
ok 2 in arr
|
||||
ok 4 not in arr
|
||||
# should cache the value used to test the array
|
||||
arr = [0]
|
||||
val = 0
|
||||
ok val++ in arr
|
||||
ok val++ not in arr
|
||||
val = 0
|
||||
ok val++ of arr
|
||||
ok val++ not of arr
|
||||
)()
|
||||
|
||||
# `of` and `in` should be able to operate on instance variables
|
||||
(->
|
||||
obj = {
|
||||
list: [2,3]
|
||||
in_list: (value) -> value in @list
|
||||
not_in_list: (value) -> value not in @list
|
||||
of_list: (value) -> value of @list
|
||||
not_of_list: (value) -> value not of @list
|
||||
}
|
||||
ok obj.in_list 3
|
||||
ok obj.not_in_list 1
|
||||
ok obj.of_list 0
|
||||
ok obj.not_of_list 2
|
||||
)()
|
||||
|
||||
#???: `in` with cache and `__indexOf` should work in argument lists
|
||||
eq [Object() in Array()].length, 1
|
||||
|
||||
#737: `in` should have higher precedence than logical operators.
|
||||
eq 1, 1 in [1] and 1
|
||||
|
||||
#768: `in` should preserve evaluation order.
|
||||
(->
|
||||
share = 0
|
||||
a = -> share++ if share is 0
|
||||
b = -> share++ if share is 1
|
||||
c = -> share++ if share is 2
|
||||
ok a() not in [b(),c()] and share is 3
|
||||
)()
|
||||
|
||||
)()
|
||||
|
||||
|
||||
## CoffeeScript supports chainable operators like Python
|
||||
(->
|
||||
|
||||
ok 100 > 10 > 1 > 0 > -1
|
||||
ok -1 < 0 < 1 < 10 < 100
|
||||
|
||||
# `is` and `isnt` may be chained
|
||||
ok true is not false is true is not false
|
||||
ok 0 is 0 isnt 1 is 1
|
||||
|
||||
# different comparison operators (`>`,`<`,`is`,etc.) may be combined
|
||||
ok 1 < 2 > 1
|
||||
ok 10 < 20 > 2+3 is 5
|
||||
|
||||
# some chainable operators can be negated by `unless`
|
||||
ok (true unless 0==10!=100)
|
||||
|
||||
# operator precedence: `|` lower than `<`
|
||||
eq 1, 1 | 2 < 3 < 4
|
||||
|
||||
# preserve references
|
||||
(->
|
||||
a = b = c = 1
|
||||
# `a == b <= c` should become `a === b && b <= c`
|
||||
ok a == b <= c
|
||||
)()
|
||||
|
||||
# chained operations should evaluate each value only once
|
||||
(->
|
||||
a = 0
|
||||
ok 1 > a++ < 1
|
||||
)()
|
||||
|
||||
#891: incorrect inversion of chained comparisons
|
||||
(->
|
||||
ok (true unless 0 > 1 > 2)
|
||||
ok (true unless (NaN = 0/0) < 0/0 < NaN)
|
||||
)()
|
||||
|
||||
)()
|
||||
|
||||
Reference in New Issue
Block a user