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

WFCatPurgeHelperTest.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2021 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.rxlua
local WFRxTestCase = require 'WFRxTestCase'

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

	-- WF.core.os
local WFFileUtils = require 'WFFileUtils'

	-- WF.oz_client.managed_catalog
local WFCatAssetAux = require 'WFCatAssetAux'
local WFCatAssetUtils = require 'WFCatAssetUtils'
local WFCatPurgeHelper = require 'WFCatPurgeHelper'
local WFCatMockCatalog = require 'WFCatMockCatalog'
local WFCatAssetTestUtils = require 'WFCatAssetTestUtils'
local WFCatVersionTestUtils = require 'WFCatVersionTestUtils'
local WFCatVolumeAgentQueryHelper = require 'WFCatVolumeAgentQueryHelper'

local LrmCatalogTestHelper

if WFPlatformInfo.isMobile() then
	LrmCatalogTestHelper = require 'LrmCatalogTestHelper'
end

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

local derefOpt = assert( KSTableUtils.derefOpt )
local derefUniversal = assert( WFCatAssetUtils.derefUniversal )

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

local WFCatPurgeHelperTest = {}

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

local function createFakeWFCatalog( rxTest )

	if WFPlatformInfo.isAndroid then
	
		local catalogService, wfCatalog = LrmCatalogTestHelper.makeCatalogService( rxTest )
		local dataCache = rxTest:getFirstValue( catalogService:getDataCache() )

		return wfCatalog, dataCache

	else

		local optArgs = {}
			
		if WFPlatformInfo.isiOS then
			optArgs.indexDefinitions = 'LrmCatalogIndexDefinitions.lua'
		end

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

	end

end

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

local function toBool( value )

	return not not value

end

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

local function doesFileExist( filePath )

	return toBool( filePath and WFFileUtils.exists( filePath ) )

end

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

local function doesFieldExist( docValue, ... )

	return not not derefOpt( docValue, ... )

end

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

local function doesUniversalFieldExist( docValue, ... )

	return not not derefUniversal( docValue, ... )

end

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

local function getExpectedBinariesAfterPurge( purgeList, optArgs )

	local expectedBinaryTypesToPurge = {}
	
	for _, purgeListForBinaryType in ipairs( purgeList ) do
	
		expectedBinaryTypesToPurge[ purgeListForBinaryType.binaryType ] = true
	
	end

	local shouldOriginalExist = not expectedBinaryTypesToPurge[ 'original' ]
	
	local shouldXmpSidecarExist, shouldDevelopSettingsExist, 
			shouldMasksExist, shouldFiltersExist, shouldC2paExist,
			shouldImageProxyExist = false, false, false, false, false, false
	
	local should1080pProxyExist, should720pProxyExist, should360pProxyExist, should1080p709ProxyExist
			= false, false, false, false
	
	if optArgs.docSubtype == 'video' then
	
		shouldImageProxyExist = false
		should1080pProxyExist = true
		should720pProxyExist = true
		should360pProxyExist = true
		should1080p709ProxyExist = true

	else
	
		shouldXmpSidecarExist = not expectedBinaryTypesToPurge[ 'original' ]
			-- The xmp sidecar should be removed if the original is removed.
		shouldDevelopSettingsExist = not expectedBinaryTypesToPurge[ 'xmp_develop' ]
		shouldMasksExist = not expectedBinaryTypesToPurge[ 'aux' ] and optArgs.hasMasks
		shouldFiltersExist = not expectedBinaryTypesToPurge[ 'aux' ] and optArgs.hasFilters
		shouldC2paExist = not expectedBinaryTypesToPurge[ 'aux' ] and optArgs.hasC2pa
		shouldImageProxyExist = true
	
	end
	
	if expectedBinaryTypesToPurge[ 'proxy' ] then
	
		local purgeListSizes = optArgs.purgeListSizes
		
		for _, proxySize in ipairs( purgeListSizes ) do
		
			if proxySize == '1080p' then
				should1080pProxyExist = false
			elseif proxySize == '1080p709' then
				should1080p709ProxyExist = false
			elseif proxySize == '720p' then
				should720pProxyExist = false
			elseif proxySize == '360p' then
				should360pProxyExist = false
			elseif proxySize == '2560' then
				shouldImageProxyExist = false
			elseif proxySize == 'panorama' then
				shouldImageProxyExist = false
			end
		
		end

	end
	
	local shouldPreviewExist = not expectedBinaryTypesToPurge[ 'preview' ]
	local shouldThumbnail2xExist = not expectedBinaryTypesToPurge[ 'thumbnail2x' ]
	local shouldFullSizeExist = not expectedBinaryTypesToPurge[ 'fullsize' ]

	return {
		-- Original
		shouldOriginalExist = shouldOriginalExist,
		shouldXmpSidecarExist = shouldXmpSidecarExist,
		-- Image Proxy
		shouldImageProxyExist = shouldImageProxyExist,
		-- Video Proxies
		should1080pProxyExist = should1080pProxyExist,
		should720pProxyExist = should720pProxyExist,
		should360pProxyExist = should360pProxyExist,
		should1080p709ProxyExist = should1080p709ProxyExist,
		-- Develop Settings
		shouldDevelopSettingsExist = shouldDevelopSettingsExist,
		-- Aux
		shouldMasksExist = not not shouldMasksExist,
		shouldFiltersExist = not not shouldFiltersExist,
		shouldC2paExist = not not shouldC2paExist,
		-- Renditions
		shouldPreviewExist = shouldPreviewExist,
		shouldThumbnail2xExist = shouldThumbnail2xExist,
		shouldFullSizeExist = shouldFullSizeExist
	}

end

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

-- @mark Asset Test Helper Functions

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

local function checkAuxParentFolders( rxTest, expectedBinaries, expectedData )

	if not ( expectedBinaries.shouldMasksExist 
			or expectedBinaries.shouldFiltersExist 
			or expectedBinaries.shouldC2paExist ) then

		-- Make sure Aux parent folders were deleted.

		if expectedData.mask1FilePath then

			local mask1ParentPath = KSPathUtils.parent( expectedData.mask1FilePath )

			rxTest:expectEqual( false, doesFileExist( mask1ParentPath ) )

		end
		
		if expectedData.mask2FilePath then

			local mask2ParentPath = KSPathUtils.parent( expectedData.mask2FilePath )

			rxTest:expectEqual( false, doesFileExist( mask2ParentPath ) )

		end

		if expectedData.filter1FilePath then

			local filter1ParentPath = KSPathUtils.parent( expectedData.filter1FilePath )

			rxTest:expectEqual( false, doesFileExist( filter1ParentPath ) )

		end

		if expectedData.filter2FilePath then

			local filter2ParentPath = KSPathUtils.parent( expectedData.filter2FilePath )

			rxTest:expectEqual( false, doesFileExist( filter2ParentPath ) )

		end

		if expectedData.c2paFilePath then

			local c2paParentPath = KSPathUtils.parent( expectedData.c2paFilePath )

			rxTest:expectEqual( false, doesFileExist( c2paParentPath ) )

		end

	end

end

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

local function testDeleteFilesByPurgeList_Asset_Desktop(
		rxTest, optArgs, wfCatalog, binaryType, purgeList, expectedDataByAssetId )

	local isVideo = optArgs.docSubtype == 'video'

	local hasMasks = not not ( optArgs.hasAllAuxType or optArgs.hasDevelopAux or optArgs.hasMasks )
	local hasFilters = not not ( optArgs.hasAllAuxType or optArgs.hasDevelopAux or optArgs.hasFilters )
	local hasC2pa = not not ( optArgs.hasAllAuxType or optArgs.hasC2pa )

	-- Verify All Files Exist on Disk
	
	for _, expectedData in pairs( expectedDataByAssetId ) do
	
		rxTest:expectEqual( true, doesFileExist( expectedData.originalFilePath ) )
	
		-- Image only files
		
		rxTest:expectEqual( not isVideo, doesFileExist( expectedData.xmpDevelopSettingsFilePath ) )
		
		rxTest:expectEqual( hasMasks, doesFileExist( expectedData.mask1FilePath ) )
		rxTest:expectEqual( hasMasks, doesFileExist( expectedData.mask2FilePath ) )

		rxTest:expectEqual( hasFilters, doesFileExist( expectedData.filter1FilePath ) )
		rxTest:expectEqual( hasFilters, doesFileExist( expectedData.filter2FilePath ) )

		rxTest:expectEqual( hasC2pa, doesFileExist( expectedData.c2paFilePath ) )
		
		rxTest:expectEqual( not isVideo, doesFileExist( expectedData.xmpSidecarFilePath ) )
		rxTest:expectEqual( not isVideo, doesFileExist( expectedData.proxyFilePath ) )
		
		-- Video Proxies should only exist for videos
		
		rxTest:expectEqual( isVideo, doesFileExist( expectedData.proxy1080pFilePath ) )
		rxTest:expectEqual( isVideo, doesFileExist( expectedData.proxy720pFilePath ) )
		rxTest:expectEqual( isVideo, doesFileExist( expectedData.proxy360pFilePath ) )
		rxTest:expectEqual( isVideo, doesFileExist( expectedData.proxy1080p709FilePath ) )
		
	end

	-- Verify Local Only Annotations Exist
	
	for assetId, expectedData in pairs( expectedDataByAssetId ) do
	
		rxTest:waitFor( wfCatalog:docStore():docValue( assetId )
		
			:map( function( assetDocValue )
				
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'original', 'master', 'relativePath' ),
						true )
				
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'proxy', 'panorama', 'relativePath' ),
						not not optArgs.isPanorama )
			
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'proxy', '1080p', 'relativePath' ),
						isVideo )
	
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'proxy', '1080p709', 'relativePath' ),
						isVideo )
	
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'proxy', '720p', 'relativePath' ),
						isVideo )
					
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'proxy', '360p', 'relativePath' ),
						isVideo )
				
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'original', 'xmp', 'path' ),
						not isVideo )
					
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'xmp_develop', 'path' ),
						not isVideo )
					
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'aux', expectedData.mask1Fingerprint, 'relativePath' ),
						hasMasks )
						
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'aux', expectedData.mask2Fingerprint, 'relativePath' ),
						hasMasks )

				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'aux', expectedData.filter1Fingerprint, 'relativePath' ),
						hasFilters )
						
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'aux', expectedData.filter2Fingerprint, 'relativePath' ),
						hasFilters )

				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'aux', expectedData.c2paFingerprint, 'relativePath' ),
						hasC2pa )
					
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'proxy', '2560', 'relativePath' ),
						not isVideo and not optArgs.isPanorama )

				return true

			end ) )
	
	end

	-- Perform Purge

	local expectedBinaries = getExpectedBinariesAfterPurge( purgeList, optArgs )
	
	if binaryType == 'preview' or binaryType == 'thumbnail2x' or binaryType == 'fullsize' then
		return rxTest:expectOnlyError( WFCatPurgeHelper.deleteFilesByPurgeList( wfCatalog, purgeList ), ':ignore:' )
	else
		rxTest:waitFor( WFCatPurgeHelper.deleteFilesByPurgeList( wfCatalog, purgeList ) )
	end
	
	-- Verify files in purge list were removed, and that nothing else was removed.
	
	for assetId, expectedData in pairs( expectedDataByAssetId ) do
	
		rxTest:expectEqual( expectedBinaries.shouldOriginalExist, doesFileExist( expectedData.originalFilePath ) )
		rxTest:expectEqual( expectedBinaries.should1080pProxyExist, doesFileExist( expectedData.proxy1080pFilePath ) )
		rxTest:expectEqual( expectedBinaries.should720pProxyExist, doesFileExist( expectedData.proxy720pFilePath ) )
		rxTest:expectEqual( expectedBinaries.should360pProxyExist, doesFileExist( expectedData.proxy360pFilePath ) )
		rxTest:expectEqual( expectedBinaries.should1080p709ProxyExist, doesFileExist( expectedData.proxy1080p709FilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldDevelopSettingsExist, doesFileExist( expectedData.xmpDevelopSettingsFilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldMasksExist, doesFileExist( expectedData.mask1FilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldMasksExist, doesFileExist( expectedData.mask2FilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldFiltersExist, doesFileExist( expectedData.filter1FilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldFiltersExist, doesFileExist( expectedData.filter2FilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldC2paExist, doesFileExist( expectedData.c2paFilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldXmpSidecarExist, doesFileExist( expectedData.xmpSidecarFilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldImageProxyExist, doesFileExist( expectedData.proxyFilePath ) )

		if hasMasks or hasFilters or hasC2pa then
			checkAuxParentFolders( rxTest, expectedBinaries, expectedData )
		end

		rxTest:waitFor( wfCatalog:docStore():docValue( assetId )
		
			:map( function( assetDocValue )
				
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'original', 'master', 'relativePath' ),
						expectedBinaries.shouldOriginalExist )
				
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'proxy', 'panorama', 'relativePath' ),
						optArgs.isPanorama and expectedBinaries.shouldImageProxyExist or false )

				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'proxy', '1080p', 'relativePath' ),
						expectedBinaries.should1080pProxyExist )
	
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'proxy', '720p', 'relativePath' ),
						expectedBinaries.should720pProxyExist )
					
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'proxy', '360p', 'relativePath' ),
						expectedBinaries.should360pProxyExist )
						
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'proxy', '1080p709', 'relativePath' ),
						expectedBinaries.should1080p709ProxyExist )
					
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'xmp_develop', 'path' ),
						expectedBinaries.shouldDevelopSettingsExist )
				
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'aux', expectedData.mask1Fingerprint, 'relativePath' ),
						expectedBinaries.shouldMasksExist )
						
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'aux', expectedData.mask2Fingerprint, 'relativePath' ),
						expectedBinaries.shouldMasksExist )
				
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'aux', expectedData.filter1Fingerprint, 'relativePath' ),
						expectedBinaries.shouldFiltersExist )
							
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'aux', expectedData.filter2Fingerprint, 'relativePath' ),
						expectedBinaries.shouldFiltersExist )
							
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'aux', expectedData.c2paFingerprint, 'relativePath' ),
						expectedBinaries.shouldC2paExist )
				
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'original', 'xmp', 'path' ),
						expectedBinaries.shouldXmpSidecarExist )
				
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'proxy', '2560', 'relativePath' ),
						expectedBinaries.shouldImageProxyExist )

				return true

			end ) )
	
	end

end

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

local function verifyAnnotationsBeforePurge_mobile( rxTest, wfCatalog, expectedDataByAssetId, optArgs )

	local isVideo = optArgs.docSubtype == 'video'

	local hasMasks = not not ( optArgs.hasAllAuxType or optArgs.hasDevelopAux or optArgs.hasMasks )
	local hasFilters = not not ( optArgs.hasAllAuxType or optArgs.hasDevelopAux or optArgs.hasFilters )
	local hasC2pa = not not ( optArgs.hasAllAuxType or optArgs.hasC2pa )

	for assetId, expectedData in pairs( expectedDataByAssetId ) do
	
		rxTest:waitFor( wfCatalog:docStore():docValue( assetId )
		
			:map( function( assetDocValue )
				
				rxTest:expectEqual(
						doesUniversalFieldExist(
								assetDocValue, 'files', 'original', 'master', 'relativePath' ),
						true )
				
				if WFPlatformInfo.isiOS then
				
					rxTest:expectEqual(
							doesFieldExist(
									assetDocValue, '_localOnly', 'files', 'latestMaster', 'filePath' ),
							true )
							
				else
				
					rxTest:expectEqual(
							doesFieldExist( 
									assetDocValue, '_localOnly', 'latestOriginal', 'filePath' ),
							true )
				
				end
						
				rxTest:expectEqual(
						doesUniversalFieldExist(
								assetDocValue, 'files', 'renditions', '2048', 'relativePath' ),
						true )
						
				rxTest:expectEqual(
						doesUniversalFieldExist(
								assetDocValue, 'files', 'renditions', 'fullsize', 'relativePath' ),
						true )
						
				rxTest:expectEqual(
						doesUniversalFieldExist(
								assetDocValue, 'files', 'renditions', 'thumbnail2x', 'relativePath' ),
						true )
			
				rxTest:expectEqual(
						doesUniversalFieldExist(
								assetDocValue, 'files', 'proxy', '1080p', 'relativePath' ),
						isVideo )
				
				rxTest:expectEqual(
						doesUniversalFieldExist(
								assetDocValue, 'files', 'proxy', '360p', 'relativePath' ),
						isVideo )

				rxTest:expectEqual(
						doesUniversalFieldExist(
								assetDocValue, 'files', 'proxy', '2560', 'relativePath' ),
						not isVideo )

				rxTest:expectEqual(
						doesUniversalFieldExist(
								assetDocValue, 'files', 'xmp_develop', 'relativePath' ),
						not isVideo )

				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'aux', expectedData.mask1Fingerprint, 'relativePath' ),
						hasMasks )
						
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'aux', expectedData.mask2Fingerprint, 'relativePath' ),
						hasMasks )

				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'aux', expectedData.filter1Fingerprint, 'relativePath' ),
						hasFilters )
							
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'aux', expectedData.filter2Fingerprint, 'relativePath' ),
						hasFilters )

				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'aux', expectedData.c2paFingerprint, 'relativePath' ),
						hasC2pa )

				return true

			end ) )
	
	end

end

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

local function verifyAnnotationsAfterPurge_mobile( rxTest, wfCatalog, purgeList, expectedDataByAssetId, expectedBinaries, optArgs )

	for assetId, expectedData in pairs( expectedDataByAssetId ) do
	
		rxTest:waitFor( wfCatalog:docStore():docValue( assetId )
		
			:map( function( assetDocValue )
				
				rxTest:expectEqual(
						doesUniversalFieldExist(
								assetDocValue, 'files', 'original', 'master', 'relativePath' ),
						expectedBinaries.shouldOriginalExist )
						
				if WFPlatformInfo.isiOS then
				
					rxTest:expectEqual(
							doesFieldExist(
									assetDocValue, '_localOnly', 'files', 'latestMaster', 'filePath' ),
							expectedBinaries.shouldOriginalExist )
							
				else
				
					rxTest:expectEqual(
							doesFieldExist( 
									assetDocValue, '_localOnly', 'latestOriginal', 'filePath' ),
							expectedBinaries.shouldOriginalExist )
				
				end
						
				rxTest:expectEqual(
						doesUniversalFieldExist(
								assetDocValue, 'files', 'renditions', '2048', 'relativePath' ),
						expectedBinaries.shouldPreviewExist )
						
				rxTest:expectEqual(
						doesUniversalFieldExist(
								assetDocValue, 'files', 'renditions', 'thumbnail2x', 'relativePath' ),
						expectedBinaries.shouldThumbnail2xExist )
						
				rxTest:expectEqual(
						doesUniversalFieldExist(
								assetDocValue, 'files', 'renditions', 'fullsize', 'relativePath' ),
						expectedBinaries.shouldFullSizeExist )

				rxTest:expectEqual(
						doesUniversalFieldExist(
								assetDocValue, 'files', 'proxy', '1080p', 'relativePath' ),
						expectedBinaries.should1080pProxyExist )
					
				rxTest:expectEqual(
						doesUniversalFieldExist(
								assetDocValue, 'files', 'proxy', '360p', 'relativePath' ),
						expectedBinaries.should360pProxyExist )

				rxTest:expectEqual(
						doesUniversalFieldExist(
								assetDocValue, 'files', 'proxy', '2560', 'relativePath' ),
						expectedBinaries.shouldImageProxyExist )
						
				rxTest:expectEqual(
						doesUniversalFieldExist(
								assetDocValue, 'files', 'xmp_develop', 'relativePath' ),
						expectedBinaries.shouldDevelopSettingsExist )
						
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'aux', expectedData.mask1Fingerprint, 'relativePath' ),
						expectedBinaries.shouldMasksExist )
						
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'aux', expectedData.mask2Fingerprint, 'relativePath' ),
						expectedBinaries.shouldMasksExist )

				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'aux', expectedData.filter1Fingerprint, 'relativePath' ),
						expectedBinaries.shouldFiltersExist )
							
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'aux', expectedData.filter2Fingerprint, 'relativePath' ),
						expectedBinaries.shouldFiltersExist )
				
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'aux', expectedData.c2paFingerprint, 'relativePath' ),
						expectedBinaries.shouldC2paExist )
					
				return true
				
			end ) )

	end

end

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

local function testDeleteFilesByPurgeList_Asset_iOS(
		rxTest, optArgs, wfCatalog, purgeList, expectedDataByAssetId )

	-- Verify Files Exist on the File System

	local isVideo = optArgs.docSubtype == 'video'

	local hasMasks = not not ( optArgs.hasAllAuxType or optArgs.hasDevelopAux or optArgs.hasMasks )
	local hasFilters = not not ( optArgs.hasAllAuxType or optArgs.hasDevelopAux or optArgs.hasFilters )
	local hasC2pa = not not ( optArgs.hasAllAuxType or optArgs.hasC2pa )

	for _, expectedData in pairs( expectedDataByAssetId ) do
		
		rxTest:expectEqual( true, doesFileExist( expectedData.originalFilePath ) )
		rxTest:expectEqual( true, doesFileExist( expectedData.latestOriginalFilePath ) )
		rxTest:expectEqual( true, doesFileExist( expectedData.previewFilePath ) )
		rxTest:expectEqual( true, doesFileExist( expectedData.thumbnailFilePath ) )
		rxTest:expectEqual( true, doesFileExist( expectedData.fullsizeFilePath ) )
		
		rxTest:expectEqual( isVideo, doesFileExist( expectedData.proxy1080pFilePath ) )
		rxTest:expectEqual( isVideo, doesFileExist( expectedData.proxy360pFilePath ) )

		rxTest:expectEqual( not isVideo, doesFileExist( expectedData.proxyFilePath ) )
		rxTest:expectEqual( not isVideo, doesFileExist( expectedData.xmpDevelopSettingsFilePath ) )
		rxTest:expectEqual( hasMasks, doesFileExist( expectedData.mask1FilePath ) )
		rxTest:expectEqual( hasMasks, doesFileExist( expectedData.mask2FilePath ) )
		rxTest:expectEqual( hasFilters, doesFileExist( expectedData.filter1FilePath ) )
		rxTest:expectEqual( hasFilters, doesFileExist( expectedData.filter2FilePath ) )
		rxTest:expectEqual( hasC2pa, doesFileExist( expectedData.c2paFilePath ) )
	
	end
	
	-- Verify Local Only Annotations Exist
	
	verifyAnnotationsBeforePurge_mobile( rxTest, wfCatalog, expectedDataByAssetId, optArgs )
	
	-- Perform Purge

	local expectedBinaries = getExpectedBinariesAfterPurge( purgeList, optArgs )

	rxTest:waitFor( WFCatPurgeHelper.deleteFilesByPurgeList( wfCatalog, purgeList ) )
	
	-- Verify files in purge list were removed, and that nothing else was removed.
	
	for assetId, expectedData in pairs( expectedDataByAssetId ) do

		rxTest:expectEqual( expectedBinaries.shouldOriginalExist, doesFileExist( expectedData.originalFilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldOriginalExist, doesFileExist( expectedData.latestOriginalFilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldPreviewExist, doesFileExist( expectedData.previewFilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldThumbnail2xExist, doesFileExist( expectedData.thumbnailFilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldFullSizeExist, doesFileExist( expectedData.fullsizeFilePath ) )
		rxTest:expectEqual( expectedBinaries.should1080pProxyExist, doesFileExist( expectedData.proxy1080pFilePath ) )
		rxTest:expectEqual( expectedBinaries.should360pProxyExist, doesFileExist( expectedData.proxy360pFilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldDevelopSettingsExist, doesFileExist( expectedData.xmpDevelopSettingsFilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldMasksExist, doesFileExist( expectedData.mask1FilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldMasksExist, doesFileExist( expectedData.mask2FilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldFiltersExist, doesFileExist( expectedData.filter1FilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldFiltersExist, doesFileExist( expectedData.filter2FilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldC2paExist, doesFileExist( expectedData.c2paFilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldImageProxyExist, doesFileExist( expectedData.proxyFilePath ) )

		if hasMasks or hasFilters or hasC2pa then
			checkAuxParentFolders( rxTest, expectedBinaries, expectedData )
		end

	end
		
	-- Verify Local Only Annotations Were Removed
	
	verifyAnnotationsAfterPurge_mobile( rxTest, wfCatalog, purgeList, expectedDataByAssetId, expectedBinaries, optArgs )

end

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

local function testDeleteFilesByPurgeList_Asset_Android(
		rxTest, optArgs, wfCatalog, purgeList, expectedDataByAssetId, dataCache )

	-- Verify All Files Exist
	
	local isVideo = optArgs.docSubtype == 'video'
	
	local hasMasks = not not ( optArgs.hasAllAuxType or optArgs.hasDevelopAux or optArgs.hasMasks )
	local hasFilters = not not ( optArgs.hasAllAuxType or optArgs.hasDevelopAux or optArgs.hasFilters )
	local hasC2pa = not not ( optArgs.hasAllAuxType or optArgs.hasC2pa )
	
	for _, expectedData in pairs( expectedDataByAssetId ) do

		rxTest:expectEqual( true, doesFileExist( expectedData.originalFilePath ) )
		rxTest:expectEqual( true, doesFileExist( expectedData.latestOriginalFilePath ) )
		rxTest:expectSingleValue( dataCache:get( expectedData.previewMd5 ):map( toBool ), true )
		rxTest:expectSingleValue( dataCache:get( expectedData.thumbMd5 ):map( toBool ), true )
		rxTest:expectSingleValue( dataCache:get( expectedData.fullsizeMd5 ):map( toBool ), true )
		
		rxTest:expectEqual( isVideo, doesFileExist( expectedData.proxy1080pFilePath ) )
		rxTest:expectEqual( isVideo, doesFileExist( expectedData.proxy360pFilePath ) )

		rxTest:expectEqual( not isVideo, doesFileExist( expectedData.proxyFilePath ) )
		rxTest:expectEqual( not isVideo, doesFileExist( expectedData.xmpDevelopSettingsFilePath ) )
		rxTest:expectEqual( hasMasks, doesFileExist( expectedData.mask1FilePath ) )
		rxTest:expectEqual( hasMasks, doesFileExist( expectedData.mask2FilePath ) )
		rxTest:expectEqual( hasFilters, doesFileExist( expectedData.filter1FilePath ) )
		rxTest:expectEqual( hasFilters, doesFileExist( expectedData.filter2FilePath ) )
		rxTest:expectEqual( hasC2pa, doesFileExist( expectedData.c2paFilePath ) )
	
	end
	
	-- Verify Local Only Annotations Exist
	
	verifyAnnotationsBeforePurge_mobile( rxTest, wfCatalog, expectedDataByAssetId, optArgs )
	
	-- Perform Purge

	local expectedBinaries = getExpectedBinariesAfterPurge( purgeList, optArgs )

	rxTest:waitFor( WFCatPurgeHelper.deleteFilesByPurgeList( wfCatalog, purgeList, nil, dataCache ) )
	
	-- Verify files in purge list were removed, and that nothing else was removed.
	
	for assetId, expectedData in pairs( expectedDataByAssetId ) do
	
		rxTest:expectEqual( expectedBinaries.shouldOriginalExist, doesFileExist( expectedData.originalFilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldOriginalExist, doesFileExist( expectedData.latestOriginalFilePath ) )
		rxTest:expectSingleValue( dataCache:get( expectedData.previewMd5 ):map( toBool ),  expectedBinaries.shouldPreviewExist )
		rxTest:expectSingleValue( dataCache:get( expectedData.thumbMd5 ):map( toBool ),  expectedBinaries.shouldThumbnail2xExist )
		rxTest:expectSingleValue( dataCache:get( expectedData.fullsizeMd5 ):map( toBool ),  expectedBinaries.shouldFullSizeExist )
		rxTest:expectEqual( expectedBinaries.should1080pProxyExist, doesFileExist( expectedData.proxy1080pFilePath ) )
		rxTest:expectEqual( expectedBinaries.should360pProxyExist, doesFileExist( expectedData.proxy360pFilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldDevelopSettingsExist, doesFileExist( expectedData.xmpDevelopSettingsFilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldMasksExist, doesFileExist( expectedData.mask1FilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldMasksExist, doesFileExist( expectedData.mask2FilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldFiltersExist, doesFileExist( expectedData.filter1FilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldFiltersExist, doesFileExist( expectedData.filter2FilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldC2paExist, doesFileExist( expectedData.c2paFilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldImageProxyExist, doesFileExist( expectedData.proxyFilePath ) )

		if hasMasks or hasFilters or hasC2pa then
			checkAuxParentFolders( rxTest, expectedBinaries, expectedData )
		end

	end
	
	-- Verify Local Only Annotations Were Removed
	
	verifyAnnotationsAfterPurge_mobile( rxTest, wfCatalog, purgeList, expectedDataByAssetId, expectedBinaries, optArgs )

end

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

local function fillDataCacheForImageAsset( rxTest, dataCache, expectedData )

	local previewData = KSData.memoryMappedContentsOfFile( expectedData.previewFilePath )
	local thumbnail2xData = KSData.memoryMappedContentsOfFile( expectedData.thumbnailFilePath )
	local fullsizeData = KSData.memoryMappedContentsOfFile( expectedData.fullsizeFilePath )
	
	expectedData.previewMd5 = previewData:digest( 'MD5' )
	expectedData.thumbMd5 = thumbnail2xData:digest( 'MD5' )
	expectedData.fullsizeMd5 = fullsizeData:digest( 'MD5' )
	
	rxTest:waitFor( dataCache:put( expectedData.previewMd5, previewData ) )
	rxTest:waitFor( dataCache:put( expectedData.thumbMd5, thumbnail2xData ) )
	rxTest:waitFor( dataCache:put( expectedData.fullsizeMd5, fullsizeData ) )
	
	rxTest:finally( function()
	
		previewData:close()
		thumbnail2xData:close()
		fullsizeData:close()
		
	end )

end

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

local function clearOutAuxCruftFromPreviousTestRuns( wfCatalog )

	local baseAuxPath = WFCatAssetAux.getBasePath( wfCatalog )
	local auxPath = KSPathUtils.child( baseAuxPath, 'auxiliary' )
	WFFileUtils.deleteDirectory( auxPath, false )

end

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

local function testDeleteFilesByPurgeList( rxTest, binaryType, optArgs, purgeListSizes )

	rxTest:setTimeLimit( 10 )
	
	optArgs = optArgs or {}
	
	optArgs.purgeListSizes = purgeListSizes
	
	local wfCatalog, maybeDataCache = createFakeWFCatalog( rxTest )
	
	clearOutAuxCruftFromPreviousTestRuns( wfCatalog )

	local expectedDataByAssetId = {}
	
	local numberOfDocumentsToCreate = 3
	
	local purgeList = {
		binaryType = binaryType
	}
	
	for i = 1, numberOfDocumentsToCreate, 1 do
	
		local assetId = KSIdGenerator.uuidInLowercaseHex()
		
		local assetDocValue, expectedData = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, assetId, optArgs )
		
		if maybeDataCache then
			fillDataCacheForImageAsset( rxTest, maybeDataCache, expectedData )
		end
		
		rxTest:waitFor( wfCatalog:docStore():setDocValue( assetDocValue ) )
		
		local localId = rxTest:getFirstValue( wfCatalog:docStore():docIdToLocalId( assetId ) )
		
		expectedDataByAssetId[ assetId ] = expectedData
	
		if binaryType == 'aux' then
		
			purgeList[ localId ] = {
				expectedData.mask1Fingerprint,
				expectedData.mask2Fingerprint,
				expectedData.filter1Fingerprint,
				expectedData.filter2Fingerprint,
				expectedData.c2paFingerprint
			}
			
		elseif binaryType == 'proxy' then

			purgeList[ localId ] = purgeListSizes
			
		else
		
			purgeList[ localId ] = true
			
		end
		
	end
	
	purgeList = { purgeList }
	
	if WFPlatformInfo.isDesktop then
	
		testDeleteFilesByPurgeList_Asset_Desktop( rxTest, optArgs, wfCatalog, binaryType, purgeList, expectedDataByAssetId )
		
	elseif WFPlatformInfo.isiOS then
	
		testDeleteFilesByPurgeList_Asset_iOS( rxTest, optArgs, wfCatalog, purgeList, expectedDataByAssetId )
		
	elseif WFPlatformInfo.isAndroid then
	
		testDeleteFilesByPurgeList_Asset_Android( rxTest, optArgs, wfCatalog, purgeList, expectedDataByAssetId, maybeDataCache )
		
	end

end

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

-- @mark Image Asset Tests

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

function WFCatPurgeHelperTest.rxTestDeleteFilesByPurgeList_Original( rxTest )
	
	testDeleteFilesByPurgeList( rxTest, 'original' )

end

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

function WFCatPurgeHelperTest.rxTestDeleteFilesByPurgeList_Proxy( rxTest )
	
	local purgeListSizes = { '2560' }
	
	testDeleteFilesByPurgeList( rxTest, 'proxy', nil, purgeListSizes )

end

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

function WFCatPurgeHelperTest.rxTestDeleteFilesByPurgeList_DevelopSettings( rxTest )
	
	local optArgs = {
		hasAllAuxType = true
	}
	
	testDeleteFilesByPurgeList( rxTest, 'xmp_develop', optArgs )

end

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

function WFCatPurgeHelperTest.rxTestDeleteFilesByPurgeList_Masks( rxTest )
	
	local optArgs = {
		hasAllAuxType = true
	}
	
	testDeleteFilesByPurgeList( rxTest, 'aux', optArgs )

end

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

function WFCatPurgeHelperTest.rxTestDeleteFilesByPurgeList_Preview( rxTest )
	
	testDeleteFilesByPurgeList( rxTest, 'preview' )

end

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

function WFCatPurgeHelperTest.rxTestDeleteFilesByPurgeList_Thumbnail( rxTest )
	
	testDeleteFilesByPurgeList( rxTest, 'thumbnail2x' )

end

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

function WFCatPurgeHelperTest.rxTestDeleteFilesByPurgeList_FullSize_Rendition( rxTest )
	
	testDeleteFilesByPurgeList( rxTest, 'fullsize' )

end

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

-- @mark Panorama Image Asset Tests

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

if WFPlatformInfo.isDesktop then

	function WFCatPurgeHelperTest.rxTestDeleteFilesByPurgeList_Pano_Proxy( rxTest )
		
		local optArgs = {
			isPanorama = true
		}
		
		local purgeListSizes = { 'panorama' }
		
		testDeleteFilesByPurgeList( rxTest, 'proxy', optArgs, purgeListSizes )

	end
	
end

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

-- @mark Video Asset Tests

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

function WFCatPurgeHelperTest.rxTestDeleteFilesByPurgeList_Video_Original( rxTest )
	
	local optArgs = {
		docSubtype = 'video',
		hasLocal360p = true,
		hasLocal720p = true,
		hasLocal1080p = true,
		hasLocal1080p709 = true
	}
	
	testDeleteFilesByPurgeList( rxTest, 'original', optArgs )

end

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

function WFCatPurgeHelperTest.rxTestDeleteFilesByPurgeList_Video_Proxy_1080p( rxTest )
	
	local optArgs = {
		docSubtype = 'video',
		hasLocal360p = true,
		hasLocal720p = true,
		hasLocal1080p = true,
		hasLocal1080p709 = true
	}
	
	local purgeListSizes = { '1080p' }
	
	testDeleteFilesByPurgeList( rxTest, 'proxy', optArgs, purgeListSizes )

end

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

function WFCatPurgeHelperTest.rxTestDeleteFilesByPurgeList_Video_Proxy_360p( rxTest )
	
	local optArgs = {
		docSubtype = 'video',
		hasLocal360p = true,
		hasLocal720p = true,
		hasLocal1080p = true,
		hasLocal1080p709 = true
	}
	
	local purgeListSizes = { '360p' }
	
	testDeleteFilesByPurgeList( rxTest, 'proxy', optArgs, purgeListSizes )

end

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

function WFCatPurgeHelperTest.rxTestDeleteFilesByPurgeList_Video_Proxy_360pAnd1080p( rxTest )
	
	local optArgs = {
		docSubtype = 'video',
		hasLocal360p = true,
		hasLocal720p = true,
		hasLocal1080p = true,
		hasLocal1080p709 = true
	}
	
	local purgeListSizes = { '1080p', '360p' }
	
	testDeleteFilesByPurgeList( rxTest, 'proxy', optArgs, purgeListSizes )

end

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

if WFPlatformInfo.isDesktop then

function WFCatPurgeHelperTest.rxTestDeleteFilesByPurgeList_Video_Proxy_720p( rxTest )
	
	local optArgs = {
		docSubtype = 'video',
		hasLocal360p = true,
		hasLocal720p = true,
		hasLocal1080p = true,
		hasLocal1080p709 = true
	}
	
	local purgeListSizes = { '720p' }
	
	testDeleteFilesByPurgeList( rxTest, 'proxy', optArgs, purgeListSizes )

end

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

function WFCatPurgeHelperTest.rxTestDeleteFilesByPurgeList_Video_Proxy_1080p709( rxTest )
	
	local optArgs = {
		docSubtype = 'video',
		hasLocal360p = true,
		hasLocal720p = true,
		hasLocal1080p = true,
		hasLocal1080p709 = true
	}
	
	local purgeListSizes = { '1080p709' }
	
	testDeleteFilesByPurgeList( rxTest, 'proxy', optArgs, purgeListSizes )

end

end

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

function WFCatPurgeHelperTest.rxTestDeleteFilesByPurgeList_Video_Preview( rxTest )
	
	local optArgs = {
		docSubtype = 'video',
		hasLocal360p = true,
		hasLocal720p = true,
		hasLocal1080p = true,
		hasLocal1080p709 = true
	}
	
	testDeleteFilesByPurgeList( rxTest, 'preview', optArgs )

end

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

function WFCatPurgeHelperTest.rxTestDeleteFilesByPurgeList_Video_Thumbnail( rxTest )
	
	local optArgs = {
		docSubtype = 'video',
		hasLocal360p = true,
		hasLocal720p = true,
		hasLocal1080p = true,
		hasLocal1080p709 = true
	}
	
	testDeleteFilesByPurgeList( rxTest, 'thumbnail2x', optArgs )

end

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

-- @mark Version Test Helper Functions

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

local function testDeleteFilesByPurgeList_Version_Desktop( rxTest, optArgs, wfCatalog, binaryType, purgeList, expectedDataByAssetId )

	local hasMasks = not not ( optArgs.hasAllAuxType or optArgs.hasDevelopAux or optArgs.hasMasks )
	local hasFilters = not not ( optArgs.hasAllAuxType or optArgs.hasDevelopAux or optArgs.hasFilters )
	local hasC2pa = not not ( optArgs.hasAllAuxType or optArgs.hasC2pa )

	for assetId, expectedData in pairs( expectedDataByAssetId ) do
	
		rxTest:expectEqual( true, doesFileExist( expectedData.xmpDevelopSettingsFilePath ) )
		rxTest:expectEqual( hasMasks, doesFileExist( expectedData.mask1FilePath ) )
		rxTest:expectEqual( hasMasks, doesFileExist( expectedData.mask2FilePath ) )
		rxTest:expectEqual( hasFilters, doesFileExist( expectedData.filter1FilePath ) )
		rxTest:expectEqual( hasFilters, doesFileExist( expectedData.filter2FilePath ) )
		rxTest:expectEqual( hasC2pa, doesFileExist( expectedData.c2paFilePath ) )

		rxTest:waitFor( wfCatalog:docStore():docValue( assetId )
		
			:map( function( assetDocValue )
				
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'xmp_develop', 'path' ),
						true )

				return true
				
			end ) )

	end

	-- Perform Purge

	local expectedBinaries = getExpectedBinariesAfterPurge( purgeList, optArgs )
	
	if binaryType == 'preview' or binaryType == 'thumbnail2x' then
		return rxTest:expectOnlyError( WFCatPurgeHelper.deleteFilesByPurgeList( wfCatalog, purgeList ), ':ignore:' )
	else
		rxTest:waitFor( WFCatPurgeHelper.deleteFilesByPurgeList( wfCatalog, purgeList ) )
	end
	
	-- Verify files in purge list were removed, and that nothing else was removed.
	
	for assetId, expectedData in pairs( expectedDataByAssetId ) do
	
		rxTest:waitFor( wfCatalog:docStore():docValue( assetId )
		
			:map( function( assetDocValue )
				
				rxTest:expectEqual( expectedBinaries.shouldDevelopSettingsExist, doesFileExist( expectedData.xmpDevelopSettingsFilePath ) )
				
				rxTest:expectEqual( expectedBinaries.shouldMasksExist, doesFileExist( expectedData.mask1FilePath ) )
				rxTest:expectEqual( expectedBinaries.shouldMasksExist, doesFileExist( expectedData.mask2FilePath ) )
				rxTest:expectEqual( expectedBinaries.shouldFiltersExist, doesFileExist( expectedData.filter1FilePath ) )
				rxTest:expectEqual( expectedBinaries.shouldFiltersExist, doesFileExist( expectedData.filter2FilePath ) )
				rxTest:expectEqual( expectedBinaries.shouldC2paExist, doesFileExist( expectedData.c2paFilePath ) )
				
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'xmp_develop', 'path' ),
						expectedBinaries.shouldDevelopSettingsExist )

				return true
				
			end ) )
	
	end

end

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

local function testDeleteFilesByPurgeList_Version_iOS( rxTest, optArgs, wfCatalog, purgeList, expectedDataByAssetId )

	local hasMasks = not not ( optArgs.hasAllAuxType or optArgs.hasDevelopAux or optArgs.hasMasks )
	local hasFilters = not not ( optArgs.hasAllAuxType or optArgs.hasDevelopAux or optArgs.hasFilters )
	local hasC2pa = not not ( optArgs.hasAllAuxType or optArgs.hasC2pa )

	-- Verify All Files Exist
	
	for _, expectedData in pairs( expectedDataByAssetId ) do
	
		rxTest:expectEqual( true, doesFileExist( expectedData.thumbnailFilePath ) )
		rxTest:expectEqual( true, doesFileExist( expectedData.xmpDevelopSettingsFilePath ) )
		rxTest:expectEqual( hasMasks, doesFileExist( expectedData.mask1FilePath ) )
		rxTest:expectEqual( hasMasks, doesFileExist( expectedData.mask2FilePath ) )
		rxTest:expectEqual( hasFilters, doesFileExist( expectedData.filter1FilePath ) )
		rxTest:expectEqual( hasFilters, doesFileExist( expectedData.filter2FilePath ) )
		rxTest:expectEqual( hasC2pa, doesFileExist( expectedData.c2paFilePath ) )
		
	end
	
	-- Perform Purge

	local expectedBinaries = getExpectedBinariesAfterPurge( purgeList, optArgs )

	rxTest:waitFor( WFCatPurgeHelper.deleteFilesByPurgeList( wfCatalog, purgeList ) )
	
	-- Verify files in purge list were removed, and that nothing else was removed.
	
	for assetId, expectedData in pairs( expectedDataByAssetId ) do

		rxTest:expectEqual( expectedBinaries.shouldDevelopSettingsExist, doesFileExist( expectedData.xmpDevelopSettingsFilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldMasksExist, doesFileExist( expectedData.mask1FilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldMasksExist, doesFileExist( expectedData.mask2FilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldFiltersExist, doesFileExist( expectedData.filter1FilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldFiltersExist, doesFileExist( expectedData.filter2FilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldC2paExist, doesFileExist( expectedData.c2paFilePath ) )
		
		rxTest:expectEqual( expectedBinaries.shouldThumbnail2xExist, doesFileExist( expectedData.thumbnailFilePath ) )
		
		rxTest:waitFor( wfCatalog:docStore():docValue( assetId )
		
			:map( function( assetDocValue )
				
				rxTest:expectEqual(
						doesUniversalFieldExist(
								assetDocValue, 'files', 'xmp_develop', 'relativePath' ),
						expectedBinaries.shouldDevelopSettingsExist )

				rxTest:expectEqual(
						doesUniversalFieldExist(
								assetDocValue, 'files', 'renditions', 'thumbnail2x', 'relativePath' ),
						expectedBinaries.shouldThumbnail2xExist )
				
				return true
				
			end ) )
	
	end

end

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

local function testDeleteFilesByPurgeList_Version_Android( rxTest, optArgs, wfCatalog, purgeList, expectedDataByAssetId, dataCache )

	local hasMasks = not not ( optArgs.hasAllAuxType or optArgs.hasDevelopAux or optArgs.hasMasks )
	local hasFilters = not not ( optArgs.hasAllAuxType or optArgs.hasDevelopAux or optArgs.hasFilters )
	local hasC2pa = not not ( optArgs.hasAllAuxType or optArgs.hasC2pa )

	-- Verify All Files Exist
	
	for _, expectedData in pairs( expectedDataByAssetId ) do
	
		rxTest:expectEqual( true, doesFileExist( expectedData.xmpDevelopSettingsFilePath ) )
		rxTest:expectEqual( hasMasks, doesFileExist( expectedData.mask1FilePath ) )
		rxTest:expectEqual( hasMasks, doesFileExist( expectedData.mask2FilePath ) )
		rxTest:expectEqual( hasFilters, doesFileExist( expectedData.filter1FilePath ) )
		rxTest:expectEqual( hasFilters, doesFileExist( expectedData.filter2FilePath ) )
		rxTest:expectEqual( hasC2pa, doesFileExist( expectedData.c2paFilePath ) )
		
		rxTest:expectSingleValue( dataCache:get( expectedData.thumbMd5 ):map( toBool ), true )
	
	end
	
	-- Perform Purge

	local expectedBinaries = getExpectedBinariesAfterPurge( purgeList, optArgs )

	rxTest:waitFor( WFCatPurgeHelper.deleteFilesByPurgeList( wfCatalog, purgeList, nil, dataCache ) )
	
	-- Verify files in purge list were removed, and that nothing else was removed.
	
	for assetId, expectedData in pairs( expectedDataByAssetId ) do
	
		rxTest:expectEqual( expectedBinaries.shouldDevelopSettingsExist, doesFileExist( expectedData.xmpDevelopSettingsFilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldMasksExist, doesFileExist( expectedData.mask1FilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldMasksExist, doesFileExist( expectedData.mask2FilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldFiltersExist, doesFileExist( expectedData.filter1FilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldFiltersExist, doesFileExist( expectedData.filter2FilePath ) )
		rxTest:expectEqual( expectedBinaries.shouldC2paExist, doesFileExist( expectedData.c2paFilePath ) )

		rxTest:expectSingleValue( dataCache:get( expectedData.thumbMd5 ):map( toBool ), expectedBinaries.shouldThumbnail2xExist )
		
		rxTest:waitFor( wfCatalog:docStore():docValue( assetId )
			:map( function( assetDocValue )
						
				rxTest:expectEqual(
						doesUniversalFieldExist(
								assetDocValue, 'files', 'xmp_develop', 'relativePath' ),
						expectedBinaries.shouldDevelopSettingsExist )
						
				rxTest:expectEqual(
						doesUniversalFieldExist(
								assetDocValue, 'files', 'renditions', 'thumbnail2x', 'relativePath' ),
						expectedBinaries.shouldThumbnail2xExist )
						
				return true

			end ) )
	
	end

end

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

local function fillDataCacheForVersion( rxTest, dataCache, expectedData )

	local thumbnail2xData = KSData.memoryMappedContentsOfFile( expectedData.thumbnailFilePath )

	expectedData.thumbMd5 = thumbnail2xData:digest( 'MD5' )
	
	rxTest:waitFor( dataCache:put( expectedData.thumbMd5, thumbnail2xData ) )

	rxTest:finally( function()
	
		thumbnail2xData:close()
	
	end )

end

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

local function testDeleteFilesByPurgeListForVersion( rxTest, binaryType, optArgs )

	rxTest:setTimeLimit( 10 )
	
	optArgs = optArgs or {}
	
	local wfCatalog, maybeDataCache = createFakeWFCatalog( rxTest )
	
	local expectedDataByDocId = {}
	
	local numberOfDocumentsToCreate = 3
	
	local purgeList = {
		binaryType = binaryType
	}
	
	for i = 1, numberOfDocumentsToCreate, 1 do
	
		local docId = KSIdGenerator.uuidInLowercaseHex()
		
		local assetDocValue, expectedData = WFCatVersionTestUtils.createVersionDocument( rxTest, wfCatalog, docId, optArgs )
		
		if maybeDataCache then
			fillDataCacheForVersion( rxTest, maybeDataCache, expectedData )
		end
		
		rxTest:waitFor( wfCatalog:docStore():setDocValue( assetDocValue ) )
		
		expectedDataByDocId[ docId ] = expectedData
	
		purgeList[ #purgeList + 1 ] = docId
	
	end
	
	purgeList = { purgeList }
	
	if WFPlatformInfo.isDesktop then
	
		testDeleteFilesByPurgeList_Version_Desktop( rxTest, optArgs, wfCatalog, binaryType, purgeList, expectedDataByDocId )
		
	elseif WFPlatformInfo.isiOS then
	
		testDeleteFilesByPurgeList_Version_iOS( rxTest, optArgs, wfCatalog, purgeList, expectedDataByDocId )
		
	elseif WFPlatformInfo.isAndroid then
	
		testDeleteFilesByPurgeList_Version_Android( rxTest, optArgs, wfCatalog, purgeList, expectedDataByDocId, maybeDataCache )
		
	end

end

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

-- @mark Version Tests

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

function WFCatPurgeHelperTest.rxTestDeleteFilesByPurgeList_Version_DevelopSettings( rxTest )
	
	local optArgs = {
		hasDevelopAux = true
	}
	
	testDeleteFilesByPurgeListForVersion( rxTest, 'xmp_develop', optArgs )

end

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

function WFCatPurgeHelperTest.rxTestDeleteFilesByPurgeList_Version_Thumbnail( rxTest )
	
	testDeleteFilesByPurgeListForVersion( rxTest, 'thumbnail2x' )

end

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

-- @mark Query Helper + Purge Helper Test

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

function WFCatPurgeHelperTest.rxTestQueryHelperThenPurgeHelper( rxTest )
	
	rxTest:setTimeLimit( 10 )
	
	local wfCatalog, maybeDataCache = createFakeWFCatalog( rxTest )
	
	clearOutAuxCruftFromPreviousTestRuns( wfCatalog )

	local expectedDataByDocId = {}
	
	local numberOfDocumentsToCreate = 10
	
	local optArgs = {
		hasAllAuxType = true,
		purgeListSizes = { '2560' }
	}
	
	for i = 1, numberOfDocumentsToCreate, 1 do
	
		local docId = KSIdGenerator.uuidInLowercaseHex()
		
		local assetDocValue, expectedData = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, docId, optArgs )
		
		if maybeDataCache then
			fillDataCacheForImageAsset( rxTest, maybeDataCache, expectedData )
		end
		
		expectedDataByDocId[ docId ] = expectedData
		
		rxTest:waitFor( wfCatalog:docStore():setDocValue( assetDocValue ) )

	end
	
	local function purgeCandidatesToPurgeList( candidates ) 
			
		local purgeList = {}
	
		for _, candidate in ipairs( candidates ) do
		
			local localId = candidate[ 1 ]
			
			local value = candidate[ 4 ] or {}
			
			if not next( value ) then
				value = true
			end
			
			purgeList[ localId ] = value
		
		end
		
		return purgeList
		
	end
	
	local originalPurgeList = rxTest:getFirstValue( WFCatVolumeAgentQueryHelper.getBatchOfPurgeableBinaries( wfCatalog, 'original' )
		:map( purgeCandidatesToPurgeList ) )
	
	originalPurgeList.binaryType = 'original'
	
	local proxyPurgeList = rxTest:getFirstValue( WFCatVolumeAgentQueryHelper.getBatchOfPurgeableBinaries( wfCatalog, 'proxy' )
		:map( purgeCandidatesToPurgeList ) )

	proxyPurgeList.binaryType = 'proxy'

	local xmpDevelopPurgeList = rxTest:getFirstValue( WFCatVolumeAgentQueryHelper.getBatchOfPurgeableBinaries( wfCatalog, 'xmp_develop' )
		:map( purgeCandidatesToPurgeList ) )
	
	xmpDevelopPurgeList.binaryType = 'xmp_develop'
	
	local auxPurgeList = rxTest:getFirstValue( WFCatVolumeAgentQueryHelper.getBatchOfPurgeableBinaries( wfCatalog, 'aux' )
		:map( purgeCandidatesToPurgeList ) )
	
	auxPurgeList.binaryType = 'aux'
	
	local purgeList = {
		originalPurgeList,
		proxyPurgeList,
		xmpDevelopPurgeList,
		auxPurgeList
	}

	if WFPlatformInfo.isDesktop then
	
		testDeleteFilesByPurgeList_Asset_Desktop( rxTest, optArgs, wfCatalog, nil, purgeList, expectedDataByDocId )
		
	elseif WFPlatformInfo.isiOS then
	
		testDeleteFilesByPurgeList_Asset_iOS( rxTest, optArgs, wfCatalog, purgeList, expectedDataByDocId )
		
	elseif WFPlatformInfo.isAndroid then
	
		testDeleteFilesByPurgeList_Asset_Android( rxTest, optArgs, wfCatalog, purgeList, expectedDataByDocId, maybeDataCache )
		
	end

end

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

-- SPAM [jandrew 2021-12-03]: Extensive validation of deleteAssetFilesByDocIdsForSpace
-- and deleteVersionFilesByDocIdsForSpace is done within WFCatSpacePurgeUtilsTest.

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

return WFRxTestCase.wrapSuite( 'WFCatPurgeHelperTest', WFCatPurgeHelperTest )
