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

WFLimboTest.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2012 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 WFLimboTest = {}

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

local assert = assert

-- local KSTestUtils = require 'KSTestUtils'

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

function WFLimboTest.testExistence()

	local WFLimbo = require 'WFLimbo'
	
	assert( WFLimbo.addToLimbo, "No addToLimbo function" )
	assert( WFLimbo.removeFromLimbo, "No removeFromLimbo function" )
	assert( WFLimbo.withPoolDo, "No withPoolDo function" )
	assert( WFLimbo.processCurrentLimboPool, "No processCurrentLimboPool function" )

end

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

function WFLimboTest.testAddToLimbo()

	local WFLimbo = require 'WFLimbo'
	
	local didHandle = { }

	local function handler( obj, success, traceback )
		assert( not didHandle[ obj ], "handler should only be called once per object" )
		didHandle[ obj ] = success
	end
	
	local objects = { { }, { }, { } }
	
	WFLimbo.addToLimbo( nil ) -- nil should just be ignored silently

	for _, obj in pairs( objects ) do
		WFLimbo.addToLimbo( obj, handler )
	end
	
	-- try to add an object already in the limbo list, should just be ignored silently
	WFLimbo.addToLimbo( objects[1], handler )

	assert( WFLimbo.processLimboPoolIfRoot(), "Processing limbo pool failed" )
	
	for _, obj in pairs( objects ) do
		assert( didHandle[ obj ] == true, "Object failed to be processed by the handler." )
	end
	
	local rmap = { }
	for k, v in pairs( objects ) do
		rmap[ v ] = k
	end
	
	for obj in pairs( didHandle ) do
		assert( rmap[ obj ], "Appear to have handled an object that shouldn't have been in limbo" )
	end

end

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

function WFLimboTest.testRemoveFromLimbo()

	local WFLimbo = require 'WFLimbo'
	
	local didHandle = { }

	local function handler( obj, success, traceback )
		didHandle[ obj ] = success
	end
	
	local objects = { { }, { }, { } }
	
	for _, obj in pairs( objects ) do
		WFLimbo.addToLimbo( obj, handler )
	end
	
	WFLimbo.removeFromLimbo( nil ) -- ignore remove nil
	WFLimbo.removeFromLimbo( objects[ 2 ] )
	WFLimbo.removeFromLimbo( objects[ 2 ] ) -- try removing again (should just be ignored)
	objects[ 2 ] = nil
	
	assert( WFLimbo.processLimboPoolIfRoot(), "Processing limbo pool failed" )
	
	for _, obj in pairs( objects ) do
		assert( didHandle[ obj ] == true, "Object failed to be processed by the handler." )
	end
	
	local rmap = { }
	for k, v in pairs( objects ) do
		rmap[ v ] = k
	end
	
	for obj in pairs( didHandle ) do
		assert( rmap[ obj ], "Appear to have handled an object that shouldn't have been in limbo" )
	end

end


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

function WFLimboTest.testProcessCurrentPool()

	local WFLimbo = require 'WFLimbo'

	-- test case with nil rootPool and no currentPool
	WFLimbo.processCurrentLimboPool( true )

	local didHandle = { }

	local function handler( obj, success, traceback )
		assert( not didHandle[ obj ], "handler should only be called once per object" )
		didHandle[ obj ] = success
	end
	
	local objects = { { }, { }, { } }
	
	WFLimbo.addToLimbo( nil ) -- nil should just be ignored silently

	for _, obj in pairs( objects ) do
		WFLimbo.addToLimbo( obj, handler )
	end
	
	
	WFLimbo.addToLimbo( objects[1], handler ) -- adding object already in the limbo list will be ignored silently

	-- test case with currentPool == rootPool
	WFLimbo.processCurrentLimboPool( true )
	
	for _, obj in pairs( objects ) do
		assert( didHandle[ obj ] == true, "Object failed to be processed by the handler." )
	end
	
	local rmap = { }
	for k, v in pairs( objects ) do
		rmap[ v ] = k
	end
	
	for obj in pairs( didHandle ) do
		assert( rmap[ obj ], "Appear to have handled an object that shouldn't have been in limbo" )
	end

	-- test case with currentPool ~= rootPool is handled in testWithPoolDo below

end

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

function WFLimboTest.testWithPoolDo()

	local WFLimbo = require 'WFLimbo'
	
	local outerObjects = { { }, { }, { } }
		
	local outerDidHandle = { }
	local function outerHandler( obj, success, traceback )
		outerDidHandle[ obj ] = success
	end

	local function nestedPoolFunction( rootEmpty )
		
		local nestedDidHandle = { }
		local nestedObjects = { { }, { }, { } }

		local function nestedHandler( obj, success, traceback )
			nestedDidHandle[ obj ] = success
		end
	
		for _, obj in pairs( nestedObjects ) do
			WFLimbo.addToLimbo( obj, nestedHandler )
		end
		
		WFLimbo.removeFromLimbo( nestedObjects[ 2 ] )
		nestedObjects[ 2 ] = nil
		
		if rootEmpty then
			assert( WFLimbo.processLimboPoolIfRoot(), "processLimboPoolIfRoot while different pool active with rootPool empty should succeed" )
		else
			assert( not WFLimbo.processLimboPoolIfRoot(), "processLimboPoolIfRoot while different pool active with items in rootPool should fail" )
		end
		
		for _, obj in pairs( nestedObjects ) do
			assert( not nestedDidHandle[ obj ], "Processing root limbo while different pool active shouldn't call limbo handler" )
		end

		for _, obj in pairs( outerObjects ) do
			assert( not outerDidHandle[ obj ], "Processing root limbo while different pool active shouldn't call limbo handler" )
		end

		WFLimbo.processCurrentLimboPool(true)
		
		for _, obj in pairs( nestedObjects ) do
			assert( nestedDidHandle[ obj ], "processCurrentLimboPool should call limbo handler of nested objects" )
		end

		for _, obj in pairs( outerObjects ) do
			assert( not outerDidHandle[ obj ], "processCurrentLimboPool should not call root object handlers" )
		end

	end
	
	WFLimbo.withPoolDo( nestedPoolFunction, true )

	for _, obj in pairs( outerObjects ) do
		WFLimbo.addToLimbo( obj, outerHandler )
	end

	WFLimbo.withPoolDo( nestedPoolFunction, false )
	
	assert( WFLimbo.processLimboPoolIfRoot(), "Processing limbo pool failed" )

	for _, obj in pairs( outerObjects ) do
		assert( outerDidHandle[ obj ], "processLimboPoolIfRoot should call object handlers" )
	end
end

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

return WFLimboTest
