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

KSUserdataProxyTest.lua

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

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

NOTICE: All information contained herein is, and remain 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 may be covered by U.S. and Foreign
Patents, patents in process, and are protected by trade secret or copyright
law.  Dissemination of this information or reproduction of this material is
strictly forbidden unless prior written permission is obtained from
Adobe Systems Incorporated.

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

local KSUserdataProxyTest = {}

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

local assertf = require 'KSLuaUtils'.assertf
local type = type
local string_format = string.format

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

local function assertType( v, wantType, msg )

	local tv = type( v )
	
	if tv == wantType then
		return v
	end
	
	local emsg
	
	if type( msg ) == 'string' then
		emsg = string_format( "Expected %s got %s (%s)", wantType, tv, msg )
	else
		emsg = string_format( "Expected %s got %s", wantType, tv )
	end
	
	error( emsg, 2 )

end

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

local function checkMakeFactoryResults( success, ... )

	if not success then
		return success, ...
	end
	
	local nresults = select( '#', ... )
	
	assertf( nresults == 5, string_format( "Expected 5 results, got %d", nresults ) )
	
	local factory, test, check, opt, mt = ...
	
	assertType( factory, 'function', "factory" )
	assertType( test, 'function', "test" )
	assertType( check, 'function', "check" )
	assertType( opt, 'function', "opt" )
	assertType( mt, 'table', "metatable" )
	
	return success, ...

end

local function pcallMakeFactoryCheckResults( makeFactory, ... )

	return checkMakeFactoryResults( pcall( makeFactory, ... ) )

end

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

local function getMakeFactory()

	local KSUserdataProxy = assert( require "KSUserdataProxy" )
	
	return assert( KSUserdataProxy.makeFactory, "No definition for makeFactory" )

end

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

function KSUserdataProxyTest.testMakeFactoryNoArgs()

	local makeFactory = getMakeFactory()
	
	assert( pcallMakeFactoryCheckResults( makeFactory ), "makeFactory should succeed with no parameters" )
	
end

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

function KSUserdataProxyTest.testMakeFactoryNilArg()

	local makeFactory = getMakeFactory()
	
	assert( pcallMakeFactoryCheckResults( makeFactory, nil ), "makeFactory should succeed with nil" )
	
end

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

function KSUserdataProxyTest.testMakeFactoryStringArg()

	local makeFactory = getMakeFactory()
	
	assert( pcallMakeFactoryCheckResults( makeFactory, "ProxyName" ), "makeFactory should succeed with a string argument" )
	
end

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

function KSUserdataProxyTest.testMakeFactoryExtraArg()

	local makeFactory = getMakeFactory()
	
	assert( pcallMakeFactoryCheckResults( makeFactory, "ProxyName", 2 ), "makeFactory should succeed with extra arguments" )
	
end

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

function KSUserdataProxyTest.testMakeFactoryBadArg()

	local makeFactory = getMakeFactory()
	
	assert( not pcallMakeFactoryCheckResults( makeFactory, 2 ), "makeFactory should fail with a bad argument" )
	
end

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

function KSUserdataProxyTest.testFactory()

	local makeFactory = getMakeFactory()
	
	local factory, test, check, opt, _ = makeFactory()
	
	local proxy = factory()
	
	assertType( proxy, 'userdata', "proxy" )
	
	assert( proxy == test( proxy ), "Proxy should pass test" )
	assert( proxy == check( proxy ), "Proxy should pass check" )
	assert( proxy == opt( proxy ), "Proxy should pass opt" )
	
end

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

function KSUserdataProxyTest.testFactoryWithEnvironment()

	local makeFactory = getMakeFactory()
	
	local factory, test, check, opt, _ = makeFactory()
	
	local env = { }
	local proxy, envr = factory( env )
	
	assert( envr == env, "factory should return environment" )
	
	assertType( proxy, 'userdata', "proxy" )
	
	local function checkResults( p, e )
		return ( p == proxy ) and ( e == env )
	end
	
	assert( checkResults( test( proxy ) ), "test should return proxy and environment" )
	assert( checkResults( check( proxy ) ), "check should return proxy and environment" )
	assert( checkResults( opt( proxy ) ), "opt should return proxy and environment" )
	
end

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

function KSUserdataProxyTest.testTestRejectsBadProxies()

	local makeFactory = getMakeFactory()
	
	local _, test, _, _, _ = makeFactory()
	
	assert( not test(), "test should fail for no arguments" )
	assert( not test( nil ), "test should fail for nil" )
	assert( not test( "foo" ), "test should fail for a non-proxy" )
	assert( not test( makeFactory()() ), "test should fail for a foreign proxy" )
	
end

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

function KSUserdataProxyTest.testCheckRejectsBadProxies()

	local makeFactory = getMakeFactory()
	
	local _, _, check, _, _ = makeFactory()
	
	assert( not pcall( check ), "check should fail for no arguments" )
	assert( not pcall( check, nil ), "check should fail for nil" )
	assert( not pcall( check, "foo" ), "check should fail for a non-proxy" )
	assert( not pcall( check, makeFactory()() ), "check should fail for a foreign proxy" )
	
end

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

function KSUserdataProxyTest.testOptRejectsBadProxies()

	local makeFactory = getMakeFactory()
	
	local _, _, _, opt, _ = makeFactory()
	
	assert( not pcall( opt, false ), "opt should fail for false" )
	assert( not pcall( opt, "foo" ), "opt should fail for a non-proxy" )
	assert( not pcall( opt, makeFactory()() ), "opt should fail for a foreign proxy" )
	
end

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

function KSUserdataProxyTest.testOptWithNone()

	local makeFactory = getMakeFactory()
	
	local _, _, _, opt, _ = makeFactory()
	
	assert( select( '#', opt() ) == 0, "opt with no args should return nothing" )
	
end

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

function KSUserdataProxyTest.testOptWithNil()

	local makeFactory = getMakeFactory()
	
	local _, _, _, opt, _ = makeFactory()
	
	assert( select( '#', opt( nil ) ) == 1, "opt with nil should return 1 value" )
	assert( opt( nil ) == nil, "opt with nil should return just nil value" )
	
end

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

function KSUserdataProxyTest.testOptWithDefaultEnvironment()

	local makeFactory = getMakeFactory()
	
	local _, _, _, opt, _ = makeFactory()
	
	local defaultEnv = { }
	
	local function checkOptResult( ... )
		
		assert( select( '#', ... ) == 2, "opt with a default environment should return two values" )
		
		local p, e = ...
		
		assert( p == nil, "opt with nil for first parameter should return nil" )
		assert( e == defaultEnv, "opt should return the default environment" )
	
	end
	
	checkOptResult( opt( nil, defaultEnv ) )
	
end

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

function KSUserdataProxyTest.testMetatable()

	local makeFactory = getMakeFactory()
	
	local factory, _, _, _, mt = makeFactory()

	local count = 0
	
	mt.__index = function( t, k )
		count = count + 1
		return 'foo'
	end
	
	local proxy = factory()
	
	assert( proxy.x == 'foo', "Wrong value from indexing proxy" )
	assert( count == 1, "index metamethod called wrong number of times" )
	
end

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

return KSUserdataProxyTest
