# 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