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

KSMemoryCacheTest.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 KSMemoryCache = require 'KSMemoryCache'

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

local KSMemoryCacheTest = { }

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

function KSMemoryCacheTest.testCacheExpiration()

	local simpleCache = KSMemoryCache( 3 )
	assert( simpleCache.maxEntries == 3 )

	simpleCache:add( "foo", { x = 1 } )
	simpleCache:add( "bar", { x = 2 } )
	simpleCache:add( "baz", { x = 3 } )
	
	assert( simpleCache.count == 3, "simpleCache:count == 3" )
	
	simpleCache:add( "bleen", { x = 4 } )

	assert( simpleCache.count == 3, "simpleCache:count == 3" )
	
	collectgarbage()
	collectgarbage()
	collectgarbage()
	
	assert( not simpleCache:getData("foo") )
	assert( simpleCache:getData("bar") )
	assert( simpleCache:getData("baz") )
	assert( simpleCache:getData("bleen") )

end

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

function KSMemoryCacheTest.testAdjustMaximumEntries()

	local simpleCache = KSMemoryCache( 3 )
	assert( simpleCache.maxEntries == 3 )

	simpleCache:add( "foo", { x = 1 } )
	simpleCache:add( "bar", { x = 2 } )
	simpleCache:add( "baz", { x = 3 } )
	
	assert( simpleCache.count == 3, "simpleCache:count == 3" )
	
	simpleCache:add( "bleen", { x = 4 } )

	assert( simpleCache.count == 3, "simpleCache:count == 3" )
	
	simpleCache:adjustMaximumEntries( 5 )
	
	assert( simpleCache.count == 3, "simpleCache:count == 3" )
	
	simpleCache:add( "bang", { x = 5 } )
	simpleCache:add( "boom", { x = 6 } )
	
	assert( simpleCache.count == 5, "simpleCache:count == 5" )
	
	assert( simpleCache:getData( "bang" ) )
	assert( simpleCache:getData( "boom" ) )
	
	collectgarbage()
	collectgarbage()
	collectgarbage()
	
	assert( not simpleCache:getData( "foo" ) )
	assert( simpleCache:getData( "bar" ) )
	assert( simpleCache:getData( "baz" ) )
	assert( simpleCache:getData( "bleen" ) )
	
	simpleCache:adjustMaximumEntries( 3 )
	
	collectgarbage()
	collectgarbage()
	collectgarbage()
	
	assert( simpleCache:getData( "bar" ) )
	assert( simpleCache:getData( "bleen" ) )
	assert( simpleCache:getData( "baz" ) )
	
	assert( not simpleCache:getData( "foo" ) )
	assert( not simpleCache:getData( "bang" ) )
	assert( not simpleCache:getData( "boom" ) )
	
	local success = pcall( function() simpleCache:adjustMaximumEntries( 1 ) end )
	
	assert( not success )

end

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

function KSMemoryCacheTest.testRemoveFirst()

	local simpleCache = KSMemoryCache( 3 )
	assert( simpleCache.maxEntries == 3 )

	simpleCache:add( "bar", { x = 1 } )
	simpleCache:add( "baz", { x = 2 } )
	
	simpleCache:remove( "baz" )
	simpleCache:remove( "bar" )

	simpleCache:add( "foo", { x = 3 } )
	simpleCache:remove( "foo" )

	simpleCache:add( "bar", { x = 1 } )
	simpleCache:remove( "bar" )

	simpleCache:add( "bar", { x = 1 } )
	simpleCache:add( "baz", { x = 2 } )

	simpleCache:remove( "baz" )
	simpleCache:add( "baz", { x = 2 } )

end

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

function KSMemoryCacheTest.testStringData()

	local simpleCache = KSMemoryCache( 3 )
	
	simpleCache:add( "foo", "bar" )
	
	assert( simpleCache:getData( "foo" ) == "bar" )
	
end

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

function KSMemoryCacheTest.testUnsupportedDataTypes()
	
	local simpleCache = KSMemoryCache( 3 )
	
	local success = pcall( function() simpleCache:add( "number", 1 ) end )
	assert( not success )
	
	success = pcall( function() simpleCache:add( "boolean", true ) end )
	assert( not success )
	
	success = pcall( function() simpleCache:add( "nil", nil ) end )
	assert( not success )
	
	success = pcall( function() simpleCache:add( "function", function() end ) end )
	assert( not success )

end

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

function KSMemoryCacheTest.testFlush()

	local simpleCache = KSMemoryCache( 3 )
	assert( simpleCache.maxEntries == 3 )

	simpleCache:add( "foo", { x = 1 } )
	simpleCache:add( "bar", { x = 2 } )
	simpleCache:add( "baz", { x = 3 } )
	
	assert( simpleCache.count == 3 )

	simpleCache:flush()
	
	assert( simpleCache.count == 0 )
	assert( simpleCache:getData( "foo" ) == nil, "all data should be cleared by flush" )
end

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

function KSMemoryCacheTest.testAddExisting()

	local simpleCache = KSMemoryCache( 3 )

	simpleCache:add( "foo", { x = 1 } )
	simpleCache:add( "foo", { x = 2 } )
	simpleCache:add( "foo", { x = 3 } )
	
	assert( simpleCache.count == 1, "adding same key multiple times shouldn't add additional items" )
	
	assert( simpleCache:getData( "foo" )['x'] == 3, "adding same key multiple times should update the data" )

end

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

function KSMemoryCacheTest.testGetDataOnClosedData()

	local simpleCache = KSMemoryCache( 3 )

	local WFCloseSupport = assert( require "WFCloseSupport" )
	
	local methodTable = { close = function( self ) self.closed = true end }
	
	WFCloseSupport.addCloseSupportMethods( methodTable )

	local w = setmetatable( { }, { __index = methodTable } )
	local x = setmetatable( { }, { __index = methodTable } )
	
	w:addCloseTarget( x )

	simpleCache:add( "foo1", w )
	simpleCache:add( "foo2", x )
	assert( simpleCache.count == 2, "cache should contain 2 items" )
	assert( simpleCache:getData( "foo1" ), "foo1 data is cached" )
	assert( simpleCache:getData( "foo2" ), "foo2 data is cached" )
	
	w:close()
	assert( w.closed, "close w failed" )
	assert( x.closed, "chained close x failed" )
	assert( simpleCache.count == 2, "cache should contain 2 closed items" )

	assert( simpleCache:getData( "foo1" ) == nil, "getting a closed value should return nil" )
	assert( simpleCache.count == 1, "getData should remove closed key" )
	
	assert( simpleCache:getData( "foo2" ) == nil, "getting a closed value should return nil")
	assert( simpleCache.count == 0, "getData should remove closed key" )

end

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

function KSMemoryCacheTest.testGetDataOnUncollectedData()

	local simpleCache = KSMemoryCache( 3 )
	assert( simpleCache.maxEntries == 3 )

	local safeData = { x = 1 }
	
	simpleCache:add( "foo", safeData )
	simpleCache:add( "foo2", { x = 2 } )
	simpleCache:add( "bar", { x = 3 } )
	simpleCache:add( "baz", { x = 4 } )
	simpleCache:add( "bleen", { x = 5 } )
	
	assert( simpleCache.count == 3 )
	
	collectgarbage()
	collectgarbage()
	collectgarbage()

	assert( simpleCache:getData( "foo" )['x'] == 1, "should still able to get data from cache that hasn't been collected" )
	assert( simpleCache:getData( "foo2" ) == nil, "should not be able to get data from cache that has been collected" )
end

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

return KSMemoryCacheTest
