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

ADOBE CONFIDENTIAL
------------------
Copyright 2019 Adobe
All Rights Reserved.

NOTICE: All information contained herein is, and remains
the property of Adobe and its suppliers, if any. The intellectual
and technical concepts contained herein are proprietary to Adobe
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.

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

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

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

    -- WF.oz_client.managed_catalog
local WFCatAssetUtils = require 'WFCatAssetUtils'
local WFCatAssetTestUtils = require 'WFCatAssetTestUtils'
local WFCatMockCatalog = require 'WFCatMockCatalog'

	-- WF.oz_client.utils
local OzFilePaths

if WFPlatformInfo.isiOS then

	OzFilePaths = require 'OzFilePaths'

end

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

local derefUniversal = assert( WFCatAssetUtils.derefUniversal )
local universalPath = assert( WFCatAssetUtils.universalPath )

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

local WFCatAssetUtilsTest = {}

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


local _wfCatalog

local function createFakeWFCatalogForTestSuite( rxTest )

	if not _wfCatalog then

		local optArgs = {
			keepOpenAfterTestFinishes = true
		}

		if WFPlatformInfo.isMobile() then
			optArgs.indexDefinitions = 'LrmCatalogIndexDefinitions.lua'
		end

		_wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest , nil, nil, optArgs )

	end

	return _wfCatalog

end

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

local function buildDocValue( rxTest, overrides )

	local assetId = KSIdGenerator.uuidInLowercaseHex()

	local wfCatalog = createFakeWFCatalogForTestSuite( rxTest )

	local docValue, expectedData = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, assetId, overrides )

	return docValue, expectedData, wfCatalog

end

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

function WFCatAssetUtilsTest.rxTestGetFullOriginalPathFromDocValue( rxTest )

	local docValue, expectedData = buildDocValue( rxTest )

	local result = WFCatAssetUtils.getFullOriginalPathFromDocValue( docValue )

	local expected = expectedData.originalFilePath

	rxTest:expectEqual( expected, result )

	local overrides = {
		docSubtype = "preset"
	}

	docValue, expectedData = buildDocValue( rxTest, overrides )

	result = WFCatAssetUtils.getFullOriginalPathFromDocValue( docValue )

	expected = expectedData.presetFilePath

	rxTest:expectEqual( expected, result )

	if WFPlatformInfo.isDesktop then

		-- Desktop: If the original is on an offline volume, this should return nil.

		overrides = {
			localOriginalIsOnDisconnectedVolume = true
		}

		docValue, expectedData = buildDocValue( rxTest, overrides )

		result = WFCatAssetUtils.getFullOriginalPathFromDocValue( docValue )

		expected = nil

		rxTest:expectEqual( expected, result )

	end

end

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

function WFCatAssetUtilsTest.rxTestGetOriginalRelativePathFromDocValue( rxTest )

	local docValue, expectedData = buildDocValue( rxTest )

	local result = WFCatAssetUtils.getOriginalRelativePathFromDocValue( docValue )

	local expected

	if WFPlatformInfo.isDesktop then

		local relativePath = WFFileUtils.removeVolumeFromPath( expectedData.originalFilePath )
		expected = relativePath

	else

		expected = expectedData.originalFilePath

	end

	rxTest:expectEqual( expected, result )

end

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

function WFCatAssetUtilsTest.rxTestGetOriginalVolumeGuidFromDocValue( rxTest )

	local docValue, expectedData = buildDocValue( rxTest )

	local result = WFCatAssetUtils.getOriginalVolumeGuidFromDocValue( docValue )

	local expected

	if WFPlatformInfo.isDesktop then

		local volumeGuid = WFFileUtils.getVolumeGuidForPath( expectedData.originalFilePath )
		expected = volumeGuid

	else

		expected = nil

	end

	rxTest:expectEqual( expected, result )

end

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

function WFCatAssetUtilsTest.rxTestGetOriginalSizeFromDocValue( rxTest )

	local docValue, expectedData = buildDocValue( rxTest )

	local result = WFCatAssetUtils.getOriginalSizeFromDocValue( docValue )

	local expected = expectedData.originalFileSize

	rxTest:expectEqual( expected, result )

	local overrides = {
		docSubtype = "preset"
	}

	docValue, expectedData = buildDocValue( rxTest, overrides )

	result = WFCatAssetUtils.getOriginalSizeFromDocValue( docValue )

	expected = expectedData.presetFileSize

	rxTest:expectEqual( expected, result )

end

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

function WFCatAssetUtilsTest.rxTestGetOriginalContentIdFromDocValue( rxTest )

	local docValue, expectedData = buildDocValue( rxTest )

	local result = WFCatAssetUtils.getOriginalContentIdFromDocValue( docValue )

	local expected = expectedData.originalContentId

	rxTest:expectEqual( expected, result )

	local overrides = {
		docSubtype = "preset"
	}

	docValue, expectedData = buildDocValue( rxTest, overrides )

	result = WFCatAssetUtils.getOriginalContentIdFromDocValue( docValue )

	expected = expectedData.presetContentId

	rxTest:expectEqual( expected, result )

end

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

function WFCatAssetUtilsTest.rxTestGetFullProxyPathFromDocValue( rxTest )

	-- Image

	local overrides = {}

	local docValue, expectedData = buildDocValue( rxTest )

	local result = WFCatAssetUtils.getFullProxyPathFromDocValue( docValue )

	rxTest:expectEqual( expectedData.proxyFilePath, result )

	-- Image on Offline Volume

	if WFPlatformInfo.isDesktop then

		overrides = {
			localProxyIsOnDisconnectedVolume = true
		}

		docValue, expectedData = buildDocValue( rxTest, overrides )

		result = WFCatAssetUtils.getFullProxyPathFromDocValue( docValue )

		rxTest:expectEqual( nil, result )

	end

	-- Image (2560)

	overrides = {
		hasLocal2560Proxy = true
	}

	docValue, expectedData = buildDocValue( rxTest, overrides )

	result = WFCatAssetUtils.getFullProxyPathFromDocValue( docValue, '2560' )

	rxTest:expectEqual( expectedData.proxyFilePath, result )

	if WFPlatformInfo.isDesktop then

		-- Mobile does not currently support panorama or fullsize proxies.

		-- Image (Panorama)

		overrides = {
			isPanorama = true
		}

		docValue, expectedData = buildDocValue( rxTest, overrides )

		result = WFCatAssetUtils.getFullProxyPathFromDocValue( docValue, 'panorama' )

		rxTest:expectEqual( expectedData.proxyFilePath, result )

		-- Image (Fullsize)

		overrides = {
			hasLocalFullsizeProxy = true
		}

		docValue, expectedData = buildDocValue( rxTest, overrides )

		result = WFCatAssetUtils.getFullProxyPathFromDocValue( docValue, 'fullsize' )

		rxTest:expectEqual( expectedData.fullsizeProxyFilePath, result )

	end

	-- No Local Proxy

	overrides = {
		noLocalProxy = true
	}

	docValue, expectedData = buildDocValue( rxTest, overrides )

	result = WFCatAssetUtils.getFullProxyPathFromDocValue( docValue )

	rxTest:expectEqual( nil, result )

	-- Video (Default)

	overrides = {
		docSubtype = 'video'
	}

	docValue, expectedData = buildDocValue( rxTest, overrides )

	result = WFCatAssetUtils.getFullProxyPathFromDocValue( docValue )

	rxTest:expectEqual( expectedData.proxy1080pFilePath, result )

	-- Video (1080p)

	overrides = {
		docSubtype = 'video',
		hasLocal1080p = true
	}

	docValue, expectedData = buildDocValue( rxTest, overrides )

	result = WFCatAssetUtils.getFullProxyPathFromDocValue( docValue, '1080p' )

	rxTest:expectEqual( expectedData.proxy1080pFilePath, result )

	-- Video (720p)

	if WFPlatformInfo.isDesktop then

		-- Only LrD supports 720p proxy/renditions

		overrides = {
			docSubtype = 'video',
			hasLocal720p = true
		}

		docValue, expectedData = buildDocValue( rxTest, overrides )

		result = WFCatAssetUtils.getFullProxyPathFromDocValue( docValue, '720p' )

		rxTest:expectEqual( expectedData.proxy720pFilePath, result )

	end

	-- Video (360p)

	overrides = {
		docSubtype = 'video',
		hasLocal360p = true
	}

	docValue, expectedData = buildDocValue( rxTest, overrides )

	result = WFCatAssetUtils.getFullProxyPathFromDocValue( docValue, '360p' )

	rxTest:expectEqual( expectedData.proxy360pFilePath, result )

	-- Video, No Local Proxy

	overrides = {
		docSubtype = 'video',
		noLocalProxy = true
	}

	docValue, expectedData = buildDocValue( rxTest, overrides )

	result = WFCatAssetUtils.getFullProxyPathFromDocValue( docValue )

	rxTest:expectEqual( nil, result )

end

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

function WFCatAssetUtilsTest.rxTestGetProxyRelativePathFromDocValue( rxTest )

	local docValue, expectedData = buildDocValue( rxTest )

	local result = WFCatAssetUtils.getProxyRelativePathFromDocValue( docValue )

	local expected

	if WFPlatformInfo.isDesktop then

		local relativePath = WFFileUtils.removeVolumeFromPath( expectedData.proxyFilePath )
		expected = relativePath

	else

		expected = expectedData.proxyFilePath

	end

	rxTest:expectEqual( expected, result )

end

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

function WFCatAssetUtilsTest.rxTestGetProxyVolumeGuidFromDocValue( rxTest )

	local docValue, expectedData = buildDocValue( rxTest )

	local result = WFCatAssetUtils.getProxyVolumeGuidFromDocValue( docValue )

	local expected

	if WFPlatformInfo.isDesktop then

		local volumeGuid = WFFileUtils.getVolumeGuidForPath( expectedData.proxyFilePath )
		expected = volumeGuid

	else

		expected = nil

	end

	rxTest:expectEqual( expected, result )

end

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

function WFCatAssetUtilsTest.rxTestGetProxySizeFromDocValue( rxTest )

	-- Image

	local overrides = {}

	local docValue, expectedData = buildDocValue( rxTest )

	local size, proxyType = WFCatAssetUtils.getProxySizeFromDocValue( docValue )

	rxTest:expectEqual( "2560", proxyType )
	rxTest:expectEqual( expectedData.proxyFileSize, size )

	-- Image (2560)

	overrides = {
		hasLocal2560Proxy = true
	}

	docValue, expectedData = buildDocValue( rxTest, overrides )

	size, proxyType = WFCatAssetUtils.getProxySizeFromDocValue( docValue, '2560' )

	rxTest:expectEqual( "2560", proxyType )
	rxTest:expectEqual( expectedData.proxyFileSize, size )

	if WFPlatformInfo.isDesktop then

		-- Mobile does not currently support panorama or fullsize proxies.

		-- Image (Panorama)

		overrides = {
			isPanorama = true
		}

		docValue, expectedData = buildDocValue( rxTest, overrides )

		size, proxyType = WFCatAssetUtils.getProxySizeFromDocValue( docValue, 'panorama' )

		rxTest:expectEqual( 'panorama', proxyType )
		rxTest:expectEqual( expectedData.proxyFileSize, size )

		-- Image (Fullsize)

		overrides = {
			hasLocalFullsizeProxy = true
		}

		docValue, expectedData = buildDocValue( rxTest, overrides )

		size, proxyType = WFCatAssetUtils.getProxySizeFromDocValue( docValue, 'fullsize' )

		rxTest:expectEqual( expectedData.fullsizeProxyFileSize, size )
		rxTest:expectEqual( 'fullsize', proxyType )

	end

	-- No Local Proxy

	overrides = {
		noLocalProxy = true
	}

	docValue, expectedData = buildDocValue( rxTest, overrides )

	size = WFCatAssetUtils.getProxySizeFromDocValue( docValue )

	rxTest:expectEqual( nil, size )

	-- Video (Default)

	overrides = {
		docSubtype = 'video'
	}

	docValue, expectedData = buildDocValue( rxTest, overrides )

	size, proxyType = WFCatAssetUtils.getProxySizeFromDocValue( docValue )

	rxTest:expectEqual( '1080p', proxyType )
	rxTest:expectEqual( expectedData.proxy1080pFileSize, size )

	-- Video (1080p)

	overrides = {
		docSubtype = 'video',
		hasLocal1080p = true
	}

	docValue, expectedData = buildDocValue( rxTest, overrides )

	size, proxyType = WFCatAssetUtils.getProxySizeFromDocValue( docValue, '1080p' )

	rxTest:expectEqual( expectedData.proxy1080pFileSize, size )
	rxTest:expectEqual( '1080p', proxyType )

	-- Video (720p)

	if WFPlatformInfo.isDesktop then

		-- Only LrD supports 720p proxy/renditions

		overrides = {
			docSubtype = 'video',
			hasLocal720p = true
		}

		docValue, expectedData = buildDocValue( rxTest, overrides )

		size, proxyType = WFCatAssetUtils.getProxySizeFromDocValue( docValue, '720p' )

		rxTest:expectEqual( expectedData.proxy720pFileSize, size )
		rxTest:expectEqual( '720p', proxyType )

	end

	-- Video (360p)

	overrides = {
		docSubtype = 'video',
		hasLocal360p = true
	}

	docValue, expectedData = buildDocValue( rxTest, overrides )

	size, proxyType = WFCatAssetUtils.getProxySizeFromDocValue( docValue, '360p' )

	rxTest:expectEqual( expectedData.proxy360pFileSize, size )
	rxTest:expectEqual( '360p', proxyType )

	-- Video, No Local Proxy
	overrides = {
		docSubtype = 'video',
		noLocalProxy = true
	}

	docValue, expectedData = buildDocValue( rxTest, overrides )

	size, proxyType = WFCatAssetUtils.getProxySizeFromDocValue( docValue )

	rxTest:expectEqual( nil, size )

end

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

function WFCatAssetUtilsTest.rxTestGetProxyContentIdFromDocValue( rxTest )

	-- Image

	local overrides = {}

	local docValue, expectedData = buildDocValue( rxTest )

	local result = WFCatAssetUtils.getProxyContentIdFromDocValue( docValue )

	local expected = ( not WFPlatformInfo.isAndroid ) and expectedData.proxyContentId or nil

	rxTest:expectEqual( expected, result )

	-- Image (2560)

	overrides = {
		hasLocal2560Proxy = true
	}

	docValue, expectedData = buildDocValue( rxTest, overrides )

	result = WFCatAssetUtils.getProxyContentIdFromDocValue( docValue, '2560' )

	expected = ( not WFPlatformInfo.isAndroid ) and expectedData.proxyContentId or nil

	rxTest:expectEqual( expected, result )

	if WFPlatformInfo.isDesktop then

		-- Mobile does not currently support panorama or fullsize proxies.

		-- Image (Panorama)

		overrides = {
			isPanorama = true
		}

		docValue, expectedData = buildDocValue( rxTest, overrides )

		result = WFCatAssetUtils.getProxyContentIdFromDocValue( docValue, 'panorama' )

		expected = ( not WFPlatformInfo.isAndroid ) and expectedData.proxyContentId or nil

		rxTest:expectEqual( expected, result )

		-- Image (Fullsize)

		overrides = {
			hasLocalFullsizeProxy = true
		}

		docValue, expectedData = buildDocValue( rxTest, overrides )

		result = WFCatAssetUtils.getProxyContentIdFromDocValue( docValue, 'fullsize' )

		expected = ( not WFPlatformInfo.isAndroid ) and expectedData.fullsizeProxyContentId or nil

		rxTest:expectEqual( expected, result )

	end

	-- No Local Proxy

	overrides = {
		noLocalProxy = true
	}

	docValue, expectedData = buildDocValue( rxTest, overrides )

	result = WFCatAssetUtils.getProxyContentIdFromDocValue( docValue )

	expected = WFPlatformInfo.isDesktop and expectedData.originalSha256 or nil

	rxTest:expectEqual( expected, result )

	-- Video (Default)

	overrides = {
		docSubtype = 'video'
	}

	docValue, expectedData = buildDocValue( rxTest, overrides )

	result = WFCatAssetUtils.getProxyContentIdFromDocValue( docValue )

	expected = expectedData.proxy1080pContentId

	rxTest:expectEqual( expected, result )

	-- Video (1080p)

	overrides = {
		docSubtype = 'video',
		hasLocal1080p = true
	}

	docValue, expectedData = buildDocValue( rxTest, overrides )

	result = WFCatAssetUtils.getProxyContentIdFromDocValue( docValue, '1080p' )

	expected = expectedData.proxy1080pContentId

	rxTest:expectEqual( expected, result )

	-- Video (720p)

	if WFPlatformInfo.isDesktop then

		-- Only LrD supports 720p proxy/renditions

		overrides = {
			docSubtype = 'video',
			hasLocal720p = true
		}

		docValue, expectedData = buildDocValue( rxTest, overrides )

		result = WFCatAssetUtils.getProxyContentIdFromDocValue( docValue, '720p' )

		expected = expectedData.proxy720pContentId

		rxTest:expectEqual( expected, result )

	end

	-- Video (360p)

	overrides = {
		docSubtype = 'video',
		hasLocal360p = true
	}

	docValue, expectedData = buildDocValue( rxTest, overrides )

	result = WFCatAssetUtils.getProxyContentIdFromDocValue( docValue, '360p' )

	expected = expectedData.proxy360pContentId

	rxTest:expectEqual( expected, result )

	-- Video, No Local Proxy

	overrides = {
		docSubtype = 'video',
		noLocalProxy = true
	}

	docValue, expectedData = buildDocValue( rxTest, overrides )

	result = WFCatAssetUtils.getProxyContentIdFromDocValue( docValue )

	expected = WFPlatformInfo.isDesktop and expectedData.originalSha256 or nil

	rxTest:expectEqual( expected, result )

end

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

function WFCatAssetUtilsTest.rxTestGetLocalExternalDevelopSettingsPath( rxTest )

	local docValue, expectedData = buildDocValue( rxTest )

	local result = WFCatAssetUtils.getLocalExternalDevelopSettingsPath( docValue )

	local expected = expectedData.xmpDevelopSettingsRelPath

	rxTest:expectEqual( expected, result )

end

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

function WFCatAssetUtilsTest.rxTestGetLocalExternalDevelopSettingsSize( rxTest )

	local docValue, expectedData = buildDocValue( rxTest )

	local result = WFCatAssetUtils.getLocalExternalDevelopSettingsSize( docValue )

	local expected = expectedData.xmpDevelopSettingsFileSize

	rxTest:expectEqual( expected, result )

end

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

function WFCatAssetUtilsTest.rxTestGetLocalExternalDevelopSettingsContentId( rxTest )

	local docValue, expectedData = buildDocValue( rxTest )

	local result = WFCatAssetUtils.getLocalExternalDevelopSettingsContentId( docValue )

	local expected = expectedData.developSettingsSha256

	rxTest:expectEqual( expected, result )

end

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

function WFCatAssetUtilsTest.rxTestGetLocalAuxObjectPath( rxTest )

	local overrides = {
		hasMasks = true
	}

	local docValue, expectedData = buildDocValue( rxTest, overrides )

	local result = WFCatAssetUtils.getLocalAuxObjectPath( docValue, expectedData.mask1Fingerprint )

	local expected = expectedData.mask1RelativeFilePath

	rxTest:expectEqual( expected, result )

	result = WFCatAssetUtils.getLocalAuxObjectPath( docValue, expectedData.mask2Fingerprint )

	expected = expectedData.mask2RelativeFilePath

	rxTest:expectEqual( expected, result )

end

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

function WFCatAssetUtilsTest.rxTestAbsolutePathToDevelopSettings( rxTest )

	local _, _, wfCatalog = buildDocValue( rxTest )

	local relativePath = 'foo/zar/bar'

	local absolutePath = WFCatAssetUtils.absolutePathToDevelopSettings( wfCatalog:ozCatalogId(), relativePath )

	if WFPlatformInfo.isDesktop then

		rxTest:expectEqual( 'foo/zar/bar', absolutePath )

	elseif WFPlatformInfo.isAndroid then

		local documentsDir = KSPathUtils.getStandardFilePath( 'carouselDocuments' )

		local externalXmpAbsolutePath = KSPathUtils.child( documentsDir, relativePath )

		rxTest:expectEqual( externalXmpAbsolutePath, absolutePath )

	elseif WFPlatformInfo.isiOS then

		local externalXmpAbsolutePath = OzFilePaths.getAbsolutePathInCatalog( wfCatalog:ozCatalogId(), relativePath )

		rxTest:expectEqual( externalXmpAbsolutePath, absolutePath )

	end

end

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

function WFCatAssetUtilsTest.rxTestHasLocalOriginal( rxTest )

	-- has local original

	local docValue = buildDocValue( rxTest )

	rxTest:expectEqual( true, WFCatAssetUtils.hasLocalOriginal( docValue ) )

	-- has no local original

	local overrides = {
		noLocalOriginal = true
	}

	docValue = buildDocValue( rxTest, overrides )

	rxTest:expectEqual( false, WFCatAssetUtils.hasLocalOriginal( docValue ) )

end

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

function WFCatAssetUtilsTest.rxTestHasLocalProxy( rxTest )

	-- has local proxy

	local docValue = buildDocValue( rxTest )

	local result = WFCatAssetUtils.hasLocalProxy( docValue )
	rxTest:expectEqual( true, result )

	-- has no local proxy

	local overrides = {
		noLocalProxy = true
	}

	docValue = buildDocValue( rxTest, overrides )

	rxTest:expectEqual( false, WFCatAssetUtils.hasLocalProxy( docValue ) )

end

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

function WFCatAssetUtilsTest.rxTestHasLocalOriginalOrProxy( rxTest )

	local docValue = buildDocValue( rxTest )

	local result = WFCatAssetUtils.hasLocalOriginalOrProxy( docValue )
	rxTest:expectEqual( true, result )

	-- has no local proxy

	local overrides = {
		noLocalProxy = true
	}

	docValue = buildDocValue( rxTest, overrides )

	rxTest:expectEqual( true, WFCatAssetUtils.hasLocalOriginalOrProxy( docValue ) )

	-- has no local original

	overrides = {
		noLocalOriginal = true,
	}

	docValue = buildDocValue( rxTest, overrides )

	rxTest:expectEqual( true, WFCatAssetUtils.hasLocalOriginalOrProxy( docValue ) )

	-- has no local original or local proxy

	overrides = {
		noLocalOriginal = true,
		noLocalProxy = true
	}

	docValue = buildDocValue( rxTest, overrides )

	rxTest:expectEqual( false, WFCatAssetUtils.hasLocalOriginalOrProxy( docValue ) )

end


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

function WFCatAssetUtilsTest.rxTestHasLocalOriginalOrAnyProxy( rxTest )
	local docValue = buildDocValue( rxTest )

	local result = WFCatAssetUtils.hasLocalOriginalOrAnyProxy( docValue )
	rxTest:expectEqual( true, result )

	-- has no local proxy

	local overrides = {
		noLocalProxy = true
	}

	docValue = buildDocValue( rxTest, overrides )

	rxTest:expectEqual( true, WFCatAssetUtils.hasLocalOriginalOrAnyProxy( docValue ) )

	-- has no local original

	overrides = {
		noLocalOriginal = true,
	}

	docValue = buildDocValue( rxTest, overrides )

	rxTest:expectEqual( true, WFCatAssetUtils.hasLocalOriginalOrAnyProxy( docValue ) )

	-- has no local original or local proxy

	overrides = {
		noLocalOriginal = true,
		noLocalProxy = true
	}

	docValue = buildDocValue( rxTest, overrides )

	rxTest:expectEqual( false, WFCatAssetUtils.hasLocalOriginalOrAnyProxy( docValue ) )

	if WFPlatformInfo.isWindows then

		-- has only video 1080p709 proxy

		overrides = {
			docSubtype = 'video',
			hasLocal1080p709 = true,
			noLocalOriginal = true,
		}

		docValue = buildDocValue( rxTest, overrides )
		rxTest:expectEqual( true, WFCatAssetUtils.hasLocalOriginalOrAnyProxy( docValue ) )

	end
end

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

function WFCatAssetUtilsTest.rxTestDoesAssetDocumentHaveLocalBinary( rxTest )

	-- asset doc w/ local original and proxy

	local docValue = buildDocValue( rxTest )

	local result = WFCatAssetUtils.doesAssetDocumentHaveLocalBinary( docValue )
	rxTest:expectEqual( true, result )

	-- asset doc w/ no local original and no local proxy

	local overrides = {
		noLocalOriginal = true,
		noLocalProxy = true
	}

	docValue = buildDocValue( rxTest, overrides )

	rxTest:expectEqual( false, WFCatAssetUtils.doesAssetDocumentHaveLocalBinary( docValue ) )

	-- style doc w/ local original

	overrides = {
		docSubtype = 'profile'
	}

	docValue = buildDocValue( rxTest, overrides )

	rxTest:expectEqual( true, WFCatAssetUtils.doesAssetDocumentHaveLocalBinary( docValue ) )

	-- style doc w/ no local original

	overrides = {
		docSubtype = 'profile',
		noLocalOriginal = true,
	}

	docValue = buildDocValue( rxTest, overrides )

	rxTest:expectEqual( false, WFCatAssetUtils.doesAssetDocumentHaveLocalBinary( docValue ) )

	-- dcp doc w/ local original

	overrides = {
		docSubtype = 'camera_profile'
	}

	docValue = buildDocValue( rxTest, overrides )

	rxTest:expectEqual( true, WFCatAssetUtils.doesAssetDocumentHaveLocalBinary( docValue ) )

	-- dcp doc w/ no local original

	overrides = {
		docSubtype = 'camera_profile',
		noLocalOriginal = true,
	}

	docValue = buildDocValue( rxTest, overrides )

	rxTest:expectEqual( false, WFCatAssetUtils.doesAssetDocumentHaveLocalBinary( docValue ) )

end

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

function WFCatAssetUtilsTest.rxTestIsValidOriginalOnOz( rxTest )

	-- asset doc w/ original on Oz

	local docValue = buildDocValue( rxTest )

	rxTest:expectEqual( true, WFCatAssetUtils.isValidOriginalOnOz( docValue ) )

	-- asset doc w/ no original on Oz

	local overrides = {
		noMasterLink = true,
	}

	docValue = buildDocValue( rxTest, overrides )

	rxTest:expectEqual( false, WFCatAssetUtils.isValidOriginalOnOz( docValue ) )

	-- asset doc w/ invalid original link on Oz

	overrides = {
		ozOriginalIsInvalid = true,
	}

	docValue = buildDocValue( rxTest, overrides )

	rxTest:expectEqual( false, WFCatAssetUtils.isValidOriginalOnOz( docValue ) )

	-- asset doc w/ corrupt original link on Oz

	overrides = {
		corruptMaster = true,
	}

	docValue = buildDocValue( rxTest, overrides )

	rxTest:expectEqual( false, WFCatAssetUtils.isValidOriginalOnOz( docValue ) )

end

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

function WFCatAssetUtilsTest.rxTestGetUniversal( rxTest )

	local docValue, expectedData = buildDocValue( rxTest )

	rxTest:expectEqual(
		WFCatAssetUtils.getProxyContentIdFromDocValue( docValue ),
		derefUniversal( docValue, 'files', 'proxy', '2560', 'contentId' ) )

	rxTest:expectEqual(
		WFCatAssetUtils.getProxyRelativePathFromDocValue( docValue ),
		derefUniversal( docValue, 'files', 'proxy', '2560', 'relativePath' ) )

	rxTest:expectEqual(
		WFCatAssetUtils.getProxySizeFromDocValue( docValue ),
		derefUniversal( docValue, 'files', 'proxy', '2560', 'fileSize' ) )

	rxTest:expectEqual(
		WFCatAssetUtils.getOriginalRelativePathFromDocValue( docValue ),
		derefUniversal( docValue, 'files', 'original', 'master', 'relativePath' ) )

	rxTest:expectEqual(
		WFCatAssetUtils.getOriginalSizeFromDocValue( docValue ),
		derefUniversal( docValue, 'files', 'original', 'master', 'fileSize' ) )

    if not WFPlatformInfo.isAndroid then
		-- Android never uses content Id for storing any type of rendition
        rxTest:expectEqual(
            WFCatAssetUtils.getOriginalContentIdFromDocValue( docValue ),
            derefUniversal( docValue, 'files', 'original', 'master', 'contentId' ) )
    end

	rxTest:expectEqual(
		WFCatAssetUtils.getLocalExternalDevelopSettingsPath( docValue ),
		derefUniversal( docValue, 'files', 'xmp_develop', 'relativePath' ) )

	rxTest:expectEqual(
		WFCatAssetUtils.getLocalExternalDevelopSettingsSize( docValue ),
		derefUniversal( docValue, 'files', 'xmp_develop', 'fileSize' ) )

	rxTest:expectEqual(
		WFCatAssetUtils.getLocalExternalDevelopSettingsContentId( docValue ),
		derefUniversal( docValue, 'files', 'xmp_develop', 'contentId' ) )

	if WFPlatformInfo.isiOS then

		rxTest:expectEqual(
			expectedData.latestOriginalFilePath,
			derefUniversal( docValue, 'files', 'original', 'latestMaster', 'relativePath' ) )

		rxTest:expectEqual(
			expectedData.thumbnailFilePath,
			derefUniversal( docValue, 'files', 'renditions', 'thumbnail2x', 'relativePath' ) )

		rxTest:expectEqual(
			expectedData.previewFilePath,
			derefUniversal( docValue, 'files', 'renditions', '2048', 'relativePath' ) )

		rxTest:expectEqual(
			expectedData.thumbnailContentId,
			derefUniversal( docValue, 'files', 'renditions', 'thumbnail2x', 'contentId' ) )

		rxTest:expectEqual(
			expectedData.thumbnailFileSize,
			derefUniversal( docValue, 'files', 'renditions', 'thumbnail2x', 'fileSize' ) )

		rxTest:expectEqual(
			expectedData.previewContentId,
			derefUniversal( docValue, 'files', 'renditions', '2048', 'contentId' ) )

		rxTest:expectEqual(
			expectedData.previewFileSize,
			derefUniversal( docValue, 'files', 'renditions', '2048', 'fileSize' ) )

	end

end

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

local function testUniversalPath_iOS( rxTest )

	rxTest:expectEqual( unpack { '_localOnly', 'files', 'thumbnail' },
		universalPath( 'files', 'renditions', 'thumbnail' )
	)

	rxTest:expectEqual( unpack { '_localOnly', 'files', 'thumbnail2' },
		universalPath( 'files', 'renditions', 'thumbnail2x' )
	)

	rxTest:expectEqual( unpack { '_localOnly', 'files', 'preview' },
		universalPath( 'files', 'renditions', '2048' )
	)

	rxTest:expectEqual( unpack { '_localOnly', 'files', 'proxy' },
		universalPath( 'files', 'proxy', '2560' )
	)

	rxTest:expectEqual( unpack { '_localOnly', 'files', 'master' },
		universalPath( 'files', 'original', 'master' )
	)

	rxTest:expectEqual( unpack { '_localOnly', 'files', 'xmp_develop' },
		universalPath( 'files', 'xmp_develop' )
	)

	-- unknown paths

	rxTest:expectEqual( nil,
		universalPath( 'files', 'foo_develop' )
	)

	rxTest:expectEqual( nil,
		universalPath( 'desktop', 'foo' )
	)

end

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

local function testUniversalPath_Android( rxTest )

	rxTest:expectEqual( unpack { '_localOnly', 'thumbnail' },
		universalPath( 'files', 'renditions', 'thumbnail' )
	)

	rxTest:expectEqual( unpack { '_localOnly', 'thumbnail2' },
		universalPath( 'files', 'renditions', 'thumbnail2x' )
	)

	rxTest:expectEqual( unpack { '_localOnly', 'preview' },
		universalPath( 'files', 'renditions', '2048' )
	)

	rxTest:expectEqual( unpack { '_localOnly', 'proxy' },
		universalPath( 'files', 'proxy', '2560' )
	)

	rxTest:expectEqual( unpack { '_localOnly', 'original' },
		universalPath( 'files', 'original', 'master' )
	)

	rxTest:expectEqual( unpack { '_localOnly', 'files', 'xmp_develop' },
		universalPath( 'files', 'xmp_develop' )
	)

	-- unknown paths

	rxTest:expectEqual( nil,
		universalPath( 'files', 'foo_develop' )
	)

	rxTest:expectEqual( nil,
		universalPath( 'desktop', 'foo' )
	)

end

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

local function testUniversalPath_Desktop( rxTest )

	rxTest:expectEqual( unpack { '_localOnly', 'thumbnail' },
		universalPath( 'files', 'renditions', 'thumbnail' )
	)

	rxTest:expectEqual( unpack { '_localOnly', 'thumbnail2' },
		universalPath( 'files', 'renditions', 'thumbnail2x' )
	)

	rxTest:expectEqual( unpack { '_localOnly', 'preview' },
		universalPath( 'files', 'renditions', '2048' )
	)

	rxTest:expectEqual( unpack { '_localOnly', 'proxy' },
		universalPath( 'files', 'proxy', '2560' )
	)

	rxTest:expectEqual( unpack { '_localOnly', 'original' },
		universalPath( 'files', 'original', 'master' )
	)

	rxTest:expectEqual( unpack { '_localOnly', 'files', 'xmp_develop' },
		universalPath( 'files', 'xmp_develop' )
	)

	-- unknown paths

	rxTest:expectEqual( nil,
		universalPath( 'files', 'foo_develop' )
	)

	rxTest:expectEqual( nil,
		universalPath( 'desktop', 'foo' )
	)

end

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

function WFCatAssetUtilsTest.rxTestUniversalPath( rxTest )

	if WFPlatformInfo.isAndroid then

		testUniversalPath_Android( rxTest )

	elseif WFPlatformInfo.isiOS then

		testUniversalPath_iOS( rxTest )

	elseif WFPlatformInfo.isiOS then

		testUniversalPath_Desktop( rxTest )

	end

end

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

local function testRenditionInfo_Android( rxTest, fakeWFCatalog, docValue, expectedData )

	local renditions = WFCatAssetUtils.getLocalRenditionInfo( fakeWFCatalog, docValue )

	rxTest:expectEqual( 3, #renditions )

	for _, renditionInfo in ipairs( renditions ) do

		if renditionInfo.renditionName == 'preview' then

			rxTest:expectEqual( expectedData.previewMd5, renditionInfo.renditionInfo.md5 )

		elseif renditionInfo.renditionName == 'thumbnail2x' then

			rxTest:expectEqual( expectedData.thumbMd5, renditionInfo.renditionInfo.md5 )

		elseif renditionInfo.renditionName == 'fullsize' then

			rxTest:expectEqual( expectedData.fullsizeMd5, renditionInfo.renditionInfo.md5 )

		end

	end

end

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

local function testRenditionInfo_iOS( rxTest, fakeWFCatalog, docValue, expectedData )

	local renditions = WFCatAssetUtils.getLocalRenditionInfo( fakeWFCatalog, docValue )

	rxTest:expectEqual( 3, #renditions )

	for _, renditionInfo in ipairs( renditions ) do

		if renditionInfo.renditionName == 'preview' then

			rxTest:expectEqual( expectedData.previewFilePath, renditionInfo.renditionRelativePath )

			rxTest:expectEqual( expectedData.previewContentId, renditionInfo.renditionContentId )

			rxTest:expectEqual( expectedData.previewFileSize, renditionInfo.renditionSize )

		elseif renditionInfo.renditionName == 'thumbnail2x' then

			rxTest:expectEqual( expectedData.thumbnailFilePath, renditionInfo.renditionRelativePath )

			rxTest:expectEqual( expectedData.thumbnailContentId, renditionInfo.renditionContentId )

			rxTest:expectEqual( expectedData.thumbnailFileSize, renditionInfo.renditionSize )

		elseif renditionInfo.renditionName == 'fullsize' then

			rxTest:expectEqual( expectedData.fullsizeFilePath, renditionInfo.renditionRelativePath )

			rxTest:expectEqual( expectedData.fullsizeContentId, renditionInfo.renditionContentId )

			rxTest:expectEqual( expectedData.fullsizeFileSize, renditionInfo.renditionSize )

		end

	end

end

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

local function testRenditionInfo_Desktop( rxTest, fakeWFCatalog, docValue, expectedData )

	local renditions = WFCatAssetUtils.getLocalRenditionInfo( fakeWFCatalog, docValue )

	rxTest:expectEqual( 2, #renditions )

	for _, renditionInfo in ipairs( renditions ) do

		if renditionInfo.longEdge == 2048 then

			rxTest:expectEqual( expectedData.previewFilePath, renditionInfo.renditionPath )

		elseif renditionInfo.longEdge == 320 then

			rxTest:expectEqual( expectedData.thumbnailFilePath, renditionInfo.renditionPath )

		end

	end

end

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

function WFCatAssetUtilsTest.rxTestRenditionInfo( rxTest )

	local docValue, expectedData, wfCatalog = buildDocValue( rxTest )

	if WFPlatformInfo.isAndroid then

		testRenditionInfo_Android( rxTest, wfCatalog, docValue, expectedData )

	elseif WFPlatformInfo.isiOS then

		testRenditionInfo_iOS( rxTest, wfCatalog, docValue, expectedData )

	elseif WFPlatformInfo.isDesktop then

		testRenditionInfo_Desktop( rxTest, wfCatalog, docValue, expectedData )

	end
end

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

local function createDocValueWithServerProvidedLinks( rxTest, isLocalCopy, serverProvidedMetadataOverlay )

	local docValue, _ = buildDocValue( rxTest )

	-- Remove all _serverProvidedMetadata (buildDocValue adds a /rels/master)
	KSTableUtils.setNested( docValue, nil, '_serverProvidedMetadata' )

	-- Set docValue.develop.sha256 to match sha in the _loca.Only file section
	-- as mobile depends on it.
	local xmpLocalFileInfo = KSTableUtils.derefOpt( docValue, '_localOnly', 'files', 'xmp_develop' )
	local cameraRawSha256 = xmpLocalFileInfo and (
			xmpLocalFileInfo.sha256 -- desktop, android
			or xmpLocalFileInfo.contentId -- iOS
		)
	KSTableUtils.setNested( docValue, cameraRawSha256, 'develop', 'xmpCameraRaw', 'sha256' )

	if isLocalCopy then

		docValue = WFTableMerge.applyOverlay( docValue, {
			_localOnly = {
				-- remove all the local file paths as copy doesn't rely on anything being local
				files = { _delete = true }, -- Desktop and iOS
				proxy = { _delete = true }, -- android
				original = { _delete = true }, -- android

				-- add the flag that we check indicating the asset was copied locally
				sourceAssetId = KSIdGenerator.uuidInLowercaseHex(),
			},
		} )

	end

	if serverProvidedMetadataOverlay then
		docValue = WFTableMerge.applyOverlay( docValue, serverProvidedMetadataOverlay )
	end

	return docValue

end

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

function WFCatAssetUtilsTest.rxTestBinaryUploadPending( rxTest )

	local function addLink( overlay, linkType )
		KSTableUtils.setNested( overlay, { href = '/url/goes/here' }, '_serverProvidedMetadata', 'links', linkType )
		return overlay
	end

	-- original, xmpDevelop pending upload
	do
		local doc = createDocValueWithServerProvidedLinks( rxTest, false )
		rxTest:expectEqual( true, WFCatAssetUtils.binaryUploadPending( doc ) )

		if WFPlatformInfo.isDesktop then
			local copy = createDocValueWithServerProvidedLinks( rxTest, true )
			rxTest:expectEqual( true, WFCatAssetUtils.binaryUploadPending( copy ) )
		end
	end

	-- original pending upload
	do
		local spm = addLink( {}, '/rels/xmp/develop' )

		local doc = createDocValueWithServerProvidedLinks( rxTest, false, spm )
		rxTest:expectEqual( true, WFCatAssetUtils.binaryUploadPending( doc ) )

		if WFPlatformInfo.isDesktop then
			local copy = createDocValueWithServerProvidedLinks( rxTest, true, spm )
			rxTest:expectEqual( true, WFCatAssetUtils.binaryUploadPending( copy ) )
		end
	end

	-- external develop settings pending upload
	do
		local spm = addLink( {}, '/rels/master' )

		local doc = createDocValueWithServerProvidedLinks( rxTest, false, spm )
		rxTest:expectEqual( true, WFCatAssetUtils.binaryUploadPending( doc ) )

		if WFPlatformInfo.isDesktop then
			local copy = createDocValueWithServerProvidedLinks( rxTest, true, spm )
			rxTest:expectEqual( true, WFCatAssetUtils.binaryUploadPending( copy ) )
		end
	end

	-- external sidecar pending upload
	do
		local spm = addLink( {}, '/rels/master' )
		addLink( spm, '/rels/xmp/develop' )

		local doc = createDocValueWithServerProvidedLinks( rxTest, false, spm )
		-- desktop currently supports external sidecar upload, mobile doesn't yet
		rxTest:expectEqual( WFPlatformInfo.isDesktop and true or false, WFCatAssetUtils.binaryUploadPending( doc ) )

		if WFPlatformInfo.isDesktop then
			local copy = createDocValueWithServerProvidedLinks( rxTest, true, spm )
			rxTest:expectEqual( true, WFCatAssetUtils.binaryUploadPending( copy ) )
		end
	end

	-- everything uploaded
	do
		local spm = addLink( {}, '/rels/master' )
		addLink( spm, '/rels/xmp/develop' )
		addLink( spm, '/rels/xmp' )

		local doc = createDocValueWithServerProvidedLinks( rxTest, false, spm )
		rxTest:expectEqual( false, WFCatAssetUtils.binaryUploadPending( doc ) )

		if WFPlatformInfo.isDesktop then
			local copy = createDocValueWithServerProvidedLinks( rxTest, true, spm )
			rxTest:expectEqual( false, WFCatAssetUtils.binaryUploadPending( copy ) )
		end
	end


	if WFPlatformInfo.isDesktop then

		-- proxy only asset pending upload
		do
			local spm = addLink( {}, '/rels/xmp/develop' )
			KSTableUtils.setNested( spm, { _delete = true }, '_localOnly', 'files', 'original' ) -- desktop
			KSTableUtils.setNested( spm, { _delete = true }, '_localOnly', 'files', 'master' ) -- iOS
			KSTableUtils.setNested( spm, { _delete = true }, '_localOnly', 'original' ) -- android

			local doc = createDocValueWithServerProvidedLinks( rxTest, false, spm )
			rxTest:expectEqual( true, WFCatAssetUtils.binaryUploadPending( doc ) )

			local copy = createDocValueWithServerProvidedLinks( rxTest, true, spm )
			rxTest:expectEqual( true, WFCatAssetUtils.binaryUploadPending( copy ) )
		end

		-- xmp sidecar pending upload
		do
			local spm = addLink( {}, '/rels/master' )
			addLink( spm, '/rels/xmp/develop' )

			local doc = createDocValueWithServerProvidedLinks( rxTest, false, spm )
			rxTest:expectEqual( true, WFCatAssetUtils.binaryUploadPending( doc ) )

			local copy = createDocValueWithServerProvidedLinks( rxTest, true, spm )
			rxTest:expectEqual( true, WFCatAssetUtils.binaryUploadPending( copy ) )
		end

	end

end

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

function WFCatAssetUtilsTest.rxTestGetLatestEditDetails( rxTest )

	local feedbackuserId = KSIdGenerator.uuidInLowercaseHex()

	local sampleAssetDoc = {
		develop = {
			userUpdated = "2023-06-08T20:41:31.478821Z",
			device = "Generic Spacecraft {i-am-a-sha256}",
		},
		_serverProvidedMetadata = {
			developedByUser = {
				id = feedbackuserId,
			}
		}
	}

	local sampleFeedbackuserDoc = {
		_id = feedbackuserId,
		_serverProvidedMetadata = {
			full_name = "The last"
		}
	}

	-- simplest case, just userUpdated and userDevice

	rxTest:expectEqual({
		userUpdated = "2023-06-08T20:41:31.478821Z",
		userDevice = "Generic Spacecraft {i-am-a-sha256}",
	}, WFCatAssetUtils.getLatestEditDetails( sampleAssetDoc, {} ) )

	-- with feedbackuser

	rxTest:expectEqual({
		userUpdated = "2023-06-08T20:41:31.478821Z",
		userDevice = "Generic Spacecraft {i-am-a-sha256}",
		userName = "The last",
	}, WFCatAssetUtils.getLatestEditDetails( sampleAssetDoc, { sampleFeedbackuserDoc } ) )

	-- with temp link info

	local tempLinkInfo = {
		develop = {
			userUpdated = "2023-06-09T20:41:31.478821Z",
			device = "Another device {blah-blah-blah}",
		},
		uploadedByUser = { id = feedbackuserId }
	}

	rxTest:expectEqual({
		userUpdated = "2023-06-08T20:41:31.478821Z",
		userDevice = "Generic Spacecraft {i-am-a-sha256}",
		tempBinary = {
			userUpdated = "2023-06-09T20:41:31.478821Z",
			userDevice = "Another device {blah-blah-blah}",
		}
	}, WFCatAssetUtils.getLatestEditDetails( sampleAssetDoc, { }, tempLinkInfo ) )

	-- with temp link info and feedbackuser

	rxTest:expectEqual({
		userUpdated = "2023-06-08T20:41:31.478821Z",
		userDevice = "Generic Spacecraft {i-am-a-sha256}",
		userName = "The last",
		tempBinary = {
			userUpdated = "2023-06-09T20:41:31.478821Z",
			userDevice = "Another device {blah-blah-blah}",
			userName = "The last",
		}
	}, WFCatAssetUtils.getLatestEditDetails( sampleAssetDoc, { sampleFeedbackuserDoc }, tempLinkInfo ) )

	-- with temp link info and two different feedbackusers

	local feedbackuserId2 = KSIdGenerator.uuidInLowercaseHex()
	local sampleFeedbackuserDoc2 = {
		_id = feedbackuserId2,
		_serverProvidedMetadata = {
			full_name = "the other guy"
		}
	}
	tempLinkInfo.uploadedByUser.id = feedbackuserId2

	rxTest:expectEqual({
		userUpdated = "2023-06-08T20:41:31.478821Z",
		userDevice = "Generic Spacecraft {i-am-a-sha256}",
		userName = "The last",
		tempBinary = {
			userUpdated = "2023-06-09T20:41:31.478821Z",
			userDevice = "Another device {blah-blah-blah}",
			userName = "the other guy",
		}
	}, WFCatAssetUtils.getLatestEditDetails( sampleAssetDoc, { sampleFeedbackuserDoc, sampleFeedbackuserDoc2 }, tempLinkInfo ) )

	-- with temp link info and only top level has feedbackuser

	rxTest:expectEqual({
		userUpdated = "2023-06-08T20:41:31.478821Z",
		userDevice = "Generic Spacecraft {i-am-a-sha256}",
		userName = "The last",
		tempBinary = {
			userUpdated = "2023-06-09T20:41:31.478821Z",
			userDevice = "Another device {blah-blah-blah}",
		}
	}, WFCatAssetUtils.getLatestEditDetails( sampleAssetDoc, { sampleFeedbackuserDoc }, tempLinkInfo ) )

	-- with temp link info and only tempBinary has feedbackuser

	rxTest:expectEqual({
		userUpdated = "2023-06-08T20:41:31.478821Z",
		userDevice = "Generic Spacecraft {i-am-a-sha256}",
		tempBinary = {
			userUpdated = "2023-06-09T20:41:31.478821Z",
			userDevice = "Another device {blah-blah-blah}",
			userName = "the other guy",
		}
	}, WFCatAssetUtils.getLatestEditDetails( sampleAssetDoc, { sampleFeedbackuserDoc2 }, tempLinkInfo ) )

end

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

function WFCatAssetUtilsTest.rxTestGetMostRecentTempDevelopInfo( rxTest )

	local catalogId = KSIdGenerator.uuidInLowercaseHex()
	local assetId = KSIdGenerator.uuidInLowercaseHex()
	local revisionId = KSIdGenerator.uuidInLowercaseHex()
	local feedbackuserId = KSIdGenerator.uuidInLowercaseHex()

	local assetDoc = {
		develop = {
			userUpdated = "2023-06-08T20:41:31.478821Z",
		},
	}
	WFCatAssetTestUtils.addBasicOzMetadataUpdateForDirectUpload( assetDoc, catalogId, assetId, revisionId )

	-- will return nil if no temp links are in the list

	rxTest:expectEqual( nil, WFCatAssetUtils.getMostRecentTempDevelopInfo( assetDoc ) )

	-- setup temp links

	local links = assetDoc._serverProvidedMetadata.links

	links[ '/rels/temp/aux/0123456789abcdef' ] = {
		develop = {
			userUpdated = "2023-06-09T20:41:31.478821Z",
			device = "Generic Spacecraft {i-am-a-sha256}",
		},
		uploadedByUser = { id = feedbackuserId },
	}

	links[ '/rels/temp/xmp/develop/0123456789abcdef' ] = {
		develop = {
			userUpdated = "2023-06-11T20:41:31.478821Z",
			device = "Device One {foo-bar}",
		},
		uploadedByUser = { id = feedbackuserId },
	}

	links[ '/rels/temp/aux/fedcba9876543210' ] = {
		develop = {
			userUpdated = "2023-06-10T20:41:31.478821Z",
			device = "Device Two {bar-foo}",
		},
		uploadedByUser = { id = feedbackuserId },
	}

	links[ '/rels/temp/xmp/develop/fedcba9876543210' ] = {
		develop = {
			userUpdated = "2023-06-08T21:41:31.478821Z",
			device = "IPad {whatever}",
		},
		uploadedByUser = { id = feedbackuserId },
	}

	-- return entry with most recent userUpdated when it is prefixed with /rels/temp/xmp/develop/

	rxTest:expectEqual( links[ '/rels/temp/xmp/develop/0123456789abcdef' ], WFCatAssetUtils.getMostRecentTempDevelopInfo( assetDoc ) )

	-- return entry with most recent userUpdated when it is prefixed with /rels/temp/aux/

	links[ '/rels/temp/aux/fedcba9876543210' ].develop.userUpdated = "2023-06-12T20:41:31.478821Z"
	rxTest:expectEqual( links[ '/rels/temp/aux/fedcba9876543210' ], WFCatAssetUtils.getMostRecentTempDevelopInfo( assetDoc ) )

	-- will not return entries with other /rels/temp prefixes

	links[ '/rels/temp/foo/fedcba9876543210' ] = links[ '/rels/temp/aux/fedcba9876543210' ]
	links[ '/rels/temp/aux/fedcba9876543210' ] = nil
	rxTest:expectEqual( links[ '/rels/temp/xmp/develop/0123456789abcdef' ], WFCatAssetUtils.getMostRecentTempDevelopInfo( assetDoc ) )

	links[ '/rels/temp/aux' ] = links[ '/rels/temp/foo/fedcba9876543210' ]
	links[ '/rels/temp/foo/fedcba9876543210' ] = nil
	rxTest:expectEqual( links[ '/rels/temp/xmp/develop/0123456789abcdef' ], WFCatAssetUtils.getMostRecentTempDevelopInfo( assetDoc ) )

	links[ '/rels/temp/xmp/develop' ] = links[ '/rels/temp/aux' ]
	links[ '/rels/temp/aux' ] = nil
	rxTest:expectEqual( links[ '/rels/temp/xmp/develop/0123456789abcdef' ], WFCatAssetUtils.getMostRecentTempDevelopInfo( assetDoc ) )

	-- will return entries missing uploadedByUser

	links[ '/rels/temp/xmp/develop/0123456789abcdef' ].uploadedByUser = nil
	rxTest:expectEqual( links[ '/rels/temp/xmp/develop/0123456789abcdef' ], WFCatAssetUtils.getMostRecentTempDevelopInfo( assetDoc ) )

	-- will not return entries missing userUpdated (this should not happen)

	links[ '/rels/temp/xmp/develop/0123456789abcdef' ].develop.userUpdated = nil
	rxTest:expectEqual( links[ '/rels/temp/aux/0123456789abcdef' ], WFCatAssetUtils.getMostRecentTempDevelopInfo( assetDoc ) )

	-- will not return entries missing device (this should not happen)

	links[ '/rels/temp/aux/0123456789abcdef' ].develop.device = nil
	rxTest:expectEqual( links[ '/rels/temp/xmp/develop/fedcba9876543210' ], WFCatAssetUtils.getMostRecentTempDevelopInfo( assetDoc ) )

	-- will return nil if no valid entry is found with userUpdated or device

	links[ '/rels/temp/xmp/develop/fedcba9876543210' ].develop.userUpdated = nil
	rxTest:expectEqual( nil, WFCatAssetUtils.getMostRecentTempDevelopInfo( assetDoc ) )

	-- will return nil if all entries userUpdated is less recent than or the same as develop userUpdated

	links[ '/rels/temp/xmp/develop/fedcba9876543210' ].develop.userUpdated = "2023-06-08T19:41:31.478821Z"
	links[ '/rels/temp/xmp/develop/0123456789abcdef' ].develop.userUpdated = "2023-06-08T20:41:31.478821Z"
	rxTest:expectEqual( nil, WFCatAssetUtils.getMostRecentTempDevelopInfo( assetDoc ) )

	-- will return most recent entry if develop.userUpdated is missing

	links[ '/rels/temp/xmp/develop/0123456789abcdef' ].develop.userUpdated = nil
	assetDoc.develop.userUpdated = nil
	rxTest:expectEqual( links[ '/rels/temp/xmp/develop/fedcba9876543210' ], WFCatAssetUtils.getMostRecentTempDevelopInfo( assetDoc ) )

	-- will return most recent entry if develop is missing

	assetDoc.develop = nil
	rxTest:expectEqual( links[ '/rels/temp/xmp/develop/fedcba9876543210' ], WFCatAssetUtils.getMostRecentTempDevelopInfo( assetDoc ) )

	-- will return nil if no valid entry is found and some entry is missing develop section

	links[ '/rels/temp/xmp/develop/fedcba9876543210' ].develop = nil
	rxTest:expectEqual( nil, WFCatAssetUtils.getMostRecentTempDevelopInfo( assetDoc ) )

	-- will return nil if links is missing

	assetDoc._serverProvidedMetadata.links = nil
	rxTest:expectEqual( nil, WFCatAssetUtils.getMostRecentTempDevelopInfo( assetDoc ) )

	-- will return nil if _serverProvidedMetadata is missing

	assetDoc._serverProvidedMetadata = nil
	rxTest:expectEqual( nil, WFCatAssetUtils.getMostRecentTempDevelopInfo( assetDoc ) )

end

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

function WFCatAssetUtilsTest.rxTestEstimateProxySize( rxTest )

	-- image variant 1

	local sampleImageDoc = {
		type = 'asset',
		subtype = 'image',
		importSource = {
			originalWidth = 5120,
			originalHeight = 3414,
		}
	}

	local estimate = WFCatAssetUtils.estimateProxySize( sampleImageDoc )

	rxTest:expectEqual( 1310976, estimate )

	-- image variant 2

	sampleImageDoc.importSource.originalWidth = 3414
	sampleImageDoc.importSource.originalHeight = 5120

	estimate = WFCatAssetUtils.estimateProxySize( sampleImageDoc )

	rxTest:expectEqual( 1310976, estimate )
		-- Should be the same as variant 1

	-- image variant 3

	sampleImageDoc.importSource.originalWidth = 512
	sampleImageDoc.importSource.originalHeight = 100

	estimate = WFCatAssetUtils.estimateProxySize( sampleImageDoc )

	rxTest:expectEqual( 15360, estimate )

	-- image variant 4

	sampleImageDoc.importSource.originalWidth = 10000
	sampleImageDoc.importSource.originalHeight = 2000

	estimate = WFCatAssetUtils.estimateProxySize( sampleImageDoc )

	rxTest:expectEqual( 393216, estimate )

	-- 2 second video

	local sampleVideoDoc = {
		type = 'asset',
		subtype = 'video',
		video = {
			duration = { 2, 1 }
		}
	}

	estimate = WFCatAssetUtils.estimateProxySize( sampleVideoDoc )

	rxTest:expectEqual( 17039360, estimate )

	-- 10 second video

	sampleVideoDoc.video.duration = { 10, 1 }

	estimate = WFCatAssetUtils.estimateProxySize( sampleVideoDoc )

	rxTest:expectEqual( 85196800, estimate )

	-- 10 minute video

	sampleVideoDoc.video.duration = { 10 * 60 * 2, 2 }

	estimate = WFCatAssetUtils.estimateProxySize( sampleVideoDoc )

	rxTest:expectEqual( 5111808000, estimate )

end

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

function WFCatAssetUtilsTest.rxTestZZ_CloseSuite( rxTest )

	-- Funky naming means this runs last in the suite.

	rxTest:finally( function()

		if _wfCatalog then

			_wfCatalog:close()
			_wfCatalog = nil

		end

	end )

end

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

function WFCatAssetUtilsTest.rxTestDoesAssetNeedDevelopSettingsUploaded( rxTest )

	-- Fully Synced

	local overrides = {
		hasMasks = true
	}

	local docValue = buildDocValue( rxTest, overrides )

	local result = WFCatAssetUtils.doesAssetNeedDevelopSettingsUploaded( docValue )

	local expected = false

	rxTest:expectEqual( expected, result )

	-- Unsynced Develop Settings

	overrides = {
		hasMasks = true,
		noDevelopSettingsLink = true
	}

	docValue = buildDocValue( rxTest, overrides )

	result = WFCatAssetUtils.doesAssetNeedDevelopSettingsUploaded( docValue )

	expected = true

	rxTest:expectEqual( expected, result )

	-- Invalid Synced Develop Settings

	overrides = {
		hasMasks = true,
		ozDevelopSettingsAreInvalid = true
	}

	docValue = buildDocValue( rxTest, overrides )

	result = WFCatAssetUtils.doesAssetNeedDevelopSettingsUploaded( docValue )

	expected = true

	rxTest:expectEqual( expected, result )

	-- Space Asset, Unsynced Develop Settings

	overrides = {
		hasMasks = true,
		noDevelopSettingsLink = true
	}

	docValue = buildDocValue( rxTest, overrides )
	docValue._spaceId = KSIdGenerator.uuidInLowercaseHex()

	result = WFCatAssetUtils.doesAssetNeedDevelopSettingsUploaded( docValue )

	expected = true

	rxTest:expectEqual( expected, result )

	-- Space Asset, Exists but no Href

	overrides = {
		hasMasks = true,
		noDevelopSettingsLink = true
	}

	docValue = buildDocValue( rxTest, overrides )
	docValue._spaceId = KSIdGenerator.uuidInLowercaseHex()
	KSTableUtils.setNested( docValue, true, '_serverProvidedMetadata', 'links', '/rels/xmp/develop', 'exists' )

	result = WFCatAssetUtils.doesAssetNeedDevelopSettingsUploaded( docValue )

	expected = false

	rxTest:expectEqual( expected, result )

end

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

function WFCatAssetUtilsTest.rxTestXmpDevelopStatus( rxTest )

	for _, hasSha256Value in pairs( { true, false } ) do
		for _, hasMasksValue in pairs( { true, false } ) do
			for _, noMaskLinksValue in pairs( { true, false } ) do
				for _, noLocalMasksValue in pairs( { true, false } ) do

					local optArguments = {}

					if hasMasksValue then

						optArguments.hasMasks = true

					end

					if noMaskLinksValue then

						optArguments.noMaskLinks = true

					end

					if noLocalMasksValue then

						optArguments.noLocalMasks = true

					end

					local docValueWithExternalXmp = buildDocValue( rxTest, optArguments )

					if not hasSha256Value then

						docValueWithExternalXmp.develop.xmpCameraRaw.sha256 = nil

					end

					rxTest:logf( "Checking hasExternalXmpDevelop( ... ) hasSha256Value = %s hasMasks = %s  noMaskLinks = %s and noLocalMasks = %s",
									hasSha256Value, hasMasksValue,
									noMaskLinksValue, noLocalMasksValue )

					local docValueHasExternalXmpDevelop =
							WFCatAssetUtils.hasExternalXmpDevelop( docValueWithExternalXmp )

					rxTest:expectEqual( hasSha256Value, docValueHasExternalXmpDevelop )

					rxTest:logf( "Checking maybeGetExternalXmpDevelopSha256( ... ) hasSha256Value = %s hasMasks = %s  noMaskLinks = %s and noLocalMasks = %s",
									hasSha256Value, hasMasksValue,
									noMaskLinksValue, noLocalMasksValue )

					rxTest
						:expectEqual(
							hasSha256Value,
							WFCatAssetUtils.maybeGetExternalXmpDevelopSha256( docValueWithExternalXmp ) ~= nil )

					local docValueHasEmbeddedXmpDevelop =
							WFCatAssetUtils.hasEmbeddedXmpDevelop( docValueWithExternalXmp )

					rxTest:expectEqual( false, docValueHasEmbeddedXmpDevelop )

				end

			end

		end

	end

	rxTest:log( "testing internal xmp" )

	local docValueWithEmbeddedXmp = buildDocValue( rxTest, { internalXmpCameraRaw = true } )

	local docValueHasExternalXmpDevelop =
			WFCatAssetUtils.hasExternalXmpDevelop( docValueWithEmbeddedXmp )

	rxTest:expectEqual( false, docValueHasExternalXmpDevelop )

	local docValueHasEmbeddedXmpDevelop =
			WFCatAssetUtils.hasEmbeddedXmpDevelop( docValueWithEmbeddedXmp )

	rxTest:expectEqual( true, docValueHasEmbeddedXmpDevelop )

end

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

function WFCatAssetUtilsTest.rxTestHasLocalXmpDevelopError( rxTest )

	local docValue = buildDocValue( rxTest )

	-- returns false when no error is present
	rxTest:expectEqual( false, WFCatAssetUtils.hasLocalXmpDevelopError( docValue ) )

	-- returns true when error is set and local develop settings match sha256 in payload
	KSTableUtils.setNested( docValue, true, '_localOnly', 'files', 'xmp_develop', 'error' )
	rxTest:expectEqual( true, WFCatAssetUtils.hasLocalXmpDevelopError( docValue ) )

	-- returns false when error is set but local file sha256 does not match payload sha256
	local differentSha256 = KSIdGenerator.uuidInLowercaseHex() .. KSIdGenerator.uuidInLowercaseHex()
	KSTableUtils.setNested( docValue, differentSha256, 'develop', 'xmpCameraRaw', 'sha256' )
	rxTest:expectEqual( false, WFCatAssetUtils.hasLocalXmpDevelopError( docValue ) )

	-- returns false when error is set but local file has no sha256 value
	-- (this should never happen, but if it does we should not be using the local xmp_develop)
	KSTableUtils.setNested( docValue, nil, '_localOnly', 'files', 'xmp_develop', 'sha256' )
	KSTableUtils.setNested( docValue, nil, '_localOnly', 'files', 'xmp_develop', 'contentId' )
	rxTest:expectEqual( false, WFCatAssetUtils.hasLocalXmpDevelopError( docValue ) )

	-- returns false when error is set but payload has inline xmp develop
	KSTableUtils.setNested( docValue, '<xmpmeta/>', 'develop', 'xmpCameraRaw' )
	rxTest:expectEqual( false, WFCatAssetUtils.hasLocalXmpDevelopError( docValue ) )

end

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

return WFRxTestCase.wrapSuite( 'WFCatAssetUtilsTest', WFCatAssetUtilsTest )
