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

WFTimerTest.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.

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

	-- wichitafoundation.core.lua.threading
local WFTimer = require 'WFTimer'

	-- wichitafoundation.core.os
local KSDate = require 'KSDate'

	-- wichitafoundation.core.utils
local KSTestUtils = require 'KSTestUtils'
local WFPlatformInfo = require 'WFPlatformInfo'


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

local WFTimerTest = {}

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

function WFTimerTest.testRejectsNegativeDelay()

	KSTestUtils.assertFails( function()
		
		WFTimer.afterDelayP( -1 )
	
	end )

end

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

function WFTimerTest.testAfterDelayP( test )

	local startTime = KSDate.timeNowForAnimation()
	local secondTimerElapsedTime = 0

	-- NOTE: Intentionally not using WFAsyncTestCase here because that class
	-- depends on WFIdle.onIdleP. Need an independent test case.
	
	WFTimer.afterDelayP( .5 )
		:whenResolvedDo( function( status, blah )
			
			if status == 'data' and blah == true then

				local elapsedTime = KSDate.timeNowForAnimation() - startTime
				
				if secondTimerElapsedTime == 0 then
					test:log( "timers are blocking" )
					test:notifyTestDidFail( "timers are blocking" )
				elseif elapsedTime < .5 or secondTimerElapsedTime < .1 then
					test:log( "promises resolved too soon" )
					test:notifyTestDidFail( "promises resolved too soon" )
				elseif elapsedTime > 1.25 or secondTimerElapsedTime > .35 then
					test:log( "promises resolved too late" )
					test:notifyTestDidFail( "promises resolved too late" )
				else
					test:notifyTestDidSucceed()
				end

			else
				test:log( string.format( "Unexpected resolution on WFTimer.afterDelayP: %s, %s", status, blah ) )
				test:log( "via " .. debug.traceback() )
				test:notifyTestDidFail( "longer promise resolved in error" )
			end
		
		end )
		:runUntilDone()
		
	WFTimer.afterDelayP( .1 )
		:whenResolvedDo( function( status, blah )
			
			if status == 'data' and blah == true then
				secondTimerElapsedTime = KSDate.timeNowForAnimation() - startTime
			else
				test:log( string.format( "Unexpected resolution on WFTimer.afterDelayP: %s, %s", status, blah ) )
				test:log( "via " .. debug.traceback() )
				test:notifyTestDidFail( "shorter promise resolved in error" )
			end
		
		end )
		:runUntilDone()
		
	test:waitForTestToFinish( 4 )

end

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

local successCount = 0
local expectedSuccessCount
	
local function _testAfterDelayDo( test, delay )

	local tooLate = math.max( delay * 2, 0.2 )
	
	if WFPlatformInfo.isAndroid then
	
		-- PERFORMANCE_ANDROID
		tooLate = tooLate * 2
	
	end
	
	local startTime = KSDate.timeNowForAnimation()

	WFTimer.afterDelayDo( delay,
		function( status, blah )

			if status ~= 'data' then
				test:log( "afterDelayDo resolved in error" )
				test:notifyTestDidFail( 'afterDelayDo resolved in error' )
			end

			local elapsedTime = KSDate.timeNowForAnimation() - startTime

			if elapsedTime < delay then
				test:log( "function called too soon: " .. delay .. "s delay fired after: " .. elapsedTime .. "s" )
				test:notifyTestDidFail( 'afterDelayDo called too soon'  )
			elseif elapsedTime > tooLate then
				test:log( "function called too late: " .. delay .. "s delay fired after: " .. elapsedTime .. "s" )
				test:notifyTestDidFail( 'afterDelayDo called too late' )
			else
				successCount = successCount + 1
				if successCount == expectedSuccessCount then
					test:notifyTestDidSucceed()
				end
			end

		end )

end

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

function WFTimerTest.testAfterDelayDo( test )

	successCount = 0
	expectedSuccessCount = 5
		-- WFTimerTest.testAfterDelayDo calls _testAfterDelayDo how many times

	_testAfterDelayDo( test, 0.05 )

	_testAfterDelayDo( test, 0.1 )

	_testAfterDelayDo( test, 0.25 )

	_testAfterDelayDo( test, 0.5 )

	_testAfterDelayDo( test, 1 )

	test:waitForTestToFinish( 10 )

end

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

function WFTimerTest.testAfterDelayDoExtensive_testNightly( test )

	successCount = 0
	expectedSuccessCount = 100
		-- WFTimerTest.testAfterDelayDoExtensive calls _testAfterDelayDo how many times

	for i = 1,expectedSuccessCount do
		_testAfterDelayDo( test, 0.1 + i / 16 )
	end

	test:waitForTestToFinish( 30 )

end


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

return WFTimerTest
