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

WFOzDocUtilsTest.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2013 Adobe Systems Incorporated
All Rights Reserved.

NOTICE: All information contained herein is, and remains 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 are protected by all applicable
intellectual property laws, including trade secret and copyright laws.
Dissemination of this information or reproduction of this material is
strictly forbidden unless prior written permission is obtained from
Adobe Systems Incorporated.

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

	-- WF.core.self_test
local WFRxTestCase = require 'WFRxTestCase'

	-- WF.core.utils
local KSIdGenerator = require 'KSIdGenerator'
local WFPlatformInfo = require 'WFPlatformInfo'
local KSTableUtils = require 'KSTableUtils'

	-- WF.oz_client
local WFCatAssetTestUtils = require 'WFCatAssetTestUtils'
local WFCatMockCatalog = require 'WFCatMockCatalog'
local WFOzDocUtils = require 'WFOzDocUtils'

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

local WFOzDocUtilsTest = {}

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

function WFOzDocUtilsTest.rxTest_escapeUnderscoreKeyword( rxTest )

	local escapeUnderscoreKeyword = require 'WFOzDocUtils'.escapeUnderscoreKeyword
	assert( escapeUnderscoreKeyword, "WFOzDocUtils.escapeUnderscoreKeyword is not nil" )
	
	assert( escapeUnderscoreKeyword( "normal keyword" ) == "normal keyword", "normal ok" )
	assert( escapeUnderscoreKeyword( "normal_keyword" ) == "normal_keyword", "normal_ ok" )
	assert( escapeUnderscoreKeyword( "_merge" ) ~= "_merge", "reserved keyword mangled" )
	
end

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

local function createFakeWFCatalog( rxTest )
	
	local optArgs = {}
	
	if WFPlatformInfo.isMobile() then
		optArgs.indexDefinitions = 'LrmCatalogIndexDefinitions.lua'
	end

	return WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, optArgs )

end

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

function WFOzDocUtilsTest.rxTestIsAssetDocFullySyncedWithOz( rxTest )

	local wfCatalog = createFakeWFCatalog( rxTest )
	
	local assetId = KSIdGenerator.uuidInLowercaseHex()
	
	-- Create a new asset doc. By default, the asset doc has a link
	-- to the master.
	
	local optOverrides = {
		internalXmpCameraRaw = true
	}
	
	local  assetDoc = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, assetId, optOverrides )
	assetDoc._newRevId = KSIdGenerator.uuidInLowercaseHex()
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue(  assetDoc ) )
	
	-- No Oz label, so this should evaluate to false.
	
	rxTest:expectEqual( WFOzDocUtils.isAssetDocFullySyncedWithOz( assetDoc ), false )
	
	rxTest:waitFor( wfCatalog:docStore():setLabel( assetId, 'oz', assetDoc._newRevId ) )
	
	rxTest:waitFor( wfCatalog:docStore():docValue( assetId )
		:map( function( docValue )
			assetDoc = docValue
			return
		end ) )
	
	-- Now that there's an Oz label, this should be true.
	
	rxTest:expectEqual( WFOzDocUtils.isAssetDocFullySyncedWithOz( assetDoc ), true )
	
	-- Remove the master link. The asset should no longer be considered
	-- as fully synced.
	
	rxTest:waitFor( wfCatalog:docStore():applyOverlay( {
	
		_id = assetId,
		_serverProvidedMetadata = {
			links = { _delete = true }
		}
	
	} ) )
	
	rxTest:waitFor( wfCatalog:docStore():docValue( assetId )
		:map( function( docValue )
			assetDoc = docValue
			return
		end ) )
		
	rxTest:expectEqual( WFOzDocUtils.isAssetDocFullySyncedWithOz( assetDoc ), false )
	
end

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

function WFOzDocUtilsTest.rxTestAreAssetsFullySyncedWithOz( rxTest )

	local wfCatalog = createFakeWFCatalog( rxTest )

	local optOverrides = {
		internalXmpCameraRaw = true
	}

	local assetId1 = KSIdGenerator.uuidInLowercaseHex()
	local  assetDoc1 = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, assetId1, optOverrides )
	assetDoc1._newRevId = KSIdGenerator.uuidInLowercaseHex()
	
	local assetId2 = KSIdGenerator.uuidInLowercaseHex()
	local  assetDoc2 = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, assetId2, optOverrides )
	assetDoc2._newRevId = KSIdGenerator.uuidInLowercaseHex()
	
	local assetId3 = KSIdGenerator.uuidInLowercaseHex()
	local  assetDoc3 = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, assetId3, optOverrides )
	assetDoc3._newRevId = KSIdGenerator.uuidInLowercaseHex()
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue(  assetDoc1 ) )
	rxTest:waitFor( wfCatalog:docStore():setDocValue(  assetDoc2 ) )
	rxTest:waitFor( wfCatalog:docStore():setDocValue(  assetDoc3 ) )
	
	local assetIds = { assetId1, assetId2, assetId3 }
	
	-- No assets have Oz labels, so this should be false.
	
	rxTest:expectSingleValue( WFOzDocUtils.areAssetsFullySyncedWithOz( wfCatalog, assetIds ), false )
	
	rxTest:waitFor( wfCatalog:docStore():setLabel( assetId1, 'oz', assetDoc1._newRevId ) )
	
	-- This should still evaluate to false since only asset as the label.
	
	rxTest:expectSingleValue( WFOzDocUtils.areAssetsFullySyncedWithOz( wfCatalog, assetIds ), false )
	
	rxTest:waitFor( wfCatalog:docStore():setLabel( assetId2, 'oz', assetDoc2._newRevId ) )
	rxTest:waitFor( wfCatalog:docStore():setLabel( assetId3, 'oz', assetDoc3._newRevId ) )
	
	-- All assets have an Oz label. This should evaluate to true.
	
	rxTest:expectSingleValue( WFOzDocUtils.areAssetsFullySyncedWithOz( wfCatalog, assetIds ), true )
	
end

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

function WFOzDocUtilsTest.rxTestWaitUntilAssetsAreFullySyncedWithOz( rxTest )

	rxTest:setTimeLimit( 10 )

	local wfCatalog = createFakeWFCatalog( rxTest )

	local optOverrides = {
		internalXmpCameraRaw = true
	}

	local assetId1 = KSIdGenerator.uuidInLowercaseHex()
	local  assetDoc1 = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, assetId1, optOverrides )
	assetDoc1._newRevId = KSIdGenerator.uuidInLowercaseHex()
	
	local assetId2 = KSIdGenerator.uuidInLowercaseHex()
	local  assetDoc2 = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, assetId2, optOverrides )
	assetDoc2._newRevId = KSIdGenerator.uuidInLowercaseHex()
	
	local assetId3 = KSIdGenerator.uuidInLowercaseHex()
	local  assetDoc3 = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, assetId3, optOverrides )
	assetDoc3._newRevId = KSIdGenerator.uuidInLowercaseHex()
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue(  assetDoc1 ) )
	rxTest:waitFor( wfCatalog:docStore():setDocValue(  assetDoc2 ) )
	rxTest:waitFor( wfCatalog:docStore():setDocValue(  assetDoc3 ) )
	
	local assetIds = { assetId1, assetId2, assetId3 }
	
	-- Subscribe to the stream that fires when all assetse are fully synced.
	
	local areFullySynced = false
	
	local subscription = WFOzDocUtils.waitUntilAssetsAreFullySyncedWithOz( wfCatalog, assetIds )
		:map( function()
			areFullySynced = true
			return true
		end )
		:subscribe()
	
	-- No assets have Oz labels, so this should be false.
	
	rxTest:expectEqual( false, areFullySynced )
	
	-- Make 1 asset fully synced.
	
	local overlay = {
		_id = assetId1,
		_localOnly = {
			foo = true
		},
		_newLabel = 'oz'
	}
	
	rxTest:waitFor( wfCatalog:docStore():applyOverlay( overlay ) )
	
	-- This should still evaluate to false since the other assets are not fully synced.
	
	rxTest:expectEqual( false, areFullySynced )
	
	-- Make all assets fully synced.
	
	overlay._id = assetId2
	rxTest:waitFor( wfCatalog:docStore():applyOverlay( overlay ) )
	
	overlay._id = assetId3
	rxTest:waitFor( wfCatalog:docStore():applyOverlay( overlay ) )
	
	-- Now waitUntilAssetsAreFullySyncedWithOz should fire with true.
	
	rxTest:sleep( 2 )
	
	rxTest:expectEqual( true, areFullySynced )
	
	subscription:dispose()
	
end

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

local function setOzLinkInvalid( docValue, binaryType, isInvalid )

	local invalid = isInvalid and true or nil

	KSTableUtils.setNested( docValue, invalid, '_serverProvidedMetadata', 'links', binaryType, 'invalid' )
	
	return docValue
	
end

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

local function setOzLinkHrefOrExists( docValue, binaryType, urlOrExists )

	if type( urlOrExists ) == 'string' then

		KSTableUtils.setNested( docValue, urlOrExists, '_serverProvidedMetadata', 'links', binaryType, 'href' )
		KSTableUtils.setNested( docValue, nil, '_serverProvidedMetadata', 'links', binaryType, 'exists' )
	
	elseif type( urlOrExists ) == 'boolean' then
		
		KSTableUtils.setNested( docValue, nil, '_serverProvidedMetadata', 'links', binaryType, 'href' )
		KSTableUtils.setNested( docValue, urlOrExists, '_serverProvidedMetadata', 'links', binaryType, 'exists' )
	
	elseif urlOrExists == nil then
		
		KSTableUtils.setNested( docValue, nil, '_serverProvidedMetadata', 'links', binaryType, 'href' )
		KSTableUtils.setNested( docValue, nil, '_serverProvidedMetadata', 'links', binaryType, 'exists' )
		
	end
	
	return docValue
	
end

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

function WFOzDocUtilsTest.rxTestIsOriginalAvailableOnOz( rxTest )

	rxTest:setTimeLimit( 300 )

	local wfCatalog = createFakeWFCatalog( rxTest )
	
	local assetDoc = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog )
	assetDoc._spaceId = KSIdGenerator.uuidInLowercaseHex()
	
	local masterBinaryType = '/rels/master'
	
	-- asset with master link
	
	rxTest:expectEqual( true, WFOzDocUtils.isOriginalAvailableOnOz( assetDoc ) )
	rxTest:expectEqual( true, WFOzDocUtils.isValidOriginalAvailableOnOz( assetDoc ) )
	
	-- asset with master link, but invalid is true
	
	assetDoc = setOzLinkInvalid( assetDoc, masterBinaryType, true )
	
	rxTest:expectEqual( true, WFOzDocUtils.isOriginalAvailableOnOz( assetDoc ) )
	rxTest:expectEqual( false, WFOzDocUtils.isValidOriginalAvailableOnOz( assetDoc ) )
	
	-- asset without master link, with master exists field
	
	assetDoc = setOzLinkHrefOrExists( assetDoc, masterBinaryType, true )
	assetDoc = setOzLinkInvalid( assetDoc, masterBinaryType, false )
	
	rxTest:expectEqual( true, WFOzDocUtils.isOriginalAvailableOnOz( assetDoc ) )
	rxTest:expectEqual( true, WFOzDocUtils.isValidOriginalAvailableOnOz( assetDoc ) )
	
	-- asset without master link, with master exists field, but invalid is true
	
	assetDoc = setOzLinkInvalid( assetDoc, masterBinaryType, true )
	
	rxTest:expectEqual( true, WFOzDocUtils.isOriginalAvailableOnOz( assetDoc ) )
	rxTest:expectEqual( false, WFOzDocUtils.isValidOriginalAvailableOnOz( assetDoc ) )
	
	-- asset without master link, without exists field
	
	assetDoc = setOzLinkHrefOrExists( assetDoc, masterBinaryType, nil )
	assetDoc = setOzLinkInvalid( assetDoc, masterBinaryType, false )
	
	rxTest:expectEqual( false, WFOzDocUtils.isOriginalAvailableOnOz( assetDoc ) )
	rxTest:expectEqual( false, WFOzDocUtils.isValidOriginalAvailableOnOz( assetDoc ) )

end


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

function WFOzDocUtilsTest.rxTestIsProxyAvailableOnOz( rxTest )

	rxTest:setTimeLimit( 300 )

	local wfCatalog = createFakeWFCatalog( rxTest )
	
	local assetDoc = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog )
	assetDoc._spaceId = KSIdGenerator.uuidInLowercaseHex()
	
	local proxyBinaryType = '/rels/proxy_type/2560'
	
	-- asset with proxy link
	
	rxTest:expectEqual( true, WFOzDocUtils.isProxyAvailableOnOz( assetDoc ) )
	rxTest:expectEqual( true, WFOzDocUtils.isValidProxyAvailableOnOz( assetDoc ) )
	
	-- asset with proxy link, but invalid is true
	
	assetDoc = setOzLinkInvalid( assetDoc, proxyBinaryType, true )
	
	rxTest:expectEqual( true, WFOzDocUtils.isProxyAvailableOnOz( assetDoc ) )
	rxTest:expectEqual( false, WFOzDocUtils.isValidProxyAvailableOnOz( assetDoc ) )
	
	-- asset without proxy link, with proxy exists field
	
	assetDoc = setOzLinkHrefOrExists( assetDoc, proxyBinaryType, true )
	assetDoc = setOzLinkInvalid( assetDoc, proxyBinaryType, false )
	
	rxTest:expectEqual( true, WFOzDocUtils.isProxyAvailableOnOz( assetDoc ) )
	rxTest:expectEqual( true, WFOzDocUtils.isValidProxyAvailableOnOz( assetDoc ) )
	
	-- asset without proxy link, with proxy exists field, but invalid is true
	
	assetDoc = setOzLinkInvalid( assetDoc, proxyBinaryType, true )
	
	rxTest:expectEqual( true, WFOzDocUtils.isProxyAvailableOnOz( assetDoc ) )
	rxTest:expectEqual( false, WFOzDocUtils.isValidProxyAvailableOnOz( assetDoc ) )
	
	-- asset without proxy link, without exists field
	
	assetDoc = setOzLinkHrefOrExists( assetDoc, proxyBinaryType, nil )
	assetDoc = setOzLinkInvalid( assetDoc, proxyBinaryType, false )
	
	rxTest:expectEqual( false, WFOzDocUtils.isProxyAvailableOnOz( assetDoc ) )
	rxTest:expectEqual( false, WFOzDocUtils.isValidProxyAvailableOnOz( assetDoc ) )

end

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

function WFOzDocUtilsTest.rxTestDoesDocumentNeedXmpDevelopSettingsUploaded( rxTest )

	local wfCatalog = createFakeWFCatalog( rxTest )
	
	-- Create a new asset doc with no external develop settings.
	
	local optOverrides = {
		internalXmpCameraRaw = true
	}
	
	local assetDoc = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, KSIdGenerator.uuidInLowercaseHex(), optOverrides )
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( assetDoc ) )
	
	rxTest:expectEqual( WFOzDocUtils.doesDocumentNeedXmpDevelopSettingsUploaded( assetDoc ), false )
	
	-- Create a new asset doc. By default, the asset doc has external xmp which
	-- has not yet synced.
	
	local assetId = KSIdGenerator.uuidInLowercaseHex()
	
	assetDoc = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, assetId )
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue(  assetDoc ) )
	
	rxTest:expectEqual( WFOzDocUtils.doesDocumentNeedXmpDevelopSettingsUploaded( assetDoc ), true )
	
	-- Make it look like the external xmp is synced.
	
	rxTest:waitFor( wfCatalog:docStore():applyOverlay( {
	
		_id = assetId,
		_serverProvidedMetadata = {
			links = {
				[ '/rels/xmp/develop' ] = {
					href = 'foo'
				}
			}
		}
	
	} ) )

	assetDoc = rxTest:getFirstValue( wfCatalog:docStore():docValue( assetId ) )
	
	rxTest:expectEqual( WFOzDocUtils.doesDocumentNeedXmpDevelopSettingsUploaded( assetDoc ), false )
	
	-- Now make it look like the synced xmp is invalid.
	
	rxTest:waitFor( wfCatalog:docStore():applyOverlay( {
	
		_id = assetId,
		_serverProvidedMetadata = {
			links = {
				[ '/rels/xmp/develop' ] = {
					invalid = true
				}
			}
		}
	
	} ) )

	assetDoc = rxTest:getFirstValue( wfCatalog:docStore():docValue( assetId ) )
	
	rxTest:expectEqual( WFOzDocUtils.doesDocumentNeedXmpDevelopSettingsUploaded( assetDoc ), true )
	
	-- Now make it look like a SWY asset that exists on Oz.
	
	rxTest:waitFor( wfCatalog:docStore():applyOverlay( {
	
		_id = assetId,
		_spaceId = KSIdGenerator.uuidInLowercaseHex(),
		_serverProvidedMetadata = {
			editable = false,
			links = {
				[ '/rels/xmp/develop' ] = {
					exists = true,
					href = { _delete = true },
					invalid = { _delete = true }
				}
			}
		}
	
	} ) )

	assetDoc = rxTest:getFirstValue( wfCatalog:docStore():docValue( assetId ) )
	
	rxTest:expectEqual( WFOzDocUtils.doesDocumentNeedXmpDevelopSettingsUploaded( assetDoc ), false )
	
end

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

-- SPAM [jandrew 2021-08-23]: This test only runs on Desktop because mobile doesn't
-- support uploading xmp sidecars, AFAIK.

if WFPlatformInfo.isDesktop then

function WFOzDocUtilsTest.rxTestDoesDocumentNeedXmpSidecarUploaded( rxTest )

	local wfCatalog = createFakeWFCatalog( rxTest )
	
	-- Create a new asset doc
	
	local assetDoc = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, KSIdGenerator.uuidInLowercaseHex() )
	
	rxTest:expectEqual( WFOzDocUtils.doesDocumentNeedXmpSidecarUploaded( assetDoc ), false )
	
	-- locally imported, no local xmp sidecar
	
	local optOverrides = {
		localXmpSidecarDoesNotExist = true
	}
	
	assetDoc = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, KSIdGenerator.uuidInLowercaseHex(), optOverrides )
	
	rxTest:expectEqual( WFOzDocUtils.doesDocumentNeedXmpSidecarUploaded( assetDoc ), false )
	
	-- local xmp sidecar, no sidecar on Oz
	
	optOverrides = {
		noXmpSidecarLink = true
	}
	
	assetDoc = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, KSIdGenerator.uuidInLowercaseHex(), optOverrides )
	
	rxTest:expectEqual( WFOzDocUtils.doesDocumentNeedXmpSidecarUploaded( assetDoc ), true )
	
end

end

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

function WFOzDocUtilsTest.rxTestDoesDocumentNeedOriginalOrProxyUploaded( rxTest )

	local wfCatalog = createFakeWFCatalog( rxTest )
	
	-- Create a new asset doc. By default, the asset doc has a link
	-- to the master and the proxy.
	
	local assetDoc = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, KSIdGenerator.uuidInLowercaseHex() )
	
	rxTest:expectEqual( WFOzDocUtils.doesDocumentNeedOriginalOrProxyUploaded( assetDoc ), false )
	
	-- An asset with an invalid original needs an upload
	
	KSTableUtils.setNested( assetDoc, true, "_serverProvidedMetadata", "links", '/rels/master', 'invalid' )
	
	rxTest:expectEqual( WFOzDocUtils.doesDocumentNeedOriginalOrProxyUploaded( assetDoc ), true )
	
	-- An asset with no original, but a valid proxy is okay
	
	KSTableUtils.setNested( assetDoc, nil, "_serverProvidedMetadata", "links", '/rels/master' )
	
	rxTest:expectEqual( WFOzDocUtils.doesDocumentNeedOriginalOrProxyUploaded( assetDoc ), false )
	
	-- But an asset with no original, and an invalid proxy, needs an upload.
	
	KSTableUtils.setNested( assetDoc, true, "_serverProvidedMetadata", "links", '/rels/proxy_type/2560', 'invalid' )
	
	rxTest:expectEqual( WFOzDocUtils.doesDocumentNeedOriginalOrProxyUploaded( assetDoc ), true )
	
	-- An asset with no original and no proxy needs an upload.
	
	KSTableUtils.setNested( assetDoc, nil, "_serverProvidedMetadata", "links", '/rels/proxy_type/2560' )
	
	rxTest:expectEqual( WFOzDocUtils.doesDocumentNeedOriginalOrProxyUploaded( assetDoc ), true )
	
end

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

return WFRxTestCase.wrapSuite( WFOzDocUtilsTest )
