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

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

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

	-- wichitafoundation.core.lua
local WFWorkerThread = require 'WFWorkerThread'

	-- wichitafoundation.core.self_test
local WFAsyncTestCase = require 'WFAsyncTestCase'
local WFRxTestCase = require 'WFRxTestCase'

local WFPlatformInfo = require 'WFPlatformInfo'
local WFTimer = require 'WFTimer'

--============================================================================--

local KSPrefsTest = {}

local prefs = require 'KSPrefs'

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

function KSPrefsTest.tearDown()

	if WFPlatformInfo.isWindows then
		local KSPrefsImpLua = require 'KSPrefsImpLua'
		KSPrefsImpLua.deletePrefsFile()
	end

end

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

local TEST_PERSISTENCE = false -- should normally be false
	-- Set this flag to true to test preferences persistence. We always write
	-- expected values to prefs and read them back within the scope of the test.
	-- This will cause us to also test the value on entry to the test; the test
	-- will fail if the expected value wasn't already there. We still perform
	-- this test when TEST_PERSISTENCE is false, but in that case we also accept
	-- nil (i.e. not previously initialized).

--------------------------------------------------------------------------------
-- Verify that we can write a value to prefs key and recall it.

local function testPrefsValue( key, expectedValue )

	-- Test existing value. See comment above about the meaning of TEST_PERSISTENCE.

	local existingValue = prefs[ key ]
	if TEST_PERSISTENCE or existingValue ~= nil then
		if existingValue ~= expectedValue then
			error( string.format( "prefs[ %q ] had unexpected value on entry %s: expected %s",
								key, existingValue, expectedValue ) )
		end
	end
	
	-- Write the value to prefs.

	prefs[ key ] = expectedValue
	
	-- Read value back from prefs.
	
	existingValue = prefs[ key ]
	if TEST_PERSISTENCE or existingValue ~= nil then
		if existingValue ~= expectedValue then
			error( string.format( "prefs[ %q ] had unexpected value after write %s: expected %s",
								key, existingValue, expectedValue ) )
		end
	end

end

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

function KSPrefsTest.testReadWriteString()

	testPrefsValue( 'unitTestItemString', 'testValue' )
	testPrefsValue( 'unitTestItemEmptyString', '' )

end

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

function KSPrefsTest.testReadWriteBoolean()

	testPrefsValue( 'unitTestItemBooleanTrue', true )
	testPrefsValue( 'unitTestItemBooleanFalse', false )

end

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

function KSPrefsTest.testReadWriteNumber()

	testPrefsValue( 'unitTestItemNumber42', 42 )
	
	-- Android, because of the jump across JNI ends up losing a bit of precision and the
	-- return value is something like 3.141590011, so I am bailing on this test
	if not WFPlatformInfo.isAndroid then
		testPrefsValue( 'unitTestItemNumberPi', 3.14159 )
	end
	
	testPrefsValue( 'unitTestItemNumberZero', 0 )

end

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

function KSPrefsTest.testAssignNil()
	
	prefs.unitTestItemNil = 42
	prefs.unitTestItemNil = nil
	
	assert( prefs.unitTestItemNil == nil, "failed to retain nil value properly" )

end

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

function KSPrefsTest.testAssignNilWithoutPreviousValue()
	
	-- Make sure that we can store nil when we've never seen a previous value.

	testPrefsValue( 'unitTestItemNilWithoutPreviousValue', nil )
	
end

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

function KSPrefsTest.testFailWriteTable()

	local success = pcall( function()
		
		prefs.unitTestItemTable = {}
	
	end )
	
	if success then
		error "should not have accepted table value"
	end

end

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

function KSPrefsTest.testFailWriteFunction()

	local success = pcall( function()
		
		prefs.unitTestItemTable = function() end
	
	end )
	
	if success then
		error "should not have accepted function value"
	end

end

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

local function testReadInvalidPrefsKey( key, value )

	local success = pcall( function()
	
		return prefs[ key ]
	
	end )
	
	if success then
		error( string.format( "should have thrown an error when reading prefs key of type %s", type( key ) ) )
	end

end

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

function KSPrefsTest.testReadInvalidPrefsKeys()

	testReadInvalidPrefsKey( nil )
	testReadInvalidPrefsKey( 42 )
	testReadInvalidPrefsKey( true )
	testReadInvalidPrefsKey( false )
	testReadInvalidPrefsKey( {} )
	testReadInvalidPrefsKey( function() end )

end

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

local function testWriteInvalidPrefsKey( key, value )

	local success = pcall( function()
	
		prefs[ key ] = "this shouldn't work"
	
	end )
	
	if success then
		error( string.format( "should have thrown an error when writing prefs key of type %s", type( key ) ) )
	end

end

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

function KSPrefsTest.testWriteInvalidPrefsKeys()

	testWriteInvalidPrefsKey( nil )
	testWriteInvalidPrefsKey( 42 )
	testWriteInvalidPrefsKey( true )
	testWriteInvalidPrefsKey( false )
	testWriteInvalidPrefsKey( {} )
	testWriteInvalidPrefsKey( function() end )

end

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

function KSPrefsTest.testPrefBSynchronous( test )

	prefs.foo = 42
	
	local fooPrefB = prefs.prefB 'foo'
	
	WFAsyncTestCase( test, 2 )

		:waitFor( function()
			-- The underlying reactive network ( RxLua ) asynchronously sets
			-- values of observables so this delay is necessary.
			return WFTimer.afterDelayP( 0.01 )
		end )
		
		:whenResolvedDo( function()
			assert( fooPrefB:valueNow() == 42, "initial value wrong" )
		end )
		
		:waitFor( function()
			prefs.foo = 43
			return WFTimer.afterDelayP( 0.01 )
		end )
		
		:whenResolvedDo( function()
			assert( fooPrefB:valueNow() == 43, "initial value wrong" )
		end )

end

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

function KSPrefsTest.testPrefBUpdateFromOtherThread_testNightly( test )

	prefs.foo = 42
	
	local fooPrefB = prefs.prefB 'foo'

	local tempEP = WFWorkerThread( "KSPrefsTestAsyncHelper.lua" )
	
	WFAsyncTestCase( test, 30 )

		:waitFor( fooPrefB )
		:continueWhenValueMatches( 42 )
		
		:waitFor( function()

			-- Set the pref from 42 to 43, but do it in another thread.

			local set43P = tempEP:requestP('set43')

			return set43P
		
		end )
		
		:whenResolvedDo( function( status, data )

			tempEP:close()
		
			assert( status == 'data' and data == true )
			
		end )

		:waitFor( fooPrefB )
		:continueWhenValueMatches( 43 )
	
end

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

function KSPrefsTest.rxTestPrefsObservable( rxTest )

	prefs.baz = 42
	
	local bazPref = prefs.pref 'baz'
	
	local bazData = rxTest:observe( bazPref )
	
	bazData:expectData( 42 )

	prefs.baz = 43
	
	bazData:expectData( 43 )
	
	prefs.baz = 44
	
	bazData:expectData( 44 )

end

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

if not WFPlatformInfo.isAndroid then

function KSPrefsTest.rxTestDeleteAllPreferences( rxTest )

	-- Verify prefs read/write

	prefs[ 'a' ] = 1
	prefs[ 'b' ] = 2
	prefs[ 'c' ] = 3
	prefs[ 'd' ] = 4
	prefs[ 'e' ] = 5
	
	rxTest:expectEqual( prefs[ 'a' ], 1 )
	rxTest:expectEqual( prefs[ 'b' ], 2 )
	rxTest:expectEqual( prefs[ 'c' ], 3 )
	rxTest:expectEqual( prefs[ 'd' ], 4 )
	rxTest:expectEqual( prefs[ 'e' ], 5 )
	
	-- Delete all prefs
	
	if WFPlatformInfo.isWindows then
		prefs.deleteAllPrefs()
	elseif WFPlatformInfo.isCocoa then
		prefs.deleteAllPreferencesForBundle()
		
		-- Verify all prefs were deleted
		
		rxTest:expectEqual( prefs[ 'a' ], nil )
		rxTest:expectEqual( prefs[ 'b' ], nil )
		rxTest:expectEqual( prefs[ 'c' ], nil )
		rxTest:expectEqual( prefs[ 'd' ], nil )
		rxTest:expectEqual( prefs[ 'e' ], nil )
		
		-- Verify read/write after delete
		
		prefs[ 'a' ] = 1
		rxTest:expectEqual( prefs[ 'a' ], 1 )
		
	end
	
end

end

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

return WFRxTestCase.wrapSuite( 'KSPrefsTest', KSPrefsTest )
