jashkenas--coffeescript/test/soaks.coffee

134 lines
3.1 KiB
CoffeeScript

# Soaks
# -----
# * Soaked Property Access
# * Soaked Method Invocation
# * Soaked Function Invocation
# Soaked Property Access
test "soaked property access", ->
nonce = {}
obj = a: b: nonce
eq nonce , obj?.a.b
eq nonce , obj?['a'].b
eq nonce , obj.a?.b
eq nonce , obj?.a?['b']
eq undefined, obj?.a?.non?.existent?.property
test "soaked property access caches method calls", ->
nonce ={}
obj = fn: -> a: nonce
eq nonce , obj.fn()?.a
eq undefined, obj.fn()?.b
test "soaked property access caching", ->
nonce = {}
counter = 0
fn = ->
counter++
'self'
obj =
self: -> @
prop: nonce
eq nonce, obj[fn()]()[fn()]()[fn()]()?.prop
eq 3, counter
test "method calls on soaked methods", ->
nonce = {}
obj = null
eq undefined, obj?.a().b()
obj = a: -> b: -> nonce
eq nonce , obj?.a().b()
test "postfix existential operator mixes well with soaked property accesses", ->
eq false, nonexistent?.property?
test "function invocation with soaked property access", ->
id = (_) -> _
eq undefined, id nonexistent?.method()
test "if-to-ternary should safely parenthesize soaked property accesses", ->
ok (if nonexistent?.property then false else true)
test "#726: don't check for a property on a conditionally-referenced nonexistent thing", ->
eq undefined, nonexistent?[Date()]
test "#756: conditional assignment edge cases", ->
# TODO: improve this test
a = null
ok isNaN a?.b.c + 1
eq undefined, a?.b.c += 1
eq undefined, ++a?.b.c
eq undefined, delete a?.b.c
test "operations on soaked properties", ->
# TODO: improve this test
a = b: {c: 0}
eq 1, a?.b.c + 1
eq 1, a?.b.c += 1
eq 2, ++a?.b.c
eq yes, delete a?.b.c
# Soaked Method Invocation
test "soaked method invocation", ->
nonce = {}
counter = 0
obj =
self: -> @
increment: -> counter++; @
eq obj , obj.self?()
eq undefined, obj.method?()
eq nonce , obj.self?().property = nonce
eq undefined, obj.method?().property = nonce
eq obj , obj.increment().increment().self?()
eq 2 , counter
test "#733: conditional assignments", ->
a = b: {c: null}
eq a.b?.c?(), undefined
a.b?.c or= (it) -> it
eq a.b?.c?(1), 1
eq a.b?.c?([2, 3]...), 2
# Soaked Function Invocation
test "soaked function invocation", ->
nonce = {}
id = (_) -> _
eq nonce , id?(nonce)
eq nonce , (id? nonce)
eq undefined, nonexistent?(nonce)
eq undefined, (nonexistent? nonce)
test "soaked function invocation with generated functions", ->
nonce = {}
id = (_) -> _
maybe = (fn, arg) -> if typeof fn is 'function' then () -> fn(arg)
eq maybe(id, nonce)?(), nonce
eq (maybe id, nonce)?(), nonce
eq (maybe false, nonce)?(), undefined
test "soaked constructor invocation", ->
eq 42 , +new Number? 42
eq undefined, new Other? 42
test "soaked constructor invocations with caching and property access", ->
semaphore = 0
nonce = {}
class C
constructor: ->
ok false if semaphore
semaphore++
prop: nonce
eq nonce, (new C())?.prop
eq 1, semaphore
test "soaked function invocation safe on non-functions", ->
eq undefined, (0)?(1)
eq undefined, (0)? 1, 2