--[[----------------------------------------------------------------------------

WFObjectProxyTest.lua

--------------------------------------------------------------------------------

ADOBE CONFIDENTIAL
------------------
Copyright 2014 Adobe Systems Incorporated
All Rights Reserved.

NOTICE: All information contained herein is, and remains the property of
Adobe Systems Incorporated and its suppliers, if any. The intellectual and
technical concepts contained herein are proprietary to Adobe Systems
Incorporated and its suppliers and are protected by all applicable
intellectual property laws, including trade secret and copyright laws.
Dissemination of this information or reproduction of this material is
strictly forbidden unless prior written permission is obtained from
Adobe Systems Incorporated.

----------------------------------------------------------------------------]]--

	-- RxLua
local Rx = require 'Rx'

	-- WF.core.utils
local WFCloseSupport = require 'WFCloseSupport'


--============================================================================--

local WFObjectProxyTest = {}

--------------------------------------------------------------------------------

local closed

local MyClassImp = Rx.Class "MyClassImp" {

	_key = false,

	_foo = false,

	__init = function( self, key, foo )

		closed = false

		self._key = key
		self._foo = foo

	end,

	foo = function( self )
		return self._foo
	end,

	key = function( self )
		return self._key
	end,

	self = function( self )
		return self
	end,

	close = function()
		closed = true
	end,

	WFCloseSupport.addCloseSupportMethods,

}

--------------------------------------------------------------------------------

local function testProxyClass( ProxyClass, invalid )

	local first = ProxyClass( 'a', 'AA' )
	local second = ProxyClass( 'a', 'BB' )

	assert( ProxyClass:isClassOf( first ), "isClassOf works on base and proxy #1" )

	assert( first:foo() == 'AA', "Proxy method foo() not forwarded" )
	assert( second:foo() == ( invalid and 'BB' or 'AA' ),
							   "2nd Proxy method foo() not forwarded (got : "
									.. tostring( second:foo() ) .. ")" )
	assert( first:key() == 'a', "Proxy method key() not forwarded" )
	assert( second:key() == 'a', "2nd Proxy method key() not forwarded" )
	assert( not closed, "Closed prematurely" )

	first:close()

	if not invalid then
		assert( not closed, "Closed after 1st closed" )
	end

	closed = false

	local third = second:relayObject()
	second:close()

	assert( not second:isSharedInstanceClosed(), "Erroneous close when second but not last proxy closed" )
	assert( not third:isSharedInstanceClosed(), "Erroneous close when second but not last proxy closed" )
	assert( not closed, "Erroneous close when second but not last proxy closed" )
	assert( third:foo() == ( invalid and 'BB' or 'AA' ), "3rd Proxy method foo()" )

	third:close()
	assert( closed, "Failed to close when last proxy closed" )

end

--------------------------------------------------------------------------------

function WFObjectProxyTest:testBasic()

	local ProxyClass

	local function validator( cache, key, foo )

		local object = cache[ key ]
		if object then
			assert( MyClassImp:isClassOf( object ), "Object not instance of class" )
			assert( ProxyClass:isClassOf( object ), "isClassOf works on base and proxy #2" )
		end

		return key

	end

	local WFObjectProxy = require 'WFObjectProxy'
	assert( WFObjectProxy, "Can't load WFObjectProxy namespace" )

	ProxyClass = WFObjectProxy( "MyClass", MyClassImp, validator )

	testProxyClass( ProxyClass )

	ProxyClass = WFObjectProxy( "MyClass", MyClassImp )

	testProxyClass( ProxyClass )

	local function invalidator( cache, key, foo )
		cache[ key ] = nil
		return key
	end

	ProxyClass = WFObjectProxy( "MyClass", MyClassImp, invalidator )

	testProxyClass( ProxyClass, 'BB' )

	assert( nil == ProxyClass.foo, "forward __index" )

	assert( false == pcall( function() ProxyClass.foo = 32 end ), "forward __newindex" )

end

--------------------------------------------------------------------------------

function WFObjectProxyTest:testMethodChaining()

	local WFObjectProxy = require 'WFObjectProxy'
	local ProxyClass = WFObjectProxy( "MyClass", MyClassImp )

	local proxy = ProxyClass( 1, 2 )
	assert( proxy:self() == proxy, "Ensure methods that return self return proxy's self" )

end

--------------------------------------------------------------------------------

function WFObjectProxyTest:testErrorIfInternallyClosed()

	local WFObjectProxy = require 'WFObjectProxy'
	local ProxyClass = WFObjectProxy( "MyClass", MyClassImp )

	local a = ProxyClass( 'a' )
	a._sharedInstance:close()
		-- I can't find a good way to know that this caused the error
		-- to throw because close support catches it.

	a:close()

end

--------------------------------------------------------------------------------

function WFObjectProxyTest:testEquality()

	local WFObjectProxy = require 'WFObjectProxy'

	local function validator( cache, key, foo )
		return foo
	end

	local ProxyClass = WFObjectProxy( "MyClass", MyClassImp, validator )

	local a = ProxyClass( 'a', 'b' )
	local c = ProxyClass( 'c', 'b' )
	local f = ProxyClass( 'f', 'f' )

	assert( a == c, "proxy references to same object compare as equal" )
	assert( a ~= f, "proxy references to different underlying objects compare not equal" )

end

--------------------------------------------------------------------------------

function WFObjectProxyTest:testValidatorKey()

	local WFObjectProxy = require 'WFObjectProxy'

	local function validator( cache, key, foo )
		return foo
	end

	local ProxyClass = WFObjectProxy( "MyClass", MyClassImp, validator )
	local a = ProxyClass( 'a', 'b' )
	local c = ProxyClass( 'c', 'b' )

	assert( c:key() == 'a', 'lookup used validator supplied key' )
	assert( a:key() == 'a', 'just do something with a to keep it alive' )

end

--------------------------------------------------------------------------------

return WFObjectProxyTest
