jashkenas--coffeescript/test/assignment.coffee

346 lines
8.6 KiB
CoffeeScript
Raw Normal View History

2010-12-29 05:48:54 +00:00
# Assignment
# ----------
2010-12-29 19:06:57 +00:00
# * Assignment
# * Compound Assignment
# * Destructuring Assignment
# * Context Property (@) Assignment
# * Existential Assignment (?=)
2010-12-29 05:48:54 +00:00
test "context property assignment (using @)", ->
nonce = {}
addMethod = ->
@method = -> nonce
this
eq nonce, addMethod.call({}).method()
test "unassignable values", ->
nonce = {}
for nonref in ['', '""', '0', 'f()'].concat CoffeeScript.RESERVED
eq nonce, (try CoffeeScript.compile "#{nonref} = v" catch e then nonce)
2011-03-12 02:41:12 +00:00
# Compound Assignment
2010-12-29 05:48:54 +00:00
2011-01-03 09:17:00 +00:00
test "boolean operators", ->
nonce = {}
a = 0
a or= nonce
eq nonce, a
b = 1
b or= nonce
eq 1, b
c = 0
c and= nonce
eq 0, c
d = 1
d and= nonce
eq nonce, d
# ensure that RHS is treated as a group
e = f = false
e and= f or true
eq false, e
test "compound assignment as a sub expression", ->
[a, b, c] = [1, 2, 3]
eq 6, (a + b += c)
eq 1, a
eq 5, b
eq 3, c
# *note: this test could still use refactoring*
test "compound assignment should be careful about caching variables", ->
count = 0
list = []
list[++count] or= 1
eq 1, list[1]
eq 1, count
list[++count] ?= 2
eq 2, list[2]
eq 2, count
list[count++] and= 6
eq 6, list[2]
eq 3, count
base = ->
++count
base
base().four or= 4
eq 4, base.four
eq 4, count
base().five ?= 5
eq 5, base.five
eq 5, count
test "compound assignment with implicit objects", ->
obj = undefined
obj ?=
one: 1
eq 1, obj.one
obj and=
two: 2
eq undefined, obj.one
eq 2, obj.two
2010-12-29 05:48:54 +00:00
test "compound assignment (math operators)", ->
num = 10
num -= 5
eq 5, num
num *= 10
eq 50, num
num /= 10
eq 5, num
num %= 3
eq 2, num
test "more compound assignment", ->
a = {}
val = undefined
val ||= a
val ||= true
eq a, val
b = {}
val &&= true
eq val, true
val &&= b
eq b, val
c = {}
val = null
val ?= c
val ?= true
eq c, val
2011-03-12 02:41:12 +00:00
# Destructuring Assignment
2010-12-29 05:48:54 +00:00
2011-01-03 09:17:00 +00:00
test "empty destructuring assignment", ->
{} = [] = undefined
test "chained destructuring assignments", ->
[a] = {0: b} = {'0': c} = [nonce={}]
eq nonce, a
eq nonce, b
eq nonce, c
test "variable swapping to verify caching of RHS values when appropriate", ->
a = nonceA = {}
b = nonceB = {}
c = nonceC = {}
[a, b, c] = [b, c, a]
eq nonceB, a
eq nonceC, b
eq nonceA, c
[a, b, c] = [b, c, a]
eq nonceC, a
eq nonceA, b
eq nonceB, c
fn = ->
[a, b, c] = [b, c, a]
arrayEq [nonceA,nonceB,nonceC], fn()
eq nonceA, a
eq nonceB, b
eq nonceC, c
test "#713", ->
nonces = [nonceA={},nonceB={}]
eq nonces, [a, b] = [c, d] = nonces
eq nonceA, a
eq nonceA, c
eq nonceB, b
eq nonceB, d
test "destructuring assignment with splats", ->
a = {}; b = {}; c = {}; d = {}; e = {}
[x,y...,z] = [a,b,c,d,e]
eq a, x
arrayEq [b,c,d], y
eq e, z
test "deep destructuring assignment with splats", ->
a={}; b={}; c={}; d={}; e={}; f={}; g={}; h={}; i={}
[u, [v, w..., x], y..., z] = [a, [b, c, d, e], f, g, h, i]
eq a, u
eq b, v
arrayEq [c,d], w
eq e, x
arrayEq [f,g,h], y
eq i, z
test "destructuring assignment with objects", ->
a={}; b={}; c={}
obj = {a,b,c}
{a:x, b:y, c:z} = obj
eq a, x
eq b, y
eq c, z
test "deep destructuring assignment with objects", ->
a={}; b={}; c={}; d={}
obj = {
a
b: {
'c': {
d: [
b
{e: c, f: d}
]
}
}
}
{a: w, 'b': {c: d: [x, {'f': z, e: y}]}} = obj
eq a, w
eq b, x
eq c, y
eq d, z
test "destructuring assignment with objects and splats", ->
a={}; b={}; c={}; d={}
obj = a: b: [a, b, c, d]
{a: b: [y, z...]} = obj
eq a, y
arrayEq [b,c,d], z
test "destructuring assignment against an expression", ->
a={}; b={}
[y, z] = if true then [a, b] else [b, a]
eq a, y
eq b, z
test "bracket insertion when necessary", ->
[a] = [0] ? [1]
eq a, 0
2011-01-03 09:17:00 +00:00
# for implicit destructuring assignment in comprehensions, see the comprehension tests
test "destructuring assignment with context (@) properties", ->
a={}; b={}; c={}; d={}; e={}
obj =
fn: () ->
local = [a, {b, c}, d, e]
[@a, {b: @b, c: @c}, @d, @e] = local
eq undefined, obj[key] for key in ['a','b','c','d','e']
obj.fn()
eq a, obj.a
eq b, obj.b
eq c, obj.c
eq d, obj.d
eq e, obj.e
2011-01-11 04:09:21 +00:00
test "#1024", ->
eq 2 * [] = 3 + 5, 16
test "#1005: invalid identifiers allowed on LHS of destructuring assignment", ->
disallowed = ['eval', 'arguments'].concat CoffeeScript.RESERVED
2011-08-11 06:17:48 +00:00
throws (-> CoffeeScript.compile "[#{disallowed.join ', '}] = x"), null, 'all disallowed'
throws (-> CoffeeScript.compile "[#{disallowed.join '..., '}...] = x"), null, 'all disallowed as splats'
t = tSplat = null
for v in disallowed when v isnt 'class' # `class` by itself is an expression
2011-08-11 06:17:48 +00:00
throws (-> CoffeeScript.compile t), null, t = "[#{v}] = x"
throws (-> CoffeeScript.compile tSplat), null, tSplat = "[#{v}...] = x"
doesNotThrow ->
for v in disallowed
CoffeeScript.compile "[a.#{v}] = x"
CoffeeScript.compile "[a.#{v}...] = x"
CoffeeScript.compile "[@#{v}] = x"
CoffeeScript.compile "[@#{v}...] = x"
test "#2055: destructuring assignment with `new`", ->
{length} = new Array
eq 0, length
2011-01-03 09:17:00 +00:00
2011-03-12 02:41:12 +00:00
# Existential Assignment
2011-01-03 09:17:00 +00:00
test "existential assignment", ->
nonce = {}
a = false
a ?= nonce
eq false, a
b = undefined
b ?= nonce
eq nonce, b
c = null
c ?= nonce
eq nonce, c
test "#1627: prohibit conditional assignment of undefined variables", ->
2011-10-04 01:57:33 +00:00
throws (-> CoffeeScript.compile "x ?= 10"), null, "prohibit (x ?= 10)"
throws (-> CoffeeScript.compile "x ||= 10"), null, "prohibit (x ||= 10)"
throws (-> CoffeeScript.compile "x or= 10"), null, "prohibit (x or= 10)"
throws (-> CoffeeScript.compile "do -> x ?= 10"), null, "prohibit (do -> x ?= 10)"
throws (-> CoffeeScript.compile "do -> x ||= 10"), null, "prohibit (do -> x ||= 10)"
throws (-> CoffeeScript.compile "do -> x or= 10"), null, "prohibit (do -> x or= 10)"
doesNotThrow (-> CoffeeScript.compile "x = null; x ?= 10"), "allow (x = null; x ?= 10)"
doesNotThrow (-> CoffeeScript.compile "x = null; x ||= 10"), "allow (x = null; x ||= 10)"
doesNotThrow (-> CoffeeScript.compile "x = null; x or= 10"), "allow (x = null; x or= 10)"
doesNotThrow (-> CoffeeScript.compile "x = null; do -> x ?= 10"), "allow (x = null; do -> x ?= 10)"
doesNotThrow (-> CoffeeScript.compile "x = null; do -> x ||= 10"), "allow (x = null; do -> x ||= 10)"
doesNotThrow (-> CoffeeScript.compile "x = null; do -> x or= 10"), "allow (x = null; do -> x or= 10)"
2011-10-04 01:57:33 +00:00
throws (-> CoffeeScript.compile "-> -> -> x ?= 10"), null, "prohibit (-> -> -> x ?= 10)"
doesNotThrow (-> CoffeeScript.compile "x = null; -> -> -> x ?= 10"), "allow (x = null; -> -> -> x ?= 10)"
2011-05-11 13:11:41 +00:00
test "#1348, #1216: existential assignment compilation", ->
nonce = {}
a = nonce
b = (a ?= 0)
eq nonce, b
2011-05-11 13:11:41 +00:00
#the first ?= compiles into a statement; the second ?= compiles to a ternary expression
eq a ?= b ?= 1, nonce
if a then a ?= 2 else a = 3
eq a, nonce
test "#1591, #1101: splatted expressions in destructuring assignment must be assignable", ->
nonce = {}
for nonref in ['', '""', '0', 'f()', '(->)'].concat CoffeeScript.RESERVED
eq nonce, (try CoffeeScript.compile "[#{nonref}...] = v" catch e then nonce)
2011-12-24 12:04:34 +00:00
test "#1643: splatted accesses in destructuring assignments should not be declared as variables", ->
nonce = {}
2011-09-09 22:59:35 +00:00
accesses = ['o.a', 'o["a"]', '(o.a)', '(o.a).a', '@o.a', 'C::a', 'C::', 'f().a', 'o?.a', 'o?.a.b', 'f?().a']
for access in accesses
2011-09-09 22:59:35 +00:00
for i,j in [1,2,3] #position can matter
2011-12-24 12:04:34 +00:00
code =
"""
2011-12-24 12:04:34 +00:00
nonce = {}; nonce2 = {}; nonce3 = {};
@o = o = new (class C then a:{}); f = -> o
[#{new Array(i).join('x,')}#{access}...] = [#{new Array(i).join('0,')}nonce, nonce2, nonce3]
unless #{access}[0] is nonce and #{access}[1] is nonce2 and #{access}[2] is nonce3 then throw new Error('[...]')
"""
2011-09-09 22:59:35 +00:00
eq nonce, unless (try CoffeeScript.run code, bare: true catch e then true) then nonce
# subpatterns like `[[a]...]` and `[{a}...]`
subpatterns = ['[sub, sub2, sub3]', '{0: sub, 1: sub2, 2: sub3}']
for subpattern in subpatterns
for i,j in [1,2,3]
code =
"""
2011-12-24 12:04:34 +00:00
nonce = {}; nonce2 = {}; nonce3 = {};
[#{new Array(i).join('x,')}#{subpattern}...] = [#{new Array(i).join('0,')}nonce, nonce2, nonce3]
unless sub is nonce and sub2 is nonce2 and sub3 is nonce3 then throw new Error('[sub...]')
"""
2011-09-09 22:59:35 +00:00
eq nonce, unless (try CoffeeScript.run code, bare: true catch e then true) then nonce
2011-12-14 23:31:20 +00:00
test "#1838: Regression with variable assignment", ->
name =
'dave'
2011-12-24 12:04:34 +00:00
eq name, 'dave'