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

WFCatPurgeOnDeleteTest.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2022 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 KSTableUtils = require 'KSTableUtils'
local KSData = require 'KSData'
local WFPlatformInfo = require 'WFPlatformInfo'

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

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

local LrmCatalogTestHelper

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

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

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

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

local WFCatPurgeOnDeleteTest = {}

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

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 deleteDocs( rxTest, wfCatalog, optArgs, docIds )

	if optArgs.localNewId then

		local overlays = {}
		
		for _, docId in ipairs( docIds ) do
		
			local overlay = {
				_id = docId,
				_deleted = true,
				_newId = KSIdGenerator.uuidInLowercaseHex()
			} 
		
			overlays[ #overlays + 1 ] = overlay
		
		end
	
		rxTest:waitFor( wfCatalog:docStore():bulkApplyOverlay( overlays ) )
		
	else
	
		rxTest:waitFor( WFCatDelete.deleteDocs( wfCatalog:docStore(), docIds ) )
		
	end

end

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

-- @mark Asset Test Helper Functions

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

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

	-- The aux annotations should remain after purge on delete operations.
	-- They are reference counted and cleaned up by a separate task.

	local isVideo = optArgs.docSubtype == 'video'

	for assetId, expectedData in pairs( expectedDataByAssetId ) do
	
		local simplifyDeletedDocs = false
	
		rxTest:waitFor( wfCatalog:docStore():docValue( assetId, nil, nil, simplifyDeletedDocs )
		
			:map( function( assetDocValue )
					
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'aux', expectedData.mask1Fingerprint, 'relativePath' ),
						not isVideo )
						
				rxTest:expectEqual(
						doesFieldExist(
								assetDocValue, '_localOnly', 'files', 'aux', expectedData.mask2Fingerprint, 'relativePath' ),
						not isVideo )

				return true

			end ) )
	
	end

end

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

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

	rxTest:makeVerbose()

	local isVideo = optArgs.docSubtype == 'video'
	
	local hasMasks = not not optArgs.hasMasks

	-- 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( 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 ) )
		
	end

	verifyAuxAnnotation( rxTest, wfCatalog, expectedDataByAssetId, optArgs )

	-- Setup Purge On Delete

	local docIds = KSTableUtils.extractKeys( expectedDataByAssetId )

	local purgeOnDeleteStream = WFCatPurgeOnDelete.setupPurgeOnDelete( wfCatalog )
	
	local observer = rxTest:observe( purgeOnDeleteStream )
	
	-- Delete the Documents
	
	deleteDocs( rxTest, wfCatalog, optArgs, docIds )
	
	-- Wait for confirmation from the Purge-On-Delete stream
	
	for _, docId in ipairs( docIds ) do
		observer:expectDataWithinTime( 2, { docId } )
	end
	
	-- Verify files were removed
	
	local shouldExist = not not optArgs.newId
		-- We should not remove files from trash/restore assets with a newId.
		
	verifyAuxAnnotation( rxTest, wfCatalog, expectedDataByAssetId, optArgs )
		
	for assetId, expectedData in pairs( expectedDataByAssetId ) do
	
		rxTest:expectEqual( shouldExist, doesFileExist( expectedData.originalFilePath ) )
		rxTest:expectEqual( shouldExist and isVideo, doesFileExist( expectedData.proxy1080pFilePath ) )
		rxTest:expectEqual( shouldExist and isVideo, doesFileExist( expectedData.proxy720pFilePath ) )
		rxTest:expectEqual( shouldExist and isVideo, doesFileExist( expectedData.proxy360pFilePath ) )
		rxTest:expectEqual( shouldExist, doesFileExist( expectedData.xmpSidecarFilePath ) )
		rxTest:expectEqual( shouldExist, doesFileExist( expectedData.proxyFilePath ) )
		
		-- Masks and Develop Settings should still exist, since they can be shared
		-- between documents.
		
		rxTest:expectEqual( not isVideo, doesFileExist( expectedData.xmpDevelopSettingsFilePath ) )
		rxTest:expectEqual( hasMasks, doesFileExist( expectedData.mask1FilePath ) )
		rxTest:expectEqual( hasMasks, doesFileExist( expectedData.mask2FilePath ) )
		
	end

end

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

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

	-- Verify Files Exist on the File System

	local isVideo = optArgs.docSubtype == 'video'

	local hasMasks = not not optArgs.hasMasks

	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 ) )
	
	end
	
	verifyAuxAnnotation( rxTest, wfCatalog, expectedDataByAssetId, optArgs )
	
	-- Setup Purge On Delete

	local docIds = KSTableUtils.extractKeys( expectedDataByAssetId )

	local purgeOnDeleteStream = WFCatPurgeOnDelete.setupPurgeOnDelete( wfCatalog )
	
	local observer = rxTest:observe( purgeOnDeleteStream )
	
	-- Delete the Documents
	
	deleteDocs( rxTest, wfCatalog, optArgs, docIds )
	
	-- Wait for confirmation from the Purge-On-Delete stream
	
	for _, docId in ipairs( docIds ) do
		observer:expectDataWithinTime( 2, { docId } )
	end
	
	-- Verify files were removed
	
	local shouldExist = not not ( optArgs.newId or optArgs.localNewId )
		-- We should not remove files from trash/restore assets with a newId.
	
	verifyAuxAnnotation( rxTest, wfCatalog, expectedDataByAssetId, optArgs )
	
	for assetId, expectedData in pairs( expectedDataByAssetId ) do

		rxTest:expectEqual( shouldExist, doesFileExist( expectedData.originalFilePath ) )
		rxTest:expectEqual( shouldExist, doesFileExist( expectedData.latestOriginalFilePath ) )
		rxTest:expectEqual( shouldExist, doesFileExist( expectedData.previewFilePath ) )
		rxTest:expectEqual( shouldExist, doesFileExist( expectedData.thumbnailFilePath ) )
		rxTest:expectEqual( shouldExist, doesFileExist( expectedData.fullsizeFilePath ) )
		rxTest:expectEqual( shouldExist and isVideo, doesFileExist( expectedData.proxy1080pFilePath ) )
		rxTest:expectEqual( shouldExist and isVideo, doesFileExist( expectedData.proxy360pFilePath ) )
		rxTest:expectEqual( shouldExist, doesFileExist( expectedData.proxyFilePath ) )
		
		-- The develop settings should not be deleted when there's a local new Id,
		-- otherwise, it should. This matches the behavior of the existing purge agent,
		-- but it seems a little odd to me.
		
		rxTest:expectEqual( not not optArgs.localNewId, doesFileExist( expectedData.xmpDevelopSettingsFilePath ) )
		
		-- Masks are shared between asset documents, so they should not be removed.
		
		rxTest:expectEqual( hasMasks, doesFileExist( expectedData.mask1FilePath ) )
		rxTest:expectEqual( hasMasks, doesFileExist( expectedData.mask2FilePath ) )

	end

end

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

local function testPurgeOnDelete_Asset_Android(
		rxTest, optArgs, wfCatalog, expectedDataByAssetId, dataCache )

	-- Verify All Files Exist
	
	local isVideo = optArgs.docSubtype == 'video'
	
	local hasMasks = not not optArgs.hasMasks
	
	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 ) )
	
	end
	
	verifyAuxAnnotation( rxTest, wfCatalog, expectedDataByAssetId, optArgs )
	
	-- Setup Purge On Delete

	local docIds = KSTableUtils.extractKeys( expectedDataByAssetId )

	local purgeOnDeleteStream = WFCatPurgeOnDelete.setupPurgeOnDelete( wfCatalog, nil, dataCache )
	
	local observer = rxTest:observe( purgeOnDeleteStream )
	
	-- Delete the Documents
	
	deleteDocs( rxTest, wfCatalog, optArgs, docIds )
	
	-- Wait for confirmation from the Purge-On-Delete stream
	
	for _, docId in ipairs( docIds ) do
		observer:expectDataWithinTime( 2, { docId } )
	end
	
	-- Verify files were removed
	
	local shouldExist = not not ( optArgs.newId or optArgs.localNewId )
		-- We should not remove files from trash/restore assets with a newId.
	
	verifyAuxAnnotation( rxTest, wfCatalog, expectedDataByAssetId, optArgs )
	
	for assetId, expectedData in pairs( expectedDataByAssetId ) do
	
		rxTest:expectEqual( shouldExist, doesFileExist( expectedData.originalFilePath ) )
		rxTest:expectEqual( shouldExist, doesFileExist( expectedData.latestOriginalFilePath ) )
		rxTest:expectSingleValue( dataCache:get( expectedData.previewMd5 ):map( toBool ), shouldExist )
		rxTest:expectSingleValue( dataCache:get( expectedData.thumbMd5 ):map( toBool ), shouldExist )
		rxTest:expectSingleValue( dataCache:get( expectedData.fullsizeMd5 ):map( toBool ), shouldExist )
		rxTest:expectEqual( shouldExist and isVideo, doesFileExist( expectedData.proxy1080pFilePath ) )
		rxTest:expectEqual( shouldExist and isVideo, doesFileExist( expectedData.proxy360pFilePath ) )
		rxTest:expectEqual( shouldExist, doesFileExist( expectedData.proxyFilePath ) )
		rxTest:expectEqual( shouldExist, doesFileExist( expectedData.xmpDevelopSettingsFilePath ) )
		
		-- Masks are shared between asset documents, so they should not be removed.
		
		rxTest:expectEqual( hasMasks, doesFileExist( expectedData.mask1FilePath ) )
		rxTest:expectEqual( hasMasks, doesFileExist( expectedData.mask2FilePath ) )

	end

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 testPurgeOnDelete( rxTest, optArgs )

	rxTest:setTimeLimit( 10 )
	
	optArgs = optArgs or {}
	
	local wfCatalog, maybeDataCache = createFakeWFCatalog( rxTest )
	
	local expectedDataByAssetId = {}
	
	local numberOfDocumentsToCreate = 5

	local newIds = {}

	for i = 1, numberOfDocumentsToCreate, 1 do
	
		local assetId = KSIdGenerator.uuidInLowercaseHex()
		
		local assetDocValue, expectedData = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, assetId, optArgs )
		
		if optArgs.newId then
			local newId = KSIdGenerator.uuidInLowercaseHex()
			assetDocValue._serverProvidedMetadata.new_id = newId
			newIds[ #newIds + 1 ] = newId
		end
		
		if maybeDataCache then
			fillDataCacheForImageAsset( rxTest, maybeDataCache, expectedData )
		end
		
		rxTest:waitFor( wfCatalog:docStore():setDocValue( assetDocValue ) )
		
		expectedDataByAssetId[ assetId ] = expectedData
		
	end
	
	if WFPlatformInfo.isDesktop then
	
		testPurgeOnDelete_Asset_Desktop( rxTest, optArgs, wfCatalog, expectedDataByAssetId )
		
	elseif WFPlatformInfo.isiOS then
	
		testPurgeOnDelete_Asset_iOS( rxTest, optArgs, wfCatalog, expectedDataByAssetId )
		
	elseif WFPlatformInfo.isAndroid then
	
		testPurgeOnDelete_Asset_Android( rxTest, optArgs, wfCatalog, expectedDataByAssetId, maybeDataCache )
		
	end

	return wfCatalog, newIds

end

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

-- @mark Asset Tests

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

function WFCatPurgeOnDeleteTest.rxTestPurgeOnDelete_Image( rxTest )
	
	local optArgs = {
		hasMasks = true
	}
	
	testPurgeOnDelete( rxTest, optArgs )

end

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

function WFCatPurgeOnDeleteTest.rxTestPurgeOnDelete_Video( rxTest )
	
	local optArgs = {
		docSubtype = 'video',
		hasLocal360p = true,
		hasLocal720p = true,
		hasLocal1080p = true
	}
	
	testPurgeOnDelete( rxTest, optArgs )

end

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

function WFCatPurgeOnDeleteTest.rxTestPurgeOnDelete_NewIdFromOz( rxTest )
	
	local optArgs = {
		newId = true,
		hasMasks = true
	}
	
	local wfCatalog, newIds = testPurgeOnDelete( rxTest, optArgs )
	
	if WFPlatformInfo.isMobile() then
	
		-- Make sure the new document has local only annotations. The checks
		-- here are not extensive, as the bulk of the work is done by WFCatCopies, which
		-- is extensively tested elsewhere.
	
		for _, newId in ipairs( newIds ) do

			rxTest:expectSingleValue( wfCatalog:docStore():docValue( newId ) 
				:map( function( assetDocValue )

					rxTest:expectEqual(
							true,
							doesUniversalFieldExist(
									assetDocValue, 'files', 'original', 'master', 'relativePath' ) )

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

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

				end ) )
				
		end
	
	end

end

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

function WFCatPurgeOnDeleteTest.rxTestPurgeOnDelete_LocalNewId( rxTest )
	
	local optArgs = {
		hasMasks = true,
		localNewId = true
	}
	
	testPurgeOnDelete( rxTest, optArgs )

end

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

-- @mark Version Test Helper Functions

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

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

	for assetId, expectedData in pairs( expectedDataByAssetId ) do
	
		rxTest:expectEqual( true, doesFileExist( expectedData.xmpDevelopSettingsFilePath ) )
		rxTest:expectEqual( true, doesFileExist( expectedData.mask1FilePath ) )
		rxTest:expectEqual( true, doesFileExist( expectedData.mask2FilePath ) )

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

				return true
				
			end ) )

	end

	-- Setup Purge On Delete

	local docIds = KSTableUtils.extractKeys( expectedDataByAssetId )

	local purgeOnDeleteStream = WFCatPurgeOnDelete.setupPurgeOnDelete( wfCatalog )
	
	local observer = rxTest:observe( purgeOnDeleteStream )
	
	-- Delete the Documents
	
	rxTest:waitFor( WFCatDelete.deleteDocs( wfCatalog:docStore(), docIds ) )
	
	for _, docId in ipairs( docIds ) do
		observer:expectDataWithinTime( 3, { docId } )
	end
	
	-- Verify nothing was removed.
	
	for assetId, expectedData in pairs( expectedDataByAssetId ) do
	
		-- Masks And Develop Settings should still exist, since they can be shared
		-- between documents.
	
		rxTest:expectEqual( true, doesFileExist( expectedData.mask1FilePath ) )
		rxTest:expectEqual( true, doesFileExist( expectedData.mask2FilePath ) )
		rxTest:expectEqual( true, doesFileExist( expectedData.xmpDevelopSettingsFilePath ) )

	end

end

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

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

	-- Verify All Files Exist
	
	for _, expectedData in pairs( expectedDataByAssetId ) do
	
		rxTest:expectEqual( true, doesFileExist( expectedData.thumbnailFilePath ) )
		rxTest:expectEqual( true, doesFileExist( expectedData.xmpDevelopSettingsFilePath ) )
		rxTest:expectEqual( true, doesFileExist( expectedData.mask1FilePath ) )
		rxTest:expectEqual( true, doesFileExist( expectedData.mask2FilePath ) )
		
	end
	
	-- Setup Purge On Delete

	local docIds = KSTableUtils.extractKeys( expectedDataByAssetId )

	local purgeOnDeleteStream = WFCatPurgeOnDelete.setupPurgeOnDelete( wfCatalog )
	
	local observer = rxTest:observe( purgeOnDeleteStream )
	
	-- Delete the Documents
	
	rxTest:waitFor( WFCatDelete.deleteDocs( wfCatalog:docStore(), docIds ) )
	
	for _, docId in ipairs( docIds ) do
		observer:expectDataWithinTime( 3, { docId } )
	end
	
	-- Verify files were removed
	
	for assetId, expectedData in pairs( expectedDataByAssetId ) do

		rxTest:expectEqual( false, doesFileExist( expectedData.xmpDevelopSettingsFilePath ) )
		rxTest:expectEqual( false, doesFileExist( expectedData.thumbnailFilePath ) )

		-- Masks should still exist, since they can be shared between documents.

		rxTest:expectEqual( true, doesFileExist( expectedData.mask1FilePath ) )
		rxTest:expectEqual( true, doesFileExist( expectedData.mask2FilePath ) )

	end

end

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

local function testPurgeOnDelete_Version_Android( rxTest, optArgs, wfCatalog, expectedDataByAssetId, dataCache )

	-- Verify All Files Exist
	
	for _, expectedData in pairs( expectedDataByAssetId ) do
	
		rxTest:expectEqual( true, doesFileExist( expectedData.xmpDevelopSettingsFilePath ) )
		rxTest:expectEqual( true, doesFileExist( expectedData.mask1FilePath ) )
		rxTest:expectEqual( true, doesFileExist( expectedData.mask2FilePath ) )
		
		rxTest:expectSingleValue( dataCache:get( expectedData.thumbMd5 ):map( toBool ), true )
	
	end
	
	-- Setup Purge On Delete

	local docIds = KSTableUtils.extractKeys( expectedDataByAssetId )

	local purgeOnDeleteStream = WFCatPurgeOnDelete.setupPurgeOnDelete( wfCatalog, nil, dataCache )
	
	local observer = rxTest:observe( purgeOnDeleteStream )
	
	-- Delete the Documents
	
	rxTest:waitFor( WFCatDelete.deleteDocs( wfCatalog:docStore(), docIds ) )
	
	for _, docId in ipairs( docIds ) do
		observer:expectDataWithinTime( 3, { docId } )
	end
	
	-- Verify files were removed
	
	for assetId, expectedData in pairs( expectedDataByAssetId ) do
	
		rxTest:expectEqual( false, doesFileExist( expectedData.xmpDevelopSettingsFilePath ) )
		rxTest:expectSingleValue( dataCache:get( expectedData.thumbMd5 ):map( toBool ), false )
	
		-- Masks should still exist, since they can be shared between documents.
		
		rxTest:expectEqual( true, doesFileExist( expectedData.mask1FilePath ) )
		rxTest:expectEqual( true, doesFileExist( expectedData.mask2FilePath ) )
	
	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 testPurgeOnDeleteForVersion( rxTest, optArgs )

	rxTest:setTimeLimit( 10 )
	
	optArgs = optArgs or {}
	
	local wfCatalog, maybeDataCache = createFakeWFCatalog( rxTest )
	
	local expectedDataByDocId = {}
	
	local numberOfDocumentsToCreate = 3
	
	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
	
	end
	
	if WFPlatformInfo.isDesktop then
	
		testPurgeOnDelete_Version_Desktop( rxTest, optArgs, wfCatalog, expectedDataByDocId )
		
	elseif WFPlatformInfo.isiOS then
	
		testPurgeOnDelete_Version_iOS( rxTest, optArgs, wfCatalog, expectedDataByDocId )
		
	elseif WFPlatformInfo.isAndroid then
	
		testPurgeOnDelete_Version_Android( rxTest, optArgs, wfCatalog, expectedDataByDocId, maybeDataCache )
		
	end

end

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

-- @mark Version Tests

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

function WFCatPurgeOnDeleteTest.rxTestPurgeOnDelete_Version( rxTest )
	
	local optArgs = {
		hasMasks = true
	}
	
	testPurgeOnDeleteForVersion( rxTest, optArgs )

end

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

return WFRxTestCase.wrapSuite( 'WFCatPurgeOnDeleteTest', WFCatPurgeOnDeleteTest )
