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

KSPCallLoopsTest.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 T = { }

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

local assert = assert
-- local collectgarbage = collectgarbage

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

local KSPCallLoops = require 'KSPCallLoops'

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

function T.testSeq()

	local i = 0
	
	local function sourceFn()
		i = i + 1
		if i < 11 then
			return i
		end
	end
	
	local sum = 0
	
	local function actionFn( x )
		sum = sum + x
		if x % 3 == 0 then
			error "Multiple of three"
		end
	end
	
	local success, _ = KSPCallLoops.pdoWithIterator( actionFn, nil, sourceFn )
	
	assert( success, "pdoWithIterator should have succeeded" )
	
	assert( i == 11, "We should have completed the iteration." )

	assert( sum == 55, "Sum should have been 55 was " .. tostring( sum ) )

end

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

function T.testErrorHandling()

	local i = 0
	
	local function sourceFn()
		i = i + 1
		if i < 11 then
			return i
		end
	end
	
	local sum = 0
	local errorSum = 0
	
	local function actionFn( x )
		sum = sum + x
		if x % 3 == 0 then
			error "Multiple of three"
		end
	end
	
	local function errorFn( msg, x )
		errorSum = errorSum + x
	end
	
	local success, _ = KSPCallLoops.pdoWithIterator( actionFn, errorFn, sourceFn )

	assert( success, "pdoWithIterator should have succeeded" )

	assert( sum == 55, "Sum should have been 55" )
	assert( errorSum == 18, "Error sum should have been 18" )

end

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

function T.testErrorHandlingWithErrorInSource()

	local function sourceFn()
		error "Source Error"
	end
	
	local sum = 0
	local errorSum = 0
	
	local function actionFn( x )
		sum = sum + x
		if x % 3 == 0 then
			error "Multiple of three"
		end
	end
	
	local function errorFn( msg, x )
		errorSum = errorSum + x
	end
	
	local success, msg = KSPCallLoops.pdoWithIterator( actionFn, errorFn, sourceFn )

	assert( not success, "pdoWithIterator should not have succeeded" )
	assert( string.find( msg, "Source Error" ), "should receive error message from sourceFn" )

	assert( sum == 0, "Sum should have been 0" )
	assert( errorSum == 0, "Error sum should have been 0" )

end

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

function T.testErrorHandlingWithRejection()

	local i = 0
	
	local function sourceFn()
		i = i + 1
		if i < 11 then
			return i
		end
	end
	
	local sum = 0
	local errorSum = 0
	
	local function actionFn( x )
		sum = sum + x
		if x % 3 == 0 then
			error "Multiple of three"
		end
	end
	
	local function errorFn( msg, x )
		errorSum = errorSum + x
		if 5 < x then
			error "TOO BIG"
		end
	end
	
	local success, msg = KSPCallLoops.pdoWithIterator( actionFn, errorFn, sourceFn )
	
	assert( not success, "pdoWithIterator should have failed" )
	
	assert( string.find( msg, "TOO BIG" ),
		"Message from error function should have come through" )

	assert( sum == 21, "Sum should have been 55" )
	assert( errorSum == 9, "Error sum should have been 9" )

end

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

function T.testSeq2()

	local i = 0
	
	local function sourceFn()
		i = i + 1
		if i < 11 then
			return i, i * i
		end
	end
	
	local sum = 0
	
	local function actionFn( x, xx )
		sum = sum + x + xx
		if x % 3 == 0 then
			error "Multiple of three"
		end
	end
	
	local success, _ = KSPCallLoops.pdoWithIterator( actionFn, nil, sourceFn )
	
	assert( success, "pdoWithIterator should have succeeded" )
	
	assert( i == 11, "We should have completed the iteration." )

	assert( sum == 440, "Sum should have been 440 was " .. tostring( sum ) )

end

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

function T.testIterator()

	local sum = 0
	
	local function actionFn( k, v )
		sum = sum + k + v
		if k % 3 == 0 then
			error "Multiple of three"
		end
	end
	
	local success, _ = KSPCallLoops.pdoWithIterator( actionFn, nil,
			ipairs{ 1, 4, 9, 16, 25, 36, 49, 64, 81, 100 } )
	
	assert( success, "pdoWithIterator should have succeeded" )
	
	assert( sum == 440, "Sum should have been 440 was " .. tostring( sum ) )

end

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

function T.testIterator2()

	local sum = 0
	
	local function actionFn( k, v )
		sum = sum + k + v
		if k % 3 == 0 then
			error "Multiple of three"
		end
	end
	
	local success, _ = KSPCallLoops.pdoWithIterator( actionFn, nil,
			pairs{ 1, 4, 9, 16, 25, 36, 49, 64, 81, 100 } )
	
	assert( success, "pdoWithIterator should have succeeded" )
	
	assert( sum == 440, "Sum should have been 440 was " .. tostring( sum ) )

end

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

function T.testDrain()

	local i = 0
	
	local function sourceFn()
		i = i + 1
		if i < 11 then
			return i
		end
	end
	
	local sum = 0
	
	local function actionFn( x )
		sum = sum + x
		if x % 3 == 0 then
			error "Multiple of three"
		end
	end
	
	local success, _ = KSPCallLoops.pdrain( actionFn, nil, sourceFn )
	
	assert( success, "pdrain should have succeeded" )
	
	assert( i == 11, "We should have completed the iteration." )

	assert( sum == 55, "Sum should have been 55 was " .. tostring( sum ) )

end

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

function T.testDrainErrorHandling()

	local i = 0
	
	local function sourceFn()
		i = i + 1
		if i < 11 then
			return i
		end
	end
	
	local sum = 0
	local errorSum = 0
	
	local function actionFn( x )
		sum = sum + x
		if x % 3 == 0 then
			error "Multiple of three"
		end
	end
	
	local function errorFn( msg, x )
		errorSum = errorSum + x
	end
	
	local success, _ = KSPCallLoops.pdrain( actionFn, errorFn, sourceFn )

	assert( success, "pdrain should have succeeded" )

	assert( sum == 55, "Sum should have been 55" )
	assert( errorSum == 18, "Error sum should have been 18" )

end

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

function T.testDrainWithErrorInSource()

	local function sourceFn()
		error "Source Error"
	end
	
	local sum = 0
	local errorSum = 0
	
	local function actionFn( x )
		sum = sum + 1
	end
	
	local function errorFn( msg, x )
		errorSum = errorSum + 1
	end
	
	local success, msg = KSPCallLoops.pdrain( actionFn, errorFn, sourceFn )

	assert( string.find( msg, "Source Error" ), "should receive error message from sourceFn" )

	assert( not success, "pdrain should have failed because of an immediate error in sourceFn" )

	assert( sum == 0, "Sum should have been 0 since actionFn should not be called" )
	assert( errorSum == 0, "Error sum should be 0 since errorFn should not be called" )

end

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

function T.testDrainErrorHandlingWithRejection()

	local i = 0
	
	local function sourceFn()
		i = i + 1
		if i < 11 then
			return i
		end
	end
	
	local sum = 0
	local errorSum = 0
	
	local function actionFn( x )
		sum = sum + x
		if x % 3 == 0 then
			error "Multiple of three"
		end
	end
	
	local function errorFn( msg, x )
		errorSum = errorSum + x
		if 5 < x then
			error "TOO BIG"
		end
	end
	
	local success, msg = KSPCallLoops.pdrain( actionFn, errorFn, sourceFn )
	
	assert( not success, "pdrain should have failed" )
	
	assert( string.find( msg, "TOO BIG" ),
		"Message from error function should have come through" )

	assert( sum == 21, "Sum should have been 55" )
	assert( errorSum == 9, "Error sum should have been 9" )

end

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

-- FIXME: Test iterator errors in pdoWithIterator
-- FIXME: Test sourceFn errors in pdrain

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

return T
