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

KSRPackedValuesTest.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2010 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 KSRPackedValuesTest = { }

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

local select = select

local KSTestUtils = require 'KSTestUtils'

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

local function testNonError( KSRPackedValues, ident, value )

	assert( not KSRPackedValues.isError( value ), ident .. " should not report as error" )
	
	assert( pcall( KSRPackedValues.throwOnError, value ) == true, ident .. " should not throw on error" )

end

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

function KSRPackedValuesTest.testPackedNone()

	local KSRPackedValues = assert( require 'KSRPackedValues' )
	
	local pnone = assert( KSRPackedValues.pack(), "None should pack to a value" )
	
	testNonError( KSRPackedValues, "< none >", pnone )
	
	assert( KSTestUtils.testResults( KSRPackedValues.unpack, pnone )(),
			"None should unpack to nothing" )

end

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

function KSRPackedValuesTest.testPackedOne()

	local KSRPackedValues = assert( require 'KSRPackedValues' )
	
	local x = { }
	
	local px = assert( KSRPackedValues.pack( x ), "Packing should result in a value" )
	
	testNonError( KSRPackedValues, "< packed one >", px )
	
	assert( KSTestUtils.testResults( KSRPackedValues.unpack, px )( x ),
			"Unpacking should result in the value" )
	
	x = nil
	collectgarbage()
	collectgarbage()
	collectgarbage()
	
	assert( KSRPackedValues.unpack( px ), "Packed value should survive GC" )
	
end

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

function KSRPackedValuesTest.testPackedNil()

	local KSRPackedValues = assert( require 'KSRPackedValues' )
	
	local pnil = KSRPackedValues.pack( nil )
	
	assert( pnil, "Packing nil should result in a value" )
	
	testNonError( KSRPackedValues, "< packed nil >", pnil )

	assert( KSTestUtils.testResults( KSRPackedValues.unpack, pnil )( nil ),
			"Unpacking nil result in nil" )
	
end

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

function KSRPackedValuesTest.testPackedFalse()

	local KSRPackedValues = assert( require 'KSRPackedValues' )
	
	local pfalse = KSRPackedValues.pack( false )
	
	assert( pfalse, "Packing false should result in a true value" )
	
	testNonError( KSRPackedValues, "< packed false >", pfalse )
	
	assert( KSTestUtils.testResults( KSRPackedValues.unpack, pfalse )( false ),
			"Unpacking the false tuple should yield false" )

end

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

function KSRPackedValuesTest.testPackedOneOptimized()

	local KSRPackedValues = assert( require 'KSRPackedValues' )
	
	local x = { }
	
	local px = assert( KSRPackedValues.packOne( x ), "Packing should result in a value" )
	
	testNonError( KSRPackedValues, "< packed one >", px )
	
	assert( select( '#', KSRPackedValues.unpack( px ) ) == 1,
		"Unpacking one should yield one" )
		
	assert( KSRPackedValues.unpack( px ) == x, "Unpacking should result in the value." )
	
	x = nil
	collectgarbage()
	collectgarbage()
	collectgarbage()
	
	assert( KSRPackedValues.unpack( px ), "Packed value should survive GC" )
	
	local pnil = KSRPackedValues.packOne( nil )
	
	assert( pnil, "Packing nil should result in a value" )
	
	testNonError( KSRPackedValues, "< packed nil >", pnil )

	assert( KSTestUtils.testResults( KSRPackedValues.unpack, pnil )( nil ),
			"Unpacking nil result in nil" )
	
	local pfalse = KSRPackedValues.packOne( false )
	
	assert( pfalse, "Packing false should result in a true value" )
	
	testNonError( KSRPackedValues, "< packed false >", pfalse )
	
	assert( KSTestUtils.testResults( KSRPackedValues.unpack, pfalse )( false ),
			"Unpacking the false tuple should yield false" )

end

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

function KSRPackedValuesTest.testPackedMany()

	local KSRPackedValues = assert( require 'KSRPackedValues' )
	
	local x = { }
	local y = { }
	
	local pxy = assert( KSRPackedValues.pack( x, y ), "Packing should result in a value" )
	
	testNonError( KSRPackedValues, "< packed many >", pxy )
	
	assert( select( '#', KSRPackedValues.unpack( pxy ) ) == 2,
		"Unpacking one should yield one" )
		
	local xx, yy = KSRPackedValues.unpack( pxy )
		
	assert( xx == x and yy == y, "Unpacking should result in the values." )
	
	x = nil
	y = nil
	xx = nil
	yy = nil
	collectgarbage()
	collectgarbage()
	collectgarbage()
	
	assert( select( '#', KSRPackedValues.unpack( pxy ) ) == 2, "Packed value should survive GC" )
	
	xx, yy = KSRPackedValues.unpack( pxy )
	
	assert( xx and yy, "Packed values should survive GC" )

end

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

function KSRPackedValuesTest.testPackedLeadingNil()

	local KSRPackedValues = assert( require 'KSRPackedValues' )
	
	local y = { }
	
	local pnily = assert( KSRPackedValues.pack( nil, y ), "Packing should result in a value" )
	
	testNonError( KSRPackedValues, "< packed leading nil >", pnily )
	
	assert( select( '#', KSRPackedValues.unpack( pnily ) ) == 2,
		"Unpacking nil + value should yield two values" )
		
	local xx, yy = KSRPackedValues.unpack( pnily )
		
	assert( xx == nil and yy == y, "Unpacking should result in the values." )
	
end

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

function KSRPackedValuesTest.testPackedTrailingNil()

	local KSRPackedValues = assert( require 'KSRPackedValues' )
	
	local x = { }
	
	local pxnil = assert( KSRPackedValues.pack( x, nil ), "Packing should result in a value" )
	
	testNonError( KSRPackedValues, "< packed trailing nil >", pxnil )

	assert( select( '#', KSRPackedValues.unpack( pxnil ) ) == 2,
		"Unpacking value + nil should yield two values" )
		
	local xx, yy = KSRPackedValues.unpack( pxnil )
		
	assert( xx == x and yy == nil, "Unpacking should result in the values." )

end

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

local function testIsErrorResult( x, ... )

	if not x then
		return false
	end
	
	return select( '#', ... ) == 1
	
end

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

local function testError( KSRPackedValues, ident, err )

	assert( testIsErrorResult( KSRPackedValues.isError( err ) ),
						ident .. " should be reported as an error" )

	assert( KSRPackedValues.unpack( err ) == err, ident .. " should unpack as itself" )
	
	assert( pcall( KSRPackedValues.throwOnError, err ) == false,
						ident .. " should result in throwOnError throwing" )

end

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

function KSRPackedValuesTest.testNullError()

	local KSRPackedValues = assert( require 'KSRPackedValues' )
	
	local err = KSRPackedValues.error()
	
	testError( KSRPackedValues, "< null error >", err )

end

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

function KSRPackedValuesTest.testErrorWithMessage()

	local KSRPackedValues = assert( require 'KSRPackedValues' )
	
	local err = KSRPackedValues.error( "Message Text" )
	
	local isError, msg = KSRPackedValues.isError( err )
	
	assert( isError, "Error with message should be an error" )
	
	assert( msg == "Message Text", "Message text should be correct." )
	
	testError( KSRPackedValues, "< error with message >", err )

end

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

local function assertOne( ident, value, ... )

	assert( select( '#', ... ) == 1, ident .. " should return one value" )
	
	local x = ...
	
	assert( x == value, ident .. " should return the right value" )

end

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

function KSRPackedValuesTest.testFirst()

	local KSRPackedValues = assert( require 'KSRPackedValues' )
	
	local nullError = KSRPackedValues.error()
	
	local err = KSRPackedValues.error( "Error Message" )
	
	local pnone = KSRPackedValues.pack()
	
	local pnil = KSRPackedValues.pack( nil )
	
	local psingle = KSRPackedValues.pack( 1 )
	
	local pmany = KSRPackedValues.pack( 1, 2 )
	
	assertOne( "first( nullError )", nullError, KSRPackedValues.first( nullError ) )
	
	assertOne( "first( err )", err, KSRPackedValues.first( err ) )
	
	assert( select( '#', KSRPackedValues.first( pnone ) ) == 0, "first( none ) should return nothing" )
	
	assertOne( "first( pnil )", nil, KSRPackedValues.first( pnil ) )
	
	assertOne( "first( psingle )", 1, KSRPackedValues.first( psingle ) )
	
	assertOne( "first( pmany )", 1, KSRPackedValues.first( pmany ) )
	
end

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

function KSRPackedValuesTest.testEquals()

	local KSRPackedValues = assert( require 'KSRPackedValues' )
	
	local nullError_a = KSRPackedValues.error()
	local nullError_b = KSRPackedValues.error()
	
	local error_a = KSRPackedValues.error( "Error Message" )
	local error_b = KSRPackedValues.error( "Error Message" )
	
	local error_c = KSRPackedValues.error( "Other Message" )
	local error_d = KSRPackedValues.error( "Other Message" )
	
	local packed0_a = KSRPackedValues.pack()
	local packed0_b = KSRPackedValues.pack()

	local packed1_a = KSRPackedValues.pack( 'x' )
	local packed1_b = KSRPackedValues.pack( 'x' )

	local packed1_c = KSRPackedValues.pack( 'y' )
	local packed1_d = KSRPackedValues.pack( 'y' )

	local packed2_a = KSRPackedValues.pack( 'x', 'y' )
	local packed2_b = KSRPackedValues.pack( 'x', 'y' )
	
	local casePairs = {
		{ 'null error', nullError_a, nullError_b },
		{ 'error with message', error_a, error_b },
		{ 'other error with message', error_c, error_d },
		{ 'packed 0', packed0_a, packed0_b },
		{ 'packed 1', packed1_a, packed1_b },
		{ 'other packed 1', packed1_c, packed1_d },
		{ 'packed 2', packed2_a, packed2_b },
	}
	
	for i = 1, #casePairs do
		local casePair = casePairs[ i ]
		assert( KSRPackedValues.testEquals( casePair[ 2 ], casePair[ 3 ] ),
			casePair[ 1 ] .. ": values should be equal" )
	end
	
	for i = 1, #casePairs - 1 do
		for j = i + 1, #casePairs do
			local casePair_i = casePairs[ i ]
			local casePair_j = casePairs[ j ]
			assert( not KSRPackedValues.testEquals( casePair_i[ 2 ], casePair_j[ 2 ] ),
				casePair_i[ 1 ] .. " v " .. casePair_j[ 1 ] .. ": values should not be equal" )
		end
	end

end

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

function KSRPackedValuesTest.testEqualsOptEqualityTest()

	local KSRPackedValues = assert( require 'KSRPackedValues' )
	
	local packed1_a = KSRPackedValues.pack( 'x' )
	local packed1_b = KSRPackedValues.pack( 'X' )

	local packed1_c = KSRPackedValues.pack( 'y' )
	
	local function equality( a, b )
		return string.lower( a ) == string.lower( b )
	end
	
	assert( not KSRPackedValues.testEquals( packed1_a, packed1_b ),
		"Different values should report non-equal" )
	
	assert( KSRPackedValues.testEquals( packed1_a, packed1_b, equality ),
		"Equality test should render more values equal" )
	
	assert( not KSRPackedValues.testEquals( packed1_a, packed1_c, equality ),
		"Equality test should not render all values equal" )

end

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

--[[

FIXME [mhamburg 2011-03-10]: implement testPackPCall

function KSRPackedValuesTest.testPackPCall()

	local KSRPackedValues = assert( require 'KSRPackedValues' )
	
end

]]

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

return KSRPackedValuesTest
