1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
# 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
|