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

WFCatCaptureDateTaskTest.lua

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

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

NOTICE: All information contained herein is, and remains the property of
Adobe Systems Incorporated and its suppliers, if any. The intellectual and
technical concepts contained herein are proprietary to Adobe Systems
Incorporated and its suppliers and are protected by all applicable
intellectual property laws, including trade secret and copyright laws.
Dissemination of this information or reproduction of this material is
strictly forbidden unless prior written permission is obtained from
Adobe Systems Incorporated.

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

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

	-- WF.oz_client.managed_catalog
local WFCatMockCatalog = require 'WFCatMockCatalog'
local WFCatCaptureDateTask = require 'WFCatCaptureDateTask'
local WFCatTaskManager = require 'WFCatTaskManager'
local WFCatAsset = require 'WFCatAsset'

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

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

if WFPlatformInfo.isAndroid then return {} end
	-- FIXME [jandrew 2018-03-22]: Disabling this test suite it's unreliable
	-- on Android.

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

local createFakeWFCatalog = WFCatMockCatalog.createFakeWFCatalog
local derefOpt = KSTableUtils.derefOpt
local setNested = KSTableUtils.setNested

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

local WFCatCaptureDateTaskTest = {}

local kDefaultDescription = "WFCatTask"

local kInfinity = 1/0

local kNegativeInfinity = -kInfinity

local kNaN = 0 / 0

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

local function addTestAsset( rxTest, catalog, localId, params )

	rxTest:expectSingleValue(

		catalog:docStore():bulkSetDocValue {
			{
				_id = KSIdGenerator.uuidInLowercaseHex(),
				_localId = localId,
				type = "asset",
				subtype = "image",
				_localOnly = {
					files = {
						original = {
							master = {
								path = string.format( 'local path %s', localId ),
							}
						}
					}
				},
				captureDate = params.maybeCaptureDate,
				xmp = {
					exif = {
						DateTimeOriginal = params.maybeDateTimeOriginal,
					},
					photoshop = {
						DateCreated = params.maybeDateCreated,
					},
					xmp = {
						CreateDate = params.maybeCreateDate,
					}
				},
			},
		},

		':ignore:' )
end

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

--[[!
	Test the following case :
	-- a, a valid date time string
	-- b, a valid date time string with millisecond
		-- The new date time string should contain the millisecond, without loss the precision

	-- c, a valid date time string with timezone.
		-- The new date time string should contain the timezone, without loss the timezone info

	-- d, both 'xmp.exif.DateTimeOriginal' and 'xmp.photoshop.DateCreated' are nil.
		-- no updates for those two fields.

	-- f, 'xmp.xmp.CreateDate' is nil as well.
		-- the createDate will be set to the original capture date.
--]]

function WFCatCaptureDateTaskTest.rxTestEditCaptureDate( rxTest )

	local timeOut = 10

	rxTest:setTimeLimit( timeOut )

	local fakeWFCatalog = createFakeWFCatalog( rxTest )

	addTestAsset( rxTest, fakeWFCatalog, 1, {
		maybeCaptureDate = '2017-08-15T15:22:59',
		maybeDateTimeOriginal = '2017-08-15T15:22:59',
		maybeDateCreated = '2017-08-15T15:22:59',
		maybeCreateDate = '2017-08-15T15:22:59',
	} )

	addTestAsset( rxTest, fakeWFCatalog, 2, {
		maybeCaptureDate = '2017-02-28T23:59:59.456',
		maybeDateTimeOriginal = '2017-02-28T23:59:59.456',
		maybeDateCreated = '2017-02-28T23:59:59.456',
		maybeCreateDate = '2017-02-28T23:59:59.456',
	} )

	addTestAsset( rxTest, fakeWFCatalog, 3, {
		maybeCaptureDate = '2017-12-31T23:59:59.456+05:30',
		maybeDateTimeOriginal = '2017-12-31T23:59:59.456+05:30',
		maybeDateCreated = '2017-12-31T23:59:59.456+05:30',
		maybeCreateDate = '2017-12-31T23:59:59.456+05:30',
	} )

	addTestAsset( rxTest, fakeWFCatalog, 4, {
		maybeCaptureDate = '2017-12-31T23:59:59.456+05:30',
		maybeDateTimeOriginal = nil,
		maybeDateCreated = nil,
		maybeCreateDate = '2017-12-31T23:59:59.456+05:30',
	} )

	addTestAsset( rxTest, fakeWFCatalog, 4, {
		maybeCaptureDate = '2017-12-31T23:59:59.456+05:30',
		maybeDateTimeOriginal = nil,
		maybeDateCreated = nil,
		maybeCreateDate = nil,
	} )

	local assetIds = { 1, 2, 3, 4, 5 }
	local numOfIds = #assetIds
	local timeDelta = 1
	local optUndoStateToken = nil

	local testTask = WFCatCaptureDateTask.createCaptureDateTask(
		fakeWFCatalog, assetIds, timeDelta, nil, optUndoStateToken )

	local manager = WFCatTaskManager.getCatTaskManager( fakeWFCatalog )

	manager:addToQueue( testTask )

	local taskObs = rxTest:observe( testTask:taskObservable()
		:map( function( data )
			optUndoStateToken = derefOpt( data, 'extraInfo', 'undoToken' )
			if optUndoStateToken then
				-- hack undoToken for testing check
				setNested( data, 1, 'extraInfo', 'undoToken' )
			end
			return data
		end )
	)

	taskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		percentComplete = 0,
		processedCount = 0,
		totalCount = numOfIds,
	})

	taskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		percentComplete = 1,
		processedCount = numOfIds,
		totalCount = numOfIds,
	})

	taskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		extraInfo = {
			totalCount = numOfIds,
			undoToken = 1,
		},
		percentComplete = 1,
		processedCount = numOfIds,
		totalCount = numOfIds,
	} )

	taskObs:expectCompleted()

	-- Check the result data
	rxTest:observe( WFCatAsset.collectInfoForAssetsFromDocStore( fakeWFCatalog, {
		assetIds = assetIds,
		captureDateTime = true,
		dateTimeOriginal = true,
		dateCreated = true,
		createDate = true,
	} ) )
	:expectData {
		{
			captureDateTime = "2017-08-15T15:23:00",
			createDate = "2017-08-15T15:22:59",
			dateCreated = "2017-08-15T15:23:00",
			dateTimeOriginal = "2017-08-15T15:23:00",
		},
		{
			captureDateTime = '2017-03-01T00:00:00.456',
			createDate = '2017-02-28T23:59:59.456',
			dateCreated = '2017-03-01T00:00:00.456',
			dateTimeOriginal = '2017-03-01T00:00:00.456',
		},
		{
			captureDateTime = '2018-01-01T00:00:00.456+05:30',
			createDate = '2017-12-31T23:59:59.456+05:30',
			dateCreated = '2018-01-01T00:00:00.456+05:30',
			dateTimeOriginal = '2018-01-01T00:00:00.456+05:30',
		},
		{
			captureDateTime = '2018-01-01T00:00:00.456+05:30',
			createDate = '2017-12-31T23:59:59.456+05:30',
		},
		{
			captureDateTime = '2018-01-01T00:00:00.456+05:30',
			createDate = "2017-12-31T23:59:59.456+05:30",
		},
	}
end

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

function WFCatCaptureDateTaskTest.rxTestEmptyTimeDelta_ClassicOnly_testSerially( rxTest )

	rxTest:setTimeLimit( 10 )
	
	WFCapabilities.setCapability( 'WFPlatformInfo.isClassic', 'true' )

	rxTest:finally( function()
		WFCapabilities.setCapability( 'WFPlatformInfo.isClassic', nil )
	end )

	local fakeWFCatalog = createFakeWFCatalog( rxTest )

	addTestAsset( rxTest, fakeWFCatalog, 1, {
		maybeCaptureDate = '2017-08-15T15:22:59',
		maybeDateTimeOriginal = '2017-08-15T15:22:59',
		maybeDateCreated = '2017-08-15T15:22:59',
		maybeCreateDate = '2017-08-15T15:22:59',
	} )

	addTestAsset( rxTest, fakeWFCatalog, 2, {
		maybeCaptureDate = '2017-02-28T23:59:59.456',
		maybeDateTimeOriginal = '2017-02-28T23:59:59.456',
		maybeDateCreated = '2017-02-28T23:59:59.456',
		maybeCreateDate = '2017-02-28T23:59:59.456',
	} )

	addTestAsset( rxTest, fakeWFCatalog, 3, {
		maybeCaptureDate = '2017-12-31T23:59:59.456+05:30',
		maybeDateTimeOriginal = nil,
		maybeDateCreated = nil,
		maybeCreateDate = '2017-12-31T23:59:59.456+05:30',
	} )

	addTestAsset( rxTest, fakeWFCatalog, 4, {
		maybeCaptureDate = '2017-12-31T23:59:59.456+05:30',
		maybeDateTimeOriginal = nil,
		maybeDateCreated = nil,
		maybeCreateDate = nil,
	} )

	local assetIds = { 1, 2, 3, 4 }
	local numOfIds = #assetIds
	local timeDelta = nil
	local newCaptureDate = '2018-08-15T15:22:59'
	local optUndoStateToken = nil

	local testTask = WFCatCaptureDateTask.createCaptureDateTask(
		fakeWFCatalog, assetIds, timeDelta, newCaptureDate, optUndoStateToken )

	local manager = WFCatTaskManager.getCatTaskManager( fakeWFCatalog )

	manager:addToQueue( testTask )

	local taskObs = rxTest:observe( testTask:taskObservable()
		:map( function( data )
			optUndoStateToken = derefOpt( data, 'extraInfo', 'undoToken' )
			if optUndoStateToken then
				-- hack undoToken for testing check
				setNested( data, 1, 'extraInfo', 'undoToken' )
			end
			return data
		end )
	)

	taskObs:expectDataWithinTime( 3, {
		description = kDefaultDescription,
		errorCount = 0,
		percentComplete = 0,
		processedCount = 0,
		totalCount = numOfIds,
	})

	taskObs:expectDataWithinTime( 3, {
		description = kDefaultDescription,
		errorCount = 0,
		percentComplete = 1,
		processedCount = numOfIds,
		totalCount = numOfIds,
	})

	taskObs:expectDataWithinTime( 3, {
		description = kDefaultDescription,
		errorCount = 0,
		extraInfo = {
			totalCount = numOfIds,
			undoToken = 1,
		},
		percentComplete = 1,
		processedCount = numOfIds,
		totalCount = numOfIds,
	} )

	taskObs:expectCompleted()

	-- Check the result data
	rxTest:observe( WFCatAsset.collectInfoForAssetsFromDocStore( fakeWFCatalog, {
		assetIds = assetIds,
		captureDateTime = true,
		dateTimeOriginal = true,
		dateCreated = true,
		createDate = true,
	} ) )
	:expectData {
		{
			captureDateTime = "2018-08-15T15:22:59",
			createDate = "2017-08-15T15:22:59",
			dateCreated = "2018-08-15T15:22:59",
			dateTimeOriginal = "2018-08-15T15:22:59",
		},
		{
			captureDateTime = "2018-08-15T15:22:59",
			createDate = '2017-02-28T23:59:59.456',
			dateCreated = "2018-08-15T15:22:59",
			dateTimeOriginal = "2018-08-15T15:22:59",
		},
		{
			captureDateTime = "2018-08-15T15:22:59",
			createDate = '2017-12-31T23:59:59.456+05:30',
		},
		{
			captureDateTime = "2018-08-15T15:22:59",
		},
	}

end

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

function WFCatCaptureDateTaskTest.rxTestEmptyCaptureDate( rxTest )

	local timeOut = 100

	rxTest:setTimeLimit( timeOut )

	local fakeWFCatalog = createFakeWFCatalog( rxTest )

	local localId = 1

	rxTest:expectSingleValue(

		fakeWFCatalog:docStore():bulkSetDocValue {
			{
				_id = KSIdGenerator.uuidInLowercaseHex(),
				_localId = localId,
				type = "asset",
				subtype = "image",
				_localOnly = {
					files = {
						original = {
							master = {
								path = string.format( 'local path %s', localId ),
							}
						}
					}
				},
			},
		},

		':ignore:' )

	local assetIds = { 1 }
	local numOfIds = #assetIds
	local timeDelta = 1
	local optUndoStateToken = nil

	local newDate = "2017-08-15T15:22:59.456+05:30"

	local testTask = WFCatCaptureDateTask.createCaptureDateTask(
		fakeWFCatalog, assetIds, timeDelta, newDate, optUndoStateToken )

	local manager = WFCatTaskManager.getCatTaskManager( fakeWFCatalog )

	manager:addToQueue( testTask )

	local taskObs = rxTest:observe( testTask:taskObservable()
		:map( function( data )
			optUndoStateToken = derefOpt( data, 'extraInfo', 'undoToken' )
			if optUndoStateToken then
				-- hack undoToken for testing check
				setNested( data, 1, 'extraInfo', 'undoToken' )
			end
			return data
		end )
	)

	taskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		percentComplete = 0,
		processedCount = 0,
		totalCount = numOfIds,
	})

	taskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		percentComplete = 1,
		processedCount = numOfIds,
		totalCount = numOfIds,
	})

	taskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		extraInfo = {
			totalCount = numOfIds,
			undoToken = 1,
		},
		percentComplete = 1,
		processedCount = numOfIds,
		totalCount = numOfIds,
	} )

	taskObs:expectCompleted()

	-- Check the result data
	rxTest:observe( WFCatAsset.collectInfoForAssetsFromDocStore( fakeWFCatalog, {
		assetIds = assetIds,
		captureDateTime = true,
		dateTimeOriginal = true,
		dateCreated = true,
		createDate = true,
	} ) )
	:expectData {
		{
			captureDateTime = "2017-08-15T15:22:59.456+05:30",
		},
	}

	-- 2), Add undo test case
	local undoTask = WFCatCaptureDateTask.createCaptureDateTask( fakeWFCatalog, assetIds, nil, nil, optUndoStateToken )

	manager:addToQueue( undoTask )

	local undoTaskObs = rxTest:observe( undoTask:taskObservable()
		:map( function( data )
			return data
		end )
	)

	undoTaskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		percentComplete = 0,
		processedCount = 0,
		totalCount = numOfIds,
	})

	undoTaskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		percentComplete = 1,
		processedCount = numOfIds,
		totalCount = numOfIds,
	})

	undoTaskObs:expectCompleted()

	-- 3) check the result
	rxTest:observe( WFCatAsset.collectInfoForAssetsFromDocStore( fakeWFCatalog, {
		assetIds = assetIds,
		captureDateTime = true,
		dateTimeOriginal = true,
		dateCreated = true,
		createDate = true,
	} ) )
	:expectData {
		{
			captureDateTime = "0000-00-00T00:00:00",
		},
	}

end

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

--[[!
	Test when passing an infinity time delta,

	The capture date will not be updated. And error message will be returned.
--]]

function WFCatCaptureDateTaskTest.rxTestInfinityTimeDelta( rxTest )

	local timeOut = 5

	rxTest:setTimeLimit( timeOut )

	local fakeWFCatalog = createFakeWFCatalog( rxTest )

	addTestAsset( rxTest, fakeWFCatalog, 1, {
		maybeCaptureDate = '2017-08-15T15:22:59',
		maybeDateTimeOriginal = '2017-08-15T15:22:59',
		maybeDateCreated = '2017-08-15T15:22:59',
		maybeCreateDate = '2017-08-15T15:22:59',
	} )

	local assetIds = { 1 }

	local timeDelta = kInfinity

	local optUndoStateToken = nil

	local testTask = WFCatCaptureDateTask.createCaptureDateTask(
		fakeWFCatalog, assetIds, timeDelta, nil, optUndoStateToken )

	local manager = WFCatTaskManager.getCatTaskManager( fakeWFCatalog )

	manager:addToQueue( testTask )

	local taskObs = rxTest:observe( testTask:taskObservable()
		:map( function( data )
			optUndoStateToken = derefOpt( data, 'extraInfo', 'undoToken' )
			if optUndoStateToken then
				-- hack undoToken for testing check
				setNested( data, 1, 'extraInfo', 'undoToken' )
			end
			return data
		end )
	)

	taskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		percentComplete = 0,
		processedCount = 0,
		totalCount = 1,
	})

	taskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		extraInfo = {
			errorMessage = "Invalid timeDelta",
		},
		percentComplete = 0,
		processedCount = 0,
		totalCount = 1,
	} )

	taskObs:expectCompleted()

	rxTest:observe( WFCatAsset.collectInfoForAssetsFromDocStore( fakeWFCatalog, {
		assetIds = assetIds,
		captureDateTime = true,
		dateTimeOriginal = true,
		dateCreated = true,
		createDate = true,
	} ) )
	:expectData {
		{
			captureDateTime = '2017-08-15T15:22:59',
			createDate = '2017-08-15T15:22:59',
			dateCreated = '2017-08-15T15:22:59',
			dateTimeOriginal = '2017-08-15T15:22:59',
		},
	}
end


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

--[[!
	Test when the original capture date string is malformed.

	The capture date will be updated with a well-formed date string if possible.
--]]

function WFCatCaptureDateTaskTest.rxTestMalformedCaptureDate( rxTest )

	local timeOut = 10

	rxTest:setTimeLimit( timeOut )

	local fakeWFCatalog = createFakeWFCatalog( rxTest )

	addTestAsset( rxTest, fakeWFCatalog, 1, {
		maybeCaptureDate = '1904-01-01T00:00Z',
		maybeDateTimeOriginal = '1904-01-01T00:00Z',
		maybeDateCreated = '1904-01-01T00:00Z',
		maybeCreateDate = '1904-01-01T00:00Z',
	} )

	addTestAsset( rxTest, fakeWFCatalog, 1, {
		maybeCaptureDate = '1904-01-01T00Z',
		maybeDateTimeOriginal = '1904-01-01T00Z',
		maybeDateCreated = '1904-01-01T00Z',
		maybeCreateDate = '1904-01-01T00Z',
	} )

	addTestAsset( rxTest, fakeWFCatalog, 1, {
		maybeCaptureDate = '1904-01-01',
		maybeDateTimeOriginal = '1904-01-01',
		maybeDateCreated = '1904-01-01',
		maybeCreateDate = '1904-01-01',
	} )

	local assetIds = { 1, 2, 3 }
	local numOfIds = #assetIds
	local timeDelta = 1
	local optUndoStateToken = nil

	local testTask = WFCatCaptureDateTask.createCaptureDateTask(
		fakeWFCatalog, assetIds, timeDelta, nil, optUndoStateToken )

	local manager = WFCatTaskManager.getCatTaskManager( fakeWFCatalog )

	manager:addToQueue( testTask )

	local taskObs = rxTest:observe( testTask:taskObservable()
		:map( function( data )
			optUndoStateToken = derefOpt( data, 'extraInfo', 'undoToken' )
			if optUndoStateToken then
				-- hack undoToken for testing check
				setNested( data, 1, 'extraInfo', 'undoToken' )
			end
			return data
		end )
	)

	taskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		percentComplete = 0,
		processedCount = 0,
		totalCount = numOfIds,
	})

	taskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		percentComplete = 1,
		processedCount = numOfIds,
		totalCount = numOfIds,
	})

	taskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		extraInfo = {
			totalCount = numOfIds,
			undoToken = 1,
		},
		percentComplete = 1,
		processedCount = numOfIds,
		totalCount = numOfIds,
	} )

	taskObs:expectCompleted()

	-- Check the result data
	rxTest:observe( WFCatAsset.collectInfoForAssetsFromDocStore( fakeWFCatalog, {
		assetIds = assetIds,
		captureDateTime = true,
		dateTimeOriginal = true,
		dateCreated = true,
		createDate = true,
	} ) )
	:expectData {
		{
			captureDateTime = "1904-01-01T00:00:01Z",
			createDate = "1904-01-01T00:00Z",
			dateCreated = "1904-01-01T00:00:01Z",
			dateTimeOriginal = "1904-01-01T00:00:01Z",
		},
		{
			captureDateTime = "1904-01-01T00:00:01Z",
			createDate = "1904-01-01T00Z",
			dateCreated = "1904-01-01T00:00:01Z",
			dateTimeOriginal = "1904-01-01T00:00:01Z",
		},
		{
			captureDateTime = "1904-01-01T00:00:01",
			createDate = "1904-01-01",
			dateCreated = "1904-01-01T00:00:01",
			dateTimeOriginal = "1904-01-01T00:00:01",
		},
	}
end


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

function WFCatCaptureDateTaskTest.rxTestMaybeCaptureDateIsEmpty( rxTest )

	local timeOut = 10

	rxTest:setTimeLimit( timeOut )

	local fakeWFCatalog = createFakeWFCatalog( rxTest )

	local testCaptureDate = '2017-08-15T15:22:59'
	local localId = 1

	rxTest:expectSingleValue(

		fakeWFCatalog:docStore():bulkSetDocValue {
			{
				_id = KSIdGenerator.uuidInLowercaseHex(),
				_localId = localId,
				type = "asset",
				subtype = "image",
				_localOnly = {
					files = {
						original = {
							master = {
								path = string.format( 'local path %s', localId ),
							}
						}
					}
				},
				xmp = {
					xmp = {
						CreateDate = testCaptureDate,
					}
				},
			},
		},

		':ignore:' )

	local assetIds = { 1 }
	local numOfIds = #assetIds
	local timeDelta = 1
	local optUndoStateToken = nil

	local testTask = WFCatCaptureDateTask.createCaptureDateTask(
		fakeWFCatalog, assetIds, timeDelta, nil, optUndoStateToken )

	local manager = WFCatTaskManager.getCatTaskManager( fakeWFCatalog )

	manager:addToQueue( testTask )

	local taskObs = rxTest:observe( testTask:taskObservable()
		:map( function( data )
			optUndoStateToken = derefOpt( data, 'extraInfo', 'undoToken' )
			if optUndoStateToken then
				-- hack undoToken for testing check
				setNested( data, 1, 'extraInfo', 'undoToken' )
			end
			return data
		end )
	)

	taskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		percentComplete = 0,
		processedCount = 0,
		totalCount = numOfIds,
	})

	taskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		percentComplete = 1,
		processedCount = numOfIds,
		totalCount = numOfIds,
	})

	taskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		extraInfo = {
			totalCount = numOfIds,
			undoToken = 1,
		},
		percentComplete = 1,
		processedCount = numOfIds,
		totalCount = numOfIds,
	} )

	taskObs:expectCompleted()

	-- Check the result data
	rxTest:observe( WFCatAsset.collectInfoForAssetsFromDocStore( fakeWFCatalog, {
		assetIds = assetIds,
		captureDateTime = true,
		dateTimeOriginal = true,
		dateCreated = true,
		createDate = true,
	} ) )
	:expectData {
		{
			captureDateTime = "2017-08-15T15:23:00",
			createDate = "2017-08-15T15:22:59",
		},
	}

	-- 2), Add undo test case
	local undoTask = WFCatCaptureDateTask.createCaptureDateTask( fakeWFCatalog, assetIds, nil, nil, optUndoStateToken )

	manager:addToQueue( undoTask )

	local undoTaskObs = rxTest:observe( undoTask:taskObservable()
		:map( function( data )
			return data
		end )
	)

	undoTaskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		percentComplete = 0,
		processedCount = 0,
		totalCount = numOfIds,
	})

	undoTaskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		percentComplete = 1,
		processedCount = numOfIds,
		totalCount = numOfIds,
	})

	undoTaskObs:expectCompleted()

	-- 3) check the result
	rxTest:observe( WFCatAsset.collectInfoForAssetsFromDocStore( fakeWFCatalog, {
		assetIds = assetIds,
		captureDateTime = true,
		dateTimeOriginal = true,
		dateCreated = true,
		createDate = true,
	} ) )
	:expectData {
		{
			createDate = "2017-08-15T15:22:59",
		},
	}

end



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

function WFCatCaptureDateTaskTest.rxTestMaybeXmpIsEmpty( rxTest )

	local timeOut = 10

	rxTest:setTimeLimit( timeOut )

	local fakeWFCatalog = createFakeWFCatalog( rxTest )

	local testCaptureDate = '2017-08-15T15:22:59'
	local localId = 1

	rxTest:expectSingleValue(

		fakeWFCatalog:docStore():bulkSetDocValue {
			{
				_id = KSIdGenerator.uuidInLowercaseHex(),
				_localId = localId,
				type = "asset",
				subtype = "image",
				_localOnly = {
					files = {
						original = {
							master = {
								path = string.format( 'local path %s', localId ),
							}
						}
					}
				},
				captureDate = testCaptureDate,
			},
		},

		':ignore:' )

	local assetIds = { 1 }
	local numOfIds = #assetIds
	local timeDelta = 1
	local optUndoStateToken = nil

	local testTask = WFCatCaptureDateTask.createCaptureDateTask(
		fakeWFCatalog, assetIds, timeDelta, nil, optUndoStateToken )

	local manager = WFCatTaskManager.getCatTaskManager( fakeWFCatalog )

	manager:addToQueue( testTask )

	local taskObs = rxTest:observe( testTask:taskObservable()
		:map( function( data )
			optUndoStateToken = derefOpt( data, 'extraInfo', 'undoToken' )
			if optUndoStateToken then
				-- hack undoToken for testing check
				setNested( data, 1, 'extraInfo', 'undoToken' )
			end
			return data
		end )
	)

	taskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		percentComplete = 0,
		processedCount = 0,
		totalCount = numOfIds,
	})

	taskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		percentComplete = 1,
		processedCount = numOfIds,
		totalCount = numOfIds,
	})

	taskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		extraInfo = {
			totalCount = numOfIds,
			undoToken = 1,
		},
		percentComplete = 1,
		processedCount = numOfIds,
		totalCount = numOfIds,
	} )

	taskObs:expectCompleted()

	-- Check the result data
	rxTest:observe( WFCatAsset.collectInfoForAssetsFromDocStore( fakeWFCatalog, {
		assetIds = assetIds,
		captureDateTime = true,
		dateTimeOriginal = true,
		dateCreated = true,
		createDate = true,
	} ) )
	:expectData {
		{
			captureDateTime = "2017-08-15T15:23:00",
			createDate = "2017-08-15T15:22:59",
		},
	}

	-- 2), Add undo test case
	local undoTask = WFCatCaptureDateTask.createCaptureDateTask( fakeWFCatalog, assetIds, nil, nil, optUndoStateToken )

	manager:addToQueue( undoTask )

	local undoTaskObs = rxTest:observe( undoTask:taskObservable()
		:map( function( data )
			return data
		end )
	)

	undoTaskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		percentComplete = 0,
		processedCount = 0,
		totalCount = numOfIds,
	})

	undoTaskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		percentComplete = 1,
		processedCount = numOfIds,
		totalCount = numOfIds,
	})

	undoTaskObs:expectCompleted()

	-- 3) check the result
	rxTest:observe( WFCatAsset.collectInfoForAssetsFromDocStore( fakeWFCatalog, {
		assetIds = assetIds,
		captureDateTime = true,
		dateTimeOriginal = true,
		dateCreated = true,
		createDate = true,
	} ) )
	:expectData {
		{
			captureDateTime = "2017-08-15T15:22:59",
		},
	}

end

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

--[[!
	Test when passing an NaN time delta,

	The capture date will not be updated. And error message will be returned.
--]]

function WFCatCaptureDateTaskTest.rxTestNanTimeDelta( rxTest )

	local timeOut = 5

	rxTest:setTimeLimit( timeOut )

	local fakeWFCatalog = createFakeWFCatalog( rxTest )

	addTestAsset( rxTest, fakeWFCatalog, 1, {
		maybeCaptureDate = '2017-08-15T15:22:59',
		maybeDateTimeOriginal = '2017-08-15T15:22:59',
		maybeDateCreated = '2017-08-15T15:22:59',
		maybeCreateDate = '2017-08-15T15:22:59',
	} )

	local assetIds = { 1 }

	local timeDelta = kNaN

	local optUndoStateToken = nil

	local testTask = WFCatCaptureDateTask.createCaptureDateTask(
		fakeWFCatalog, assetIds, timeDelta, nil, optUndoStateToken )

	local manager = WFCatTaskManager.getCatTaskManager( fakeWFCatalog )

	manager:addToQueue( testTask )

	local taskObs = rxTest:observe( testTask:taskObservable()
		:map( function( data )
			return data
		end )
	)

	taskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		percentComplete = 0,
		processedCount = 0,
		totalCount = 1,
	})

	taskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		extraInfo = {
			errorMessage = "Invalid timeDelta",
		},
		percentComplete = 0,
		processedCount = 0,
		totalCount = 1,
	} )

	taskObs:expectCompleted()

	-- The capture date will not change due to the invalid time delta
	rxTest:observe( WFCatAsset.collectInfoForAssetsFromDocStore( fakeWFCatalog, {
		assetIds = assetIds,
		captureDateTime = true,
		dateTimeOriginal = true,
		dateCreated = true,
		createDate = true,
	} ) )
	:expectData {
		{
			captureDateTime = '2017-08-15T15:22:59',
			createDate = '2017-08-15T15:22:59',
			dateCreated = '2017-08-15T15:22:59',
			dateTimeOriginal = '2017-08-15T15:22:59',
		},
	}
end

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

--[[!
	Test when passing an negative infinity time delta,

	The capture date will not be updated. And error message will be returned.
--]]

function WFCatCaptureDateTaskTest.rxTestNegativeInfinityTimeDelta( rxTest )

	local timeOut = 5

	rxTest:setTimeLimit( timeOut )

	local fakeWFCatalog = createFakeWFCatalog( rxTest )

	addTestAsset( rxTest, fakeWFCatalog, 1, {
		maybeCaptureDate = '2017-08-15T15:22:59',
		maybeDateTimeOriginal = '2017-08-15T15:22:59',
		maybeDateCreated = '2017-08-15T15:22:59',
		maybeCreateDate = '2017-08-15T15:22:59',
	} )

	local assetIds = { 1 }

	local timeDelta = kNegativeInfinity

	local optUndoStateToken = nil

	local testTask = WFCatCaptureDateTask.createCaptureDateTask(
		fakeWFCatalog, assetIds, timeDelta, nil, optUndoStateToken )

	local manager = WFCatTaskManager.getCatTaskManager( fakeWFCatalog )

	manager:addToQueue( testTask )

	local taskObs = rxTest:observe( testTask:taskObservable()
		:map( function( data )
			return data
		end )
	)

	taskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		percentComplete = 0,
		processedCount = 0,
		totalCount = 1,
	})

	taskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		extraInfo = {
			errorMessage = "Invalid timeDelta",
		},
		percentComplete = 0,
		processedCount = 0,
		totalCount = 1,
	} )

	taskObs:expectCompleted()

	-- The capture date will not change due to the invalid time delta
	rxTest:observe( WFCatAsset.collectInfoForAssetsFromDocStore( fakeWFCatalog, {
		assetIds = assetIds,
		captureDateTime = true,
		dateTimeOriginal = true,
		dateCreated = true,
		createDate = true,
	} ) )
	:expectData {
		{
			captureDateTime = '2017-08-15T15:22:59',
			createDate = '2017-08-15T15:22:59',
			dateCreated = '2017-08-15T15:22:59',
			dateTimeOriginal = '2017-08-15T15:22:59',
		},
	}
end


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

function WFCatCaptureDateTaskTest.rxTestUndoEditCaptureDate( rxTest )

	local timeOut = 10

	rxTest:setTimeLimit( timeOut )

	local fakeWFCatalog = createFakeWFCatalog( rxTest )

	addTestAsset( rxTest, fakeWFCatalog, 1, {
		maybeCaptureDate = '2017-08-15T15:22:59',
		maybeDateTimeOriginal = '2016-08-15T15:22:59',
		maybeDateCreated = '2016-08-15T15:22:59',
		maybeCreateDate = '2016-08-15T15:22:59',
	} )


	-- 1) Edit capture date
	local assetIds = { 1 }
	local numOfIds = #assetIds

	local timeDelta = 1

	local optUndoStateToken = nil

	local testTask = WFCatCaptureDateTask.createCaptureDateTask(
		fakeWFCatalog, assetIds, timeDelta, nil, optUndoStateToken )

	local manager = WFCatTaskManager.getCatTaskManager( fakeWFCatalog )

	manager:addToQueue( testTask )

	local taskObs = rxTest:observe( testTask:taskObservable()
		:map( function( data )
			optUndoStateToken = derefOpt( data, 'extraInfo', 'undoToken' )
			if optUndoStateToken then
				-- hack undoToken for testing check
				setNested( data, 1, 'extraInfo', 'undoToken' )
			end
			return data
		end )
	)

	taskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		percentComplete = 0,
		processedCount = 0,
		totalCount = 1,
	})

	taskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		percentComplete = 1,
		processedCount = 1,
		totalCount = 1,
	})

	taskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		extraInfo = {
			totalCount = 1,
			undoToken = 1,
		},
		percentComplete = 1,
		processedCount = 1,
		totalCount = 1,
	} )

	taskObs:expectCompleted()

	rxTest:observe( WFCatAsset.collectInfoForAssetsFromDocStore( fakeWFCatalog, {
		assetIds = assetIds,
		captureDateTime = true,
		dateTimeOriginal = true,
		dateCreated = true,
		createDate = true,
	} ) )
	:expectData {
		{
			captureDateTime = '2017-08-15T15:23:00',
			createDate = '2016-08-15T15:22:59',
			dateCreated = '2017-08-15T15:23:00',
			dateTimeOriginal = '2017-08-15T15:23:00',
		},
	}

	-- 2) Undo edit

	local undoTask = WFCatCaptureDateTask.createCaptureDateTask( fakeWFCatalog, assetIds, nil, nil, optUndoStateToken )

	manager:addToQueue( undoTask )

	local undoTaskObs = rxTest:observe( undoTask:taskObservable()
		:map( function( data )
			return data
		end )
	)

	undoTaskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		percentComplete = 0,
		processedCount = 0,
		totalCount = numOfIds,
	})

	undoTaskObs:expectDataWithinTime( timeOut, {
		description = kDefaultDescription,
		errorCount = 0,
		percentComplete = 1,
		processedCount = numOfIds,
		totalCount = numOfIds,
	})

	undoTaskObs:expectCompleted()

	-- 3) check the result
	rxTest:observe( WFCatAsset.collectInfoForAssetsFromDocStore( fakeWFCatalog, {
		assetIds = assetIds,
		captureDateTime = true,
		dateTimeOriginal = true,
		dateCreated = true,
		createDate = true,
	} ) )
	:expectData {
		{
			captureDateTime = '2017-08-15T15:22:59',
			createDate = '2016-08-15T15:22:59',
			dateCreated = '2016-08-15T15:22:59',
			dateTimeOriginal = '2016-08-15T15:22:59',
		},
	}
end

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

return WFRxTestCase.wrapSuite( 'WFCatCaptureDateTaskTest', WFCatCaptureDateTaskTest )
