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

WFRxIndexStoreSchemaTest.lua

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

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

NOTICE: All information contained herein is, and remain 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 may be covered by U.S. and Foreign
Patents, patents in process, and are protected by trade secret or copyright
law.  Dissemination of this information or reproduction of this material is
strictly forbidden unless prior written permission is obtained from
Adobe Systems Incorporated.

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

	-- WF.core.crypto
local WFCrypto = require 'WFCrypto'

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

	-- WF.sqlite.database
local WFSQLiteDatabase = require 'WFSQLiteDatabase'

	-- WF.sqlite.index_store
local WFRxIndexStoreSchema = require 'WFRxIndexStoreSchema'

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

local md5 = assert( WFCrypto.MD5, "Cannot find MD5 digest" )

local coreInfoHash = md5.digest [[CREATE TABLE coreInfo( docId, aspectRatio, displayDate )]]

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

local WFRxIndexStoreSchemaTest = {}

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

local function mapForExampleSchema( docValue, emit )

	-- WARNING: This version is grossly simplified and omits error checking.
	-- See OzCatalogIndexDefinitions.lua for a better example.

	if docValue._docType == 'asset' then
		emit( docValue.width / docValue.height,
			  docValue.captureDate:sub( 1, 10 ) )
	end

end

local exampleFunction_md5 = WFRxIndexStoreSchema.mapFunctionHashForUnitTest( mapForExampleSchema )

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

local function exampleSchemaFromApiDocs()

	-- Why not start by testing the exact schema declaration described in
	-- the API docs? :-)

	local indexStoreSchema = WFRxIndexStoreSchema()

	indexStoreSchema:addTable {
		sql = "CREATE TABLE coreInfo( aspectRatio, displayDate )",
		map = mapForExampleSchema,
		relevantTypeSubtypeTuples = { { '*', '*' } },
	}

	indexStoreSchema:addIndex
		"CREATE INDEX coreInfo_displayDate ON coreInfo( displayDate )"

	return indexStoreSchema

end

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

local function exampleSchemaWithDocId( hasOneRowPerDocument, useLocalId )

	-- Why not start by testing the exact schema declaration described in
	-- the API docs? :-)

	local indexStoreSchema = WFRxIndexStoreSchema()

	indexStoreSchema:addTable {
		sql = "CREATE TABLE coreInfo( aspectRatio, displayDate )",
		map = mapForExampleSchema,
		hasOneRowPerDocument = hasOneRowPerDocument,
		useLocalId = useLocalId,
		relevantTypeSubtypeTuples = { { '*', '*' } },
	}

	return indexStoreSchema 

end

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

function WFRxIndexStoreSchemaTest.rxTestTableNames_simple( rxTest )

	local indexStoreSchema = exampleSchemaFromApiDocs()

	rxTest:expectEqual(
		{ coreInfo = true },
		indexStoreSchema:tableNames() )

end

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

function WFRxIndexStoreSchemaTest.rxTestIndices_simple( rxTest )

	local indexStoreSchema = exampleSchemaFromApiDocs()

	rxTest:expectEqual(
		{
			coreInfo = {
				coreInfo_displayDate = "CREATE INDEX coreInfo_displayDate ON coreInfo( displayDate )",
				coreInfo_docId = "CREATE INDEX coreInfo_docId ON coreInfo( docId )"
			},
		},
		indexStoreSchema:indexInfos() )

end

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

function WFRxIndexStoreSchemaTest.rxTestDocIdAutomaticIndexes( rxTest )
	-- docId should be automatically added as an index if the docId
	-- is not already a primary key on the table
	local indexStoreSchema  = exampleSchemaWithDocId()

	local db 
	
	rxTest:finally( function()
		if db then
			db:close()
		end
	end )
	
	db = indexStoreSchema:openOrCreateDatabaseAtPath( ':memory:' )
	
	rxTest:expectEqual(

		{
			{
				"CREATE TABLE coreInfo( docId, aspectRatio, displayDate )",
			},
			{
				"CREATE INDEX coreInfo_docId ON coreInfo( docId )",
			},
			{
				"CREATE TABLE indexStatus(\n\t\t\t\t\tindexTableName UNIQUE,\n\t\t\t\t\tneedsUpdateFrom,\n\t\t\t\t\tsqlSchemaHash,\n\t\t\t\t\tmapFunctionHash)",
			},
			{
				"CREATE TABLE localState( name UNIQUE NOT NULL, value )",
			},
			{
				"CREATE TABLE schemaVersion( currentVersion, backwardCompatibleToVersion )",
			},
			{
			},
			{
			},
		},


		db:gatherArrayOfArray [[SELECT sql FROM sqlite_master ORDER BY name, type]] )
	
	db:close()
	
	-- docId should not be added as an index if the docId is a primary key
	-- is unique	
	indexStoreSchema = exampleSchemaWithDocId( true, true )
	
	db = indexStoreSchema:openOrCreateDatabaseAtPath( ':memory:' )
	
	rxTest:expectEqual( {
			{
				"CREATE TABLE coreInfo( docId INTEGER PRIMARY KEY, aspectRatio, displayDate )",
			},
			{
				"CREATE TABLE indexStatus(\n\t\t\t\t\tindexTableName UNIQUE,\n\t\t\t\t\tneedsUpdateFrom,\n\t\t\t\t\tsqlSchemaHash,\n\t\t\t\t\tmapFunctionHash)",
			},
			{
				"CREATE TABLE localState( name UNIQUE NOT NULL, value )",
			},
			{
				"CREATE TABLE schemaVersion( currentVersion, backwardCompatibleToVersion )",
			},
			{
			},
			{
			},
		},
		db:gatherArrayOfArray [[SELECT sql FROM sqlite_master ORDER BY name, type]] )
	
	db:close()
	
	indexStoreSchema = exampleSchemaWithDocId( true, false )
	
	db = indexStoreSchema:openOrCreateDatabaseAtPath( ':memory:' )
	
	rxTest:expectEqual( {
			{
				"CREATE TABLE coreInfo( docId UNIQUE, aspectRatio, displayDate )",
			},
			{
				"CREATE TABLE indexStatus(\n\t\t\t\t\tindexTableName UNIQUE,\n\t\t\t\t\tneedsUpdateFrom,\n\t\t\t\t\tsqlSchemaHash,\n\t\t\t\t\tmapFunctionHash)",
			},
			{
				"CREATE TABLE localState( name UNIQUE NOT NULL, value )",
			},
			{
				"CREATE TABLE schemaVersion( currentVersion, backwardCompatibleToVersion )",
			},
			{
			},
			{
			},
			{
			},
		},
		db:gatherArrayOfArray [[SELECT sql FROM sqlite_master ORDER BY name, type]] )
	
	db:close()
	
end

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

function WFRxIndexStoreSchemaTest.rxTestTableNames_isACopy( rxTest )

	-- Verify that the table we get back from :tableNames is a tear-off
	-- copy of the underlying data.

	local indexStoreSchema = exampleSchemaFromApiDocs()

	local tableNamesCopy1 = indexStoreSchema:tableNames()

	tableNamesCopy1.coreInfo = nil

	local tableNamesCopy2 = indexStoreSchema:tableNames()

	rxTest:expectEqual(
		{ coreInfo = true },
		tableNamesCopy2 )

end

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

function WFRxIndexStoreSchemaTest.rxTestTableNames_threeTables( rxTest )

	local indexStoreSchema = WFRxIndexStoreSchema()

	indexStoreSchema:addTable {
		sql = "CREATE TABLE coreInfo( aspectRatio, displayDate )",
		map = mapForExampleSchema,
		relevantTypeSubtypeTuples = { { '*', '*' } },
	}

	indexStoreSchema:addTable {
		sql = "CREATE TABLE anotherTable( foo, bar )",
		map = mapForExampleSchema,
		relevantTypeSubtypeTuples = { { '*', '*' } },
	}

	indexStoreSchema:addTable {
		sql = "CREATE TABLE blah( boop, bap )",
		map = mapForExampleSchema,
		relevantTypeSubtypeTuples = { { '*', '*' } },
	}

	rxTest:expectEqual(

		{
			anotherTable = true,
			blah = true,
			coreInfo = true,
		},

		indexStoreSchema:tableNames() )

end

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

function WFRxIndexStoreSchemaTest.rxTestOpenOrCreateDatabaseAtPath( rxTest )

	-- Why not start by testing the exact schema declaration described in
	-- the API docs? :-)

	local indexStoreSchema = exampleSchemaFromApiDocs()

	-- Instead of spinning up an index store based on this, we'll apply it
	-- directly to an in-memory database and verify the result schema.

	local db = indexStoreSchema:openOrCreateDatabaseAtPath( ':memory:' )

	rxTest:expectEqual( true, WFSQLiteDatabase:isClassOf( db ) )

	-- Examine the schema.

	rxTest:expectEqual(

		{
			{
				"CREATE TABLE coreInfo( docId, aspectRatio, displayDate )",
			},
			{
				"CREATE INDEX coreInfo_displayDate ON coreInfo( displayDate )",
			},
			{
				"CREATE INDEX coreInfo_docId ON coreInfo( docId )",
			},
			{
				"CREATE TABLE indexStatus(\n\t\t\t\t\tindexTableName UNIQUE,\n\t\t\t\t\tneedsUpdateFrom,\n\t\t\t\t\tsqlSchemaHash,\n\t\t\t\t\tmapFunctionHash)",
					-- Ugh, but white space has to match.
			},
			{
				"CREATE TABLE localState( name UNIQUE NOT NULL, value )",
			},
			{
				"CREATE TABLE schemaVersion( currentVersion, backwardCompatibleToVersion )",
			},
			{
			},
			{
			},
		},

		db:gatherArrayOfArray [[SELECT sql FROM sqlite_master ORDER BY name, type]] )

end

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

function WFRxIndexStoreSchemaTest.rxTestOpenOrCreateDatabaseAtPath_validateArgs( rxTest )

	rxTest:expectError( function()

		local indexStoreSchema = WFRxIndexStoreSchema()

		return indexStoreSchema:openOrCreateDatabaseAtPath()
			-- No path. Should fail.

	end )

end

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

function WFRxIndexStoreSchemaTest.rxTestAddTable_validateArgs_table( rxTest )

	rxTest:expectError( function()

		local indexStoreSchema = WFRxIndexStoreSchema()

		indexStoreSchema:addTable()
			-- No args table. Should fail.

	end )

end

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

function WFRxIndexStoreSchemaTest.rxTestAddTable_validateArgs_sqlString( rxTest )

	rxTest:expectError( function()

		local indexStoreSchema = WFRxIndexStoreSchema()

		indexStoreSchema:addTable {
			sql = 42,
				-- FAIL: Should be a string.
			map = function() end,
			relevantTypeSubtypeTuples = { { '*', '*' } },
		}

	end )

end

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

function WFRxIndexStoreSchemaTest.rxTestAddTable_validateArgs_sqlCreateTable( rxTest )

	rxTest:expectError( function()

		local indexStoreSchema = WFRxIndexStoreSchema()

		indexStoreSchema:addTable {
			sql = "CREATE BOGUS TABLE foo( bar, blah )",
				-- FAIL: Should be CREATE TABLE!
			map = function() end,
			relevantTypeSubtypeTuples = { { '*', '*' } },
		}

	end )

end

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

function WFRxIndexStoreSchemaTest.rxTestAddTable_validateArgs_sqlCreateTableHasName( rxTest )

	rxTest:expectError( function()

		local indexStoreSchema = WFRxIndexStoreSchema()

		indexStoreSchema:addTable {
			sql = "CREATE TABLE foo WITH COLUMNS bar, blah",
				-- FAIL: Should be proper CREATE TABLE syntax!
			map = function() end,
			relevantTypeSubtypeTuples = { { '*', '*' } },
		}

	end )

end

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

function WFRxIndexStoreSchemaTest.rxTestAddTable_validateArgs_mapFunction( rxTest )

	rxTest:expectError( function()

		local indexStoreSchema = WFRxIndexStoreSchema()

		indexStoreSchema:addTable {
			sql = "CREATE TABLE coreInfo( aspectRatio, displayDate )",
			map = "This is not a function.",
				-- FAIL: Should be a function
			relevantTypeSubtypeTuples = { { '*', '*' } },
		}

	end )

end

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

function WFRxIndexStoreSchemaTest.rxTestAddTable_validateArgs_createTableTwice( rxTest )

	local indexStoreSchema = WFRxIndexStoreSchema()

	indexStoreSchema:addTable {

		sql = "CREATE TABLE coreInfo( aspectRatio, displayDate )",

		relevantTypeSubtypeTuples = { { '*', '*' } },

		map = function( docValue, emit )

			-- WARNING: This version is grossly simplified and omits error checking.
			-- See OzCatalogIndexDefinitions.lua for a better example.

			if docValue._docType == 'asset' then
				emit( docValue.width / docValue.height,
					  docValue.captureDate:sub( 1, 10 ) )
			end

		end,

	}

	rxTest:expectError( function()

		indexStoreSchema:addTable {

			sql = "CREATE TABLE coreInfo( aspectRatio, displayDate )",

			relevantTypeSubtypeTuples = { { '*', '*' } },

			map = function( docValue, emit )

				-- WARNING: This version is grossly simplified and omits error checking.
				-- See OzCatalogIndexDefinitions.lua for a better example.

				if docValue._docType == 'asset' then
					emit( docValue.width / docValue.height,
						  docValue.captureDate:sub( 1, 10 ) )
				end

			end,

		}

	end )

end

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

function WFRxIndexStoreSchemaTest.rxTestAddTable_validateArgs_createTableTwice( rxTest )

	local indexStoreSchema = WFRxIndexStoreSchema()

	indexStoreSchema:addTable {

		sql = "CREATE TABLE coreInfo( aspectRatio, displayDate )",

		relevantTypeSubtypeTuples = { { '*', '*' } },

		map = function( docValue, emit )

			-- WARNING: This version is grossly simplified and omits error checking.
			-- See OzCatalogIndexDefinitions.lua for a better example.

			if docValue._docType == 'asset' then
				emit( docValue.width / docValue.height,
					  docValue.captureDate:sub( 1, 10 ) )
			end

		end,

	}

	rxTest:expectError( function()

		indexStoreSchema:addTable {

			sql = "CREATE TABLE coreInfo( aspectRatio, displayDate )",

			relevantTypeSubtypeTuples = { { '*', '*' } },

			map = function( docValue, emit )

				-- WARNING: This version is grossly simplified and omits error checking.
				-- See OzCatalogIndexDefinitions.lua for a better example.

				if docValue._docType == 'asset' then
					emit( docValue.width / docValue.height,
						  docValue.captureDate:sub( 1, 10 ) )
				end

			end,

		}

	end )

end

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

function WFRxIndexStoreSchemaTest.rxTestAddTable_validateArgs_reservedName1( rxTest )

	local indexStoreSchema = WFRxIndexStoreSchema()

	rxTest:expectError( function()

		indexStoreSchema:addTable {
			sql = "CREATE TABLE indexstatus( aspectRatio, displayDate )",
			map = mapForExampleSchema,
			relevantTypeSubtypeTuples = { { '*', '*' } },
		}

	end )

end

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

function WFRxIndexStoreSchemaTest.rxTestAddTable_validateArgs_reservedName2( rxTest )

	local indexStoreSchema = WFRxIndexStoreSchema()

	rxTest:expectError( function()

		indexStoreSchema:addTable {
			sql = "CREATE TABLE LocalState( aspectRatio, displayDate )",
			map = mapForExampleSchema,
			relevantTypeSubtypeTuples = { { '*', '*' } },
		}

	end )

end

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

function WFRxIndexStoreSchemaTest.rxTestAddTable_validateArgs_reservedName3( rxTest )

	local indexStoreSchema = WFRxIndexStoreSchema()

	rxTest:expectError( function()

		indexStoreSchema:addTable {
			sql = "CREATE TABLE wfIndexStore_foo( aspectRatio, displayDate )",
			map = mapForExampleSchema,
			relevantTypeSubtypeTuples = { { '*', '*' } },
		}

	end )

end

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

function WFRxIndexStoreSchemaTest.rxTestAddTable_validateArgs_reservedName4( rxTest )

	local indexStoreSchema = WFRxIndexStoreSchema()

	rxTest:expectError( function()

		indexStoreSchema:addTable {
			sql = "CREATE TABLE wfRxIndexStore_foo( aspectRatio, displayDate )",
			map = mapForExampleSchema,
			relevantTypeSubtypeTuples = { { '*', '*' } },
		}

	end )

end

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

function WFRxIndexStoreSchemaTest.rxTestAddTable_validateArgs_relevantTypeSubtypeTuples_Required( rxTest )

	local indexStoreSchema = WFRxIndexStoreSchema()

	-- relevantTypeSubtypeTuples is required!
	
	rxTest:expectError( function()
	
		indexStoreSchema:addTable {

			sql = "CREATE TABLE images( aspectRatio, displayDate )",	

			map = function( docValue, emit )

				if docValue._docType == 'asset' then
					emit( docValue.width / docValue.height,
						  docValue.captureDate:sub( 1, 10 ) )
				end

			end,

		}
		
	end )

end

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

function WFRxIndexStoreSchemaTest.rxTestAddTable_validateArgs_relevantTypeSubtypeTuples( rxTest )

	local indexStoreSchema = WFRxIndexStoreSchema()

	-- Single Types
	
	indexStoreSchema:addTable {

		sql = "CREATE TABLE images( aspectRatio, displayDate )",	

		map = function( docValue, emit )

			if docValue._docType == 'asset' then
				emit( docValue.width / docValue.height,
					  docValue.captureDate:sub( 1, 10 ) )
			end

		end,

		relevantTypeSubtypeTuples = { { 'asset', 'image', } }

	}
	
	-- Multiple Types/Subtypes
	
	indexStoreSchema:addTable {

		sql = "CREATE TABLE imagesAndAlbums( aspectRatio, displayDate )",

		map = function( docValue, emit )

			if docValue._docType == 'asset' or docValue._docType == 'album' then
				emit( docValue.width / docValue.height,
					  docValue.captureDate:sub( 1, 10 ) )
			end

		end,

		relevantTypeSubtypeTuples = { { 'asset', 'image' }, { 'album', 'collection' } }

	}
	
	-- Same Types, Two Subtypes
	
	indexStoreSchema:addTable {

		sql = "CREATE TABLE assets( aspectRatio, displayDate )",

		map = function( docValue, emit )

			if docValue._docType == 'asset' then
				emit( docValue.width / docValue.height,
					  docValue.captureDate:sub( 1, 10 ) )
			end

		end,

		relevantTypeSubtypeTuples = { { 'asset', 'image' }, { 'asset', 'video' } }

	}

end

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

function WFRxIndexStoreSchemaTest.rxTestAddTable_validateArgs_relevantTypeSubtypeTuples_incorrectType( rxTest )

	local indexStoreSchema = WFRxIndexStoreSchema()

	rxTest:expectError( function()
	
		indexStoreSchema:addTable {

			sql = "CREATE TABLE coreInfo( aspectRatio, displayDate )",

			map = function( docValue, emit )

				if docValue._docType == 'asset' then
					emit( docValue.width / docValue.height,
						  docValue.captureDate:sub( 1, 10 ) )
				end

			end,

			relevantTypeSubtypeTuples = 3

		}

	end )

end

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

function WFRxIndexStoreSchemaTest.rxTestAddTable_validateArgs_relevantTypeSubtypeTuples_invalidFormat( rxTest )

	local indexStoreSchema = WFRxIndexStoreSchema()

	rxTest:expectError( function()
	
		indexStoreSchema:addTable {

			sql = "CREATE TABLE coreInfo( aspectRatio, displayDate )",

			map = function( docValue, emit )

				if docValue._docType == 'asset' then
					emit( docValue.width / docValue.height,
						  docValue.captureDate:sub( 1, 10 ) )
				end

			end,

			relevantTypeSubtypeTuples = { { 'asset', 'image', 'thisShouldNotbeHere' } }

		}

	end )

end

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

function WFRxIndexStoreSchemaTest.rxTestAddTable_validateArgs_relevantTypeSubtypeTuples_invalidTypeEntry( rxTest )
	
	local indexStoreSchema = WFRxIndexStoreSchema()

	rxTest:expectError( function()
	
		indexStoreSchema:addTable {

			sql = "CREATE TABLE coreInfo( aspectRatio, displayDate )",

			map = function( docValue, emit )

				if docValue._docType == 'asset' then
					emit( docValue.width / docValue.height,
						  docValue.captureDate:sub( 1, 10 ) )
				end

			end,

			relevantTypeSubtypeTuples = { 'invalidType', 'image', }

		}

	end )

end

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

function WFRxIndexStoreSchemaTest.rxTestAddTable_validateArgs_relevantTypeSubtypeTuples_NullSubtypeValidation( rxTest )

	local indexStoreSchema = WFRxIndexStoreSchema()

	indexStoreSchema:addTable {

		sql = "CREATE TABLE albumAssets( aspectRatio, displayDate )",

		map = function( docValue, emit )

			if docValue._docType == 'album_asset' then
				emit( docValue.width / docValue.height,
					  docValue.captureDate:sub( 1, 10 ) )
			end

		end,

		relevantTypeSubtypeTuples = { { 'album_asset', 'NULL', } }

	}

	rxTest:expectError( function()
	
		indexStoreSchema:addTable {

			sql = "CREATE TABLE coreInfo( aspectRatio, displayDate )",

			map = function( docValue, emit )

				if docValue._docType == 'asset' then
					emit( docValue.width / docValue.height,
						  docValue.captureDate:sub( 1, 10 ) )
				end

			end,

			relevantTypeSubtypeTuples = { { 'asset', 'NULL', } }

		}

	end )

end

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

function WFRxIndexStoreSchemaTest.rxTestAddTable_validateArgs_relevantTypeSubtypeTuples_invalidTypesEntry( rxTest )

	local indexStoreSchema = WFRxIndexStoreSchema()

	indexStoreSchema:addTable {

		sql = "CREATE TABLE assets( aspectRatio, displayDate )",

		map = function( docValue, emit )

			if docValue._docType == 'asset' then
				emit( docValue.width / docValue.height,
					  docValue.captureDate:sub( 1, 10 ) )
			end

		end,

		relevantTypeSubtypeTuples = { { 'asset', '*', } }

	}

	rxTest:expectError( function()
	
		indexStoreSchema:addTable {

			sql = "CREATE TABLE albumAssets( aspectRatio, displayDate )",

			map = function( docValue, emit )

				if docValue._docType == 'album_asset' then
					emit( docValue.width / docValue.height,
						  docValue.captureDate:sub( 1, 10 ) )
				end

			end,

			relevantTypeSubtypeTuples = { { 'album_asset', '*', } }

		}

	end )

end

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

function WFRxIndexStoreSchemaTest.rxTestAddTable_validateArgs_relevantTypeSubtypeTuples_invalidSubtypeEntry( rxTest )

	local indexStoreSchema = WFRxIndexStoreSchema()

	rxTest:expectError( function()
	
		indexStoreSchema:addTable {

			sql = "CREATE TABLE coreInfo( aspectRatio, displayDate )",

			map = function( docValue, emit )

				if docValue._docType == 'asset' then
					emit( docValue.width / docValue.height,
						  docValue.captureDate:sub( 1, 10 ) )
				end

			end,

			relevantTypeSubtypeTuples = { { 'asset', 'foobar', } }

		}

	end )

end

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

function WFRxIndexStoreSchemaTest.rxTestResetTablesIfNecessary_validateArgs_db( rxTest )

	local indexStoreSchema = exampleSchemaFromApiDocs()

	rxTest:expectError( function()

		indexStoreSchema:resetTablesIfNecessary()
			-- First arg should be a WFSQLiteDatabase instance.

	end )

end

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

function WFRxIndexStoreSchemaTest.rxTestResetTablesIfNecessary_validateArgs_forceRefresh( rxTest )

	local indexStoreSchema = exampleSchemaFromApiDocs()

	rxTest:expectError( function()

		local db = indexStoreSchema:openOrCreateDatabaseAtPath( ':memory:' )

		indexStoreSchema:resetTablesIfNecessary( db, 42 )
			-- Second arg should be nil or boolean.

	end )

end

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

function WFRxIndexStoreSchemaTest.rxTestResetTablesIfNecessary_emptyDatabase( rxTest )

	local indexStoreSchema = exampleSchemaFromApiDocs()

	local db = indexStoreSchema:openOrCreateDatabaseAtPath( ':memory:' )

	indexStoreSchema:resetTablesIfNecessary( db )

	-- Examine the schema.

	rxTest:expectEqual(

		{
			{
				"CREATE TABLE coreInfo( docId, aspectRatio, displayDate )",
			},
			{
				"CREATE INDEX coreInfo_displayDate ON coreInfo( displayDate )",
			},
			{
				"CREATE INDEX coreInfo_docId ON coreInfo( docId )",
			},
			{
				"CREATE TABLE indexStatus(\n\t\t\t\t\tindexTableName UNIQUE,\n\t\t\t\t\tneedsUpdateFrom,\n\t\t\t\t\tsqlSchemaHash,\n\t\t\t\t\tmapFunctionHash)",
					-- Ugh, but white space has to match.
			},
			{
				"CREATE TABLE localState( name UNIQUE NOT NULL, value )",
			},
			{
				"CREATE TABLE schemaVersion( currentVersion, backwardCompatibleToVersion )",
			},
			{
			},
			{
			},
		},

		db:gatherArrayOfArray
			[[SELECT sql FROM sqlite_master ORDER BY name, type]] )

	-- Examine the indexStatus table.

	rxTest:expectEqual(

		{
			{
				"coreInfo",
				1,
				coreInfoHash,
				exampleFunction_md5,
			},
		},

		db:gatherArrayOfArray
			[[SELECT * FROM indexStatus ORDER BY indexTableName]] )

end

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

function WFRxIndexStoreSchemaTest.rxTestResetTablesIfNecessary_existingDatabase_unchanged( rxTest )

	local indexStoreSchema = exampleSchemaFromApiDocs()

	local db = indexStoreSchema:openOrCreateDatabaseAtPath( ':memory:' )

	-- Fake some existing rows in the index status.

	local needsUpdateFrom = 4711
	
	db:execOnce( [[INSERT INTO indexStatus VALUES( 'coreInfo', ?, ?, ? )]],
				needsUpdateFrom,
				coreInfoHash,
				exampleFunction_md5 )

	-- Fake existing content in tables.

	db:execOnce
		[[INSERT INTO coreInfo VALUES( 'docId', 1.5, '2009-08-11' )]]

	-- Reset the schema.

	indexStoreSchema:resetTablesIfNecessary( db )

	-- Examine the schema.

	rxTest:expectEqual(

		{
			{
				"CREATE TABLE coreInfo( docId, aspectRatio, displayDate )",
			},
			{
				"CREATE INDEX coreInfo_displayDate ON coreInfo( displayDate )",
			},
			{
				"CREATE INDEX coreInfo_docId ON coreInfo( docId )",
			},
			{
				"CREATE TABLE indexStatus(\n\t\t\t\t\tindexTableName UNIQUE,\n\t\t\t\t\tneedsUpdateFrom,\n\t\t\t\t\tsqlSchemaHash,\n\t\t\t\t\tmapFunctionHash)",
					-- Ugh, but white space has to match.
			},
			{
				"CREATE TABLE localState( name UNIQUE NOT NULL, value )",
			},
			{
				"CREATE TABLE schemaVersion( currentVersion, backwardCompatibleToVersion )",
			},
			{
			},
			{
			},
		},

		db:gatherArrayOfArray
			[[SELECT sql FROM sqlite_master ORDER BY name, type]] )

	-- Examine the indexStatus table.

	rxTest:expectEqual(

		{
			{
				"coreInfo",
				needsUpdateFrom,
				coreInfoHash,
				exampleFunction_md5,
			},
		},

		db:gatherArrayOfArray
			[[SELECT * FROM indexStatus ORDER BY indexTableName]] )

	-- Make sure the index table has not been cleared.

	rxTest:expectEqual(
		{ { 1 } },
		db:gatherArrayOfArray [[SELECT count() FROM coreInfo]] )

end

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

function WFRxIndexStoreSchemaTest.rxTestResetTablesIfNecessary_existingDatabase_sqlChanged( rxTest )

	local indexStoreSchema = exampleSchemaFromApiDocs()

	local db = indexStoreSchema:openOrCreateDatabaseAtPath( ':memory:' )

	-- Fake some existing rows in the index status.

	local needsUpdateFrom = 4711

	db:execOnce( [[INSERT INTO indexStatus VALUES( 'coreInfo', ?, 'bogus_sql_hash', ? )]],
				needsUpdateFrom,
				exampleFunction_md5 )

	-- Fake existing content in tables.

	db:execOnce
		[[INSERT INTO coreInfo VALUES( 'docId', 1.5, '2009-08-11' )]]

	-- Reset the schema.

	indexStoreSchema:resetTablesIfNecessary( db )

	-- Examine the schema.

	rxTest:expectEqual(

		{
			{
				"CREATE TABLE coreInfo( docId, aspectRatio, displayDate )",
			},
			{
				"CREATE INDEX coreInfo_displayDate ON coreInfo( displayDate )",
			},
			{
				"CREATE INDEX coreInfo_docId ON coreInfo( docId )",
			},
			{
				"CREATE TABLE indexStatus(\n\t\t\t\t\tindexTableName UNIQUE,\n\t\t\t\t\tneedsUpdateFrom,\n\t\t\t\t\tsqlSchemaHash,\n\t\t\t\t\tmapFunctionHash)",
					-- Ugh, but white space has to match.
			},
			{
				"CREATE TABLE localState( name UNIQUE NOT NULL, value )",
			},
			{
				"CREATE TABLE schemaVersion( currentVersion, backwardCompatibleToVersion )",
			},
			{
			},
			{
			},
		},

		db:gatherArrayOfArray
			[[SELECT sql FROM sqlite_master ORDER BY name, type]] )

	-- Examine the indexStatus table.

	rxTest:expectEqual(

		{
			{
				"coreInfo",
				1,
				coreInfoHash,
				exampleFunction_md5,
			},
		},

		db:gatherArrayOfArray
			[[SELECT * FROM indexStatus ORDER BY indexTableName]] )

	-- Make sure the index table has been cleared.

	rxTest:expectEqual(
		{ { 0 } },
		db:gatherArrayOfArray [[SELECT count() FROM coreInfo]] )

end

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

function WFRxIndexStoreSchemaTest.rxTestResetTablesIfNecessary_existingDatabase_mapFnChanged( rxTest )

	local indexStoreSchema = exampleSchemaFromApiDocs()

	local db = indexStoreSchema:openOrCreateDatabaseAtPath( ':memory:' )

	-- Fake some existing rows in the index status.

	local needsUpdateFrom = 4711

	db:execOnce(
		[[INSERT INTO indexStatus VALUES( 'coreInfo', ?, ?, 'bogus_map_changed' )]],
		needsUpdateFrom,
		coreInfoHash )


	-- Fake existing content in tables.

	db:execOnce
		[[INSERT INTO coreInfo VALUES( 'docId', 1.5, '2009-08-11' )]]

	-- Reset the schema.

	indexStoreSchema:resetTablesIfNecessary( db )

	-- Examine the schema.

	rxTest:expectEqual(

		{
			{
				"CREATE TABLE coreInfo( docId, aspectRatio, displayDate )",
			},
			{
				"CREATE INDEX coreInfo_displayDate ON coreInfo( displayDate )",
			},
			{
				"CREATE INDEX coreInfo_docId ON coreInfo( docId )",
			},
			{
				"CREATE TABLE indexStatus(\n\t\t\t\t\tindexTableName UNIQUE,\n\t\t\t\t\tneedsUpdateFrom,\n\t\t\t\t\tsqlSchemaHash,\n\t\t\t\t\tmapFunctionHash)",
					-- Ugh, but white space has to match.
			},
			{
				"CREATE TABLE localState( name UNIQUE NOT NULL, value )",
			},
			{
				"CREATE TABLE schemaVersion( currentVersion, backwardCompatibleToVersion )",
			},
			{
			},
			{
			},
		},

		db:gatherArrayOfArray [[SELECT sql FROM sqlite_master ORDER BY name, type]] )

	-- Examine the indexStatus table.

	rxTest:expectEqual(

		{
			{
				"coreInfo",
				1,
				coreInfoHash,
				exampleFunction_md5,
			},
		},

		db:gatherArrayOfArray [[SELECT * FROM indexStatus ORDER BY indexTableName]] )

	-- Make sure the index table has been cleared.

	rxTest:expectEqual(
		{ { 0 } },
		db:gatherArrayOfArray [[SELECT count() FROM coreInfo]] )

end

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

function WFRxIndexStoreSchemaTest.rxTestResetTablesIfNecessary_existingDatabase_forceRefresh( rxTest )

	local indexStoreSchema = exampleSchemaFromApiDocs()

	local db = indexStoreSchema:openOrCreateDatabaseAtPath( ':memory:' )

	-- Fake some existing rows in the index status.

	local needsUpdateFrom = 4711

	db:execOnce( [[INSERT INTO indexStatus VALUES( 'coreInfo', ?, ?, ? )]],
				 needsUpdateFrom, coreInfoHash, exampleFunction_md5 )

	-- Fake existing content in tables.

	db:execOnce
		[[INSERT INTO coreInfo VALUES( 'docId', 1.5, '2009-08-11' )]]

	-- Reset the schema.

	indexStoreSchema:resetTablesIfNecessary( db, true )

	-- Examine the schema.

	rxTest:expectEqual(

		{
			{
				"CREATE TABLE coreInfo( docId, aspectRatio, displayDate )",
			},
			{
				"CREATE INDEX coreInfo_displayDate ON coreInfo( displayDate )",
			},
			{
				"CREATE INDEX coreInfo_docId ON coreInfo( docId )",
			},
			{
				"CREATE TABLE indexStatus(\n\t\t\t\t\tindexTableName UNIQUE,\n\t\t\t\t\tneedsUpdateFrom,\n\t\t\t\t\tsqlSchemaHash,\n\t\t\t\t\tmapFunctionHash)",
					-- Ugh, but white space has to match.
			},
			{
				"CREATE TABLE localState( name UNIQUE NOT NULL, value )",
			},
			{
				"CREATE TABLE schemaVersion( currentVersion, backwardCompatibleToVersion )",
			},
			{
			},
			{
			},
		},

		db:gatherArrayOfArray
			[[SELECT sql FROM sqlite_master ORDER BY name, type]] )

	-- Examine the indexStatus table.

	rxTest:expectEqual(

		{
			{
				"coreInfo",
				1,
				coreInfoHash,
				exampleFunction_md5,
			},
		},

		db:gatherArrayOfArray
			[[SELECT * FROM indexStatus ORDER BY indexTableName]] )

	-- Make sure the index table has been cleared.

	rxTest:expectEqual(
		{ { 0 } },
		db:gatherArrayOfArray [[SELECT count() FROM coreInfo]] )

end

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

function WFRxIndexStoreSchemaTest.rxTestMapFunctions( rxTest )

	local indexStoreSchema = exampleSchemaFromApiDocs()

	rxTest:expectEqual(
		{ coreInfo = mapForExampleSchema },
		indexStoreSchema:mapFunctions() )

end

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

function WFRxIndexStoreSchemaTest.rxTestNColumnsPerTable( rxTest )

	local indexStoreSchema = WFRxIndexStoreSchema()

	indexStoreSchema:addTable {
		sql = "CREATE TABLE coreInfo( aspectRatio, displayDate )",
		map = mapForExampleSchema,
		relevantTypeSubtypeTuples = { { '*', '*' } },
	}

	indexStoreSchema:addTable {
		sql = "CREATE TABLE blah( foo )",
		map = mapForExampleSchema,
		relevantTypeSubtypeTuples = { { '*', '*' } },
	}

	rxTest:expectEqual(

		{ coreInfo = 2, blah = 1 },
		indexStoreSchema:nColumnsPerTable() )
		
	rxTest:expectEqual( { TEMP_search = 2 }, indexStoreSchema:nColumnsPerManualTable() )

end

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

function WFRxIndexStoreSchemaTest.rxTestManualTableNames( rxTest )

	local indexStoreSchema = WFRxIndexStoreSchema()
	
	rxTest:expectEqual(
		{ TEMP_search = true }, 
		indexStoreSchema:manualTableNames()
	)
	
end

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

function WFRxIndexStoreSchemaTest.rxTestVerifyManualTables( rxTest )

	local indexStoreSchema = WFRxIndexStoreSchema()
	local db = indexStoreSchema:openOrCreateDatabaseAtPath( ':memory:' )
	
	rxTest:expectEqual( {},
		db:gatherArrayOfArray
			[[SELECT * FROM TEMP_search]] )
			
end

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

function WFRxIndexStoreSchemaTest.rxTestIncludeAndExcludeSpaceIdDocs( rxTest )

	local indexStoreSchema = WFRxIndexStoreSchema()

	-- Default should be includeDocumentsFromSource = all.
	
	indexStoreSchema:addTable {
		sql = "CREATE TABLE coreInfo( aspectRatio, displayDate )",
		map = mapForExampleSchema,
		relevantTypeSubtypeTuples = { { '*', '*' } },
		
	}

	indexStoreSchema:addTable {
		sql = "CREATE TABLE blah( foo )",
		map = mapForExampleSchema,
		relevantTypeSubtypeTuples = { { '*', '*' } },
	}

	rxTest:expectEqual(

		{ TEMP_search = true, coreInfo = true, blah = true },
		indexStoreSchema:tablesThatShouldIncludeDocumentsWithoutSpaceIds() )

	rxTest:expectEqual(

		{ TEMP_search = true, coreInfo = true, blah = true },
		indexStoreSchema:tablesThatShouldIncludeDocumentsWithSpaceIds() )
		

	local indexStoreSchema2 = WFRxIndexStoreSchema()

	-- Test includeDocumentsFromSource = catalog.
	
	indexStoreSchema2:addTable {
		sql = "CREATE TABLE coreInfo( aspectRatio, displayDate )",
		map = mapForExampleSchema,
		includeDocumentsFromSource = WFRxIndexStoreSchema.sourceCatalogDocuments,
		relevantTypeSubtypeTuples = { { '*', '*' } },
	}

	indexStoreSchema2:addTable {
		sql = "CREATE TABLE blah( foo )",
		map = mapForExampleSchema,
		includeDocumentsFromSource = WFRxIndexStoreSchema.sourceCatalogDocuments,
		relevantTypeSubtypeTuples = { { '*', '*' } },
	}

	rxTest:expectEqual(

		{ TEMP_search = true, coreInfo = true, blah = true },
		indexStoreSchema2:tablesThatShouldIncludeDocumentsWithoutSpaceIds() )

	rxTest:expectEqual(

		{ TEMP_search = true, coreInfo = false, blah = false },
		indexStoreSchema2:tablesThatShouldIncludeDocumentsWithSpaceIds() )

	local indexStoreSchema3 = WFRxIndexStoreSchema()

	-- Test includeDocumentsFromSource = all.
	
	indexStoreSchema3:addTable {
		sql = "CREATE TABLE coreInfo( aspectRatio, displayDate )",
		map = mapForExampleSchema,
		includeDocumentsFromSource = WFRxIndexStoreSchema.sourceAllDocuments,
		relevantTypeSubtypeTuples = { { '*', '*' } },
	}

	indexStoreSchema3:addTable {
		sql = "CREATE TABLE blah( foo )",
		map = mapForExampleSchema,
		includeDocumentsFromSource = WFRxIndexStoreSchema.sourceAllDocuments,
		relevantTypeSubtypeTuples = { { '*', '*' } },
	}

	rxTest:expectEqual(

		{ TEMP_search = true, coreInfo = true, blah = true },
		indexStoreSchema3:tablesThatShouldIncludeDocumentsWithoutSpaceIds() )

	rxTest:expectEqual(

		{ TEMP_search = true, coreInfo = true, blah = true },
		indexStoreSchema3:tablesThatShouldIncludeDocumentsWithSpaceIds() )

	local indexStoreSchema4 = WFRxIndexStoreSchema()

	-- Test includeDocumentsFromSource = space feed.
	
	indexStoreSchema4:addTable {
		sql = "CREATE TABLE coreInfo( aspectRatio, displayDate )",
		map = mapForExampleSchema,
		includeDocumentsFromSource = WFRxIndexStoreSchema.sourceSpaceFeedDocuments,
		relevantTypeSubtypeTuples = { { '*', '*' } },
	}

	indexStoreSchema4:addTable {
		sql = "CREATE TABLE blah( foo )",
		map = mapForExampleSchema,
		includeDocumentsFromSource = WFRxIndexStoreSchema.sourceSpaceFeedDocuments,
		relevantTypeSubtypeTuples = { { '*', '*' } },
	}

	rxTest:expectEqual(

		{ TEMP_search = true, coreInfo = false, blah = false },
		indexStoreSchema4:tablesThatShouldIncludeDocumentsWithoutSpaceIds() )

	rxTest:expectEqual(

		{ TEMP_search = true, coreInfo = true, blah = true },
		indexStoreSchema4:tablesThatShouldIncludeDocumentsWithSpaceIds() )

	local indexStoreSchema5 = WFRxIndexStoreSchema()

	-- Test includeDocumentsFromSource = "invalid"
	-- Should end up using default of catalog
	
	indexStoreSchema5:addTable {
		sql = "CREATE TABLE coreInfo( aspectRatio, displayDate )",
		map = mapForExampleSchema,
		includeDocumentsFromSource = "foo",
		relevantTypeSubtypeTuples = { { '*', '*' } },
	}

	indexStoreSchema5:addTable {
		sql = "CREATE TABLE blah( foo )",
		map = mapForExampleSchema,
		includeDocumentsFromSource = "foo",
		relevantTypeSubtypeTuples = { { '*', '*' } },
	}

	rxTest:expectEqual(

		{ TEMP_search = true, coreInfo = true, blah = true },
		indexStoreSchema5:tablesThatShouldIncludeDocumentsWithoutSpaceIds() )

	rxTest:expectEqual(

		{ TEMP_search = true, coreInfo = false, blah = false },
		indexStoreSchema5:tablesThatShouldIncludeDocumentsWithSpaceIds() )

end


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

function WFRxIndexStoreSchemaTest.rxTestResetTablesBySchemaVersionList_validateArgs_db( rxTest )

	local indexStoreSchema = exampleSchemaFromApiDocs()

	rxTest:expectError( function()

		indexStoreSchema:resetTablesBySchemaVersionList()
			-- First arg should be a WFSQLiteDatabase instance.

	end )

	rxTest:expectError( function()

		local db = indexStoreSchema:openOrCreateDatabaseAtPath( ':memory:' )

		indexStoreSchema:resetTablesBySchemaVersionList( db )
			-- Second arg should be a list of tables to reindex.

	end )

	rxTest:expectError( function()

		local db = indexStoreSchema:openOrCreateDatabaseAtPath( ':memory:' )

		indexStoreSchema:resetTablesBySchemaVersionList( db, true )
			-- Second arg should be a list of tables to reindex.

	end )

end

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

function WFRxIndexStoreSchemaTest.rxTestResetTablesBySchemaVersionList_noTablesToReindex( rxTest )

	local indexStoreSchema = exampleSchemaFromApiDocs()

	local db = indexStoreSchema:openOrCreateDatabaseAtPath( ':memory:' )

	-- Fake some existing rows in the index status.

	local needsUpdateFrom = 4711

	db:execOnce( [[INSERT INTO indexStatus VALUES( 'coreInfo', ?, ?, ? )]],
				needsUpdateFrom,
				coreInfoHash,
				exampleFunction_md5 )

	indexStoreSchema:resetTablesBySchemaVersionList( db, {} )

	-- Examine the schema.
	rxTest:expectEqual(
		{
			{
				"CREATE TABLE coreInfo( docId, aspectRatio, displayDate )",
			},
			{
				"CREATE INDEX coreInfo_displayDate ON coreInfo( displayDate )",
			},
			{
				"CREATE INDEX coreInfo_docId ON coreInfo( docId )",
			},
			{
				"CREATE TABLE indexStatus(\n\t\t\t\t\tindexTableName UNIQUE,\n\t\t\t\t\tneedsUpdateFrom,\n\t\t\t\t\tsqlSchemaHash,\n\t\t\t\t\tmapFunctionHash)",
					-- Ugh, but white space has to match.
			},
			{
				"CREATE TABLE localState( name UNIQUE NOT NULL, value )",
			},
			{
				"CREATE TABLE schemaVersion( currentVersion, backwardCompatibleToVersion )",
			},
			{
			},
			{
			},
		},
		db:gatherArrayOfArray
			[[SELECT sql FROM sqlite_master ORDER BY name, type]] )

	-- Examine the indexStatus table.
	rxTest:expectEqual(
		{
			{
				"coreInfo",
				4711,
				coreInfoHash,
				exampleFunction_md5,
			},
		},
		db:gatherArrayOfArray
			[[SELECT * FROM indexStatus ORDER BY indexTableName]] )

	rxTest:expectEqual( {}, indexStoreSchema:tablesResetAtInitialization() )

end

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

function WFRxIndexStoreSchemaTest.rxTestResetTablesBySchemaVersionList_noTablesToReindex_tableSchemaChange( rxTest )

	-- Verifies that when a table's SQL schema changes, we force a reindex of that table even
	-- if it does not appear in the schema version list.

	local indexStoreSchema = exampleSchemaFromApiDocs()

	local db = indexStoreSchema:openOrCreateDatabaseAtPath( ':memory:' )

	-- Fake some existing rows in the index status.

	local needsUpdateFrom = 4711

	db:execOnce( [[INSERT INTO indexStatus VALUES( 'coreInfo', ?, 'bogus_sql_hash', ? )]],
				needsUpdateFrom,
				exampleFunction_md5 )

	indexStoreSchema:resetTablesBySchemaVersionList( db, {} )

	-- Examine the schema.

	rxTest:expectEqual(

		{
			{
				"CREATE TABLE coreInfo( docId, aspectRatio, displayDate )",
			},
			{
				"CREATE INDEX coreInfo_displayDate ON coreInfo( displayDate )",
			},
			{
				"CREATE INDEX coreInfo_docId ON coreInfo( docId )",
			},
			{
				"CREATE TABLE indexStatus(\n\t\t\t\t\tindexTableName UNIQUE,\n\t\t\t\t\tneedsUpdateFrom,\n\t\t\t\t\tsqlSchemaHash,\n\t\t\t\t\tmapFunctionHash)",
					-- Ugh, but white space has to match.
			},
			{
				"CREATE TABLE localState( name UNIQUE NOT NULL, value )",
			},
			{
				"CREATE TABLE schemaVersion( currentVersion, backwardCompatibleToVersion )",
			},
			{
			},
			{
			},
		},

		db:gatherArrayOfArray
			[[SELECT sql FROM sqlite_master ORDER BY name, type]] )

	-- Examine the indexStatus table.

	rxTest:expectEqual(

		{
			{
				"coreInfo",
				1,
				coreInfoHash,
				exampleFunction_md5,
			},
		},

		db:gatherArrayOfArray
			[[SELECT * FROM indexStatus ORDER BY indexTableName]] )

	rxTest:expectEqual( { coreInfo = "schema" }, indexStoreSchema:tablesResetAtInitialization() )

end

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

function WFRxIndexStoreSchemaTest.rxTestResetTablesBySchemaVersionList_existingDatabase_tablesToReindex( rxTest )

	local indexStoreSchema = exampleSchemaFromApiDocs()

	local db = indexStoreSchema:openOrCreateDatabaseAtPath( ':memory:' )

	-- Fake some existing rows in the index status.

	local needsUpdateFrom = 4711

	db:execOnce( [[INSERT INTO indexStatus VALUES( 'coreInfo', ?, 'bogus_sql_hash', ? )]],
				needsUpdateFrom,
				exampleFunction_md5 )

	-- Fake existing content in tables.

	db:execOnce
		[[INSERT INTO coreInfo VALUES( 'docId', 1.5, '2009-08-11' )]]

	-- Reset the schema.

	indexStoreSchema:resetTablesBySchemaVersionList( db, { 'coreInfo' } )

	-- Examine the schema.

	rxTest:expectEqual(

		{
			{
				"CREATE TABLE coreInfo( docId, aspectRatio, displayDate )",
			},
			{
				"CREATE INDEX coreInfo_displayDate ON coreInfo( displayDate )",
			},
			{
				"CREATE INDEX coreInfo_docId ON coreInfo( docId )",
			},
			{
				"CREATE TABLE indexStatus(\n\t\t\t\t\tindexTableName UNIQUE,\n\t\t\t\t\tneedsUpdateFrom,\n\t\t\t\t\tsqlSchemaHash,\n\t\t\t\t\tmapFunctionHash)",
					-- Ugh, but white space has to match.
			},
			{
				"CREATE TABLE localState( name UNIQUE NOT NULL, value )",
			},
			{
				"CREATE TABLE schemaVersion( currentVersion, backwardCompatibleToVersion )",
			},
			{
			},
			{
			},
		},

		db:gatherArrayOfArray
			[[SELECT sql FROM sqlite_master ORDER BY name, type]] )

	-- Examine the indexStatus table.

	rxTest:expectEqual(

		{
			{
				"coreInfo",
				1,
				coreInfoHash,
				exampleFunction_md5,
			},
		},

		db:gatherArrayOfArray
			[[SELECT * FROM indexStatus ORDER BY indexTableName]] )

	-- Make sure the index table was cleared

	rxTest:expectEqual(
		{ { 0 } },
		db:gatherArrayOfArray [[SELECT count() FROM coreInfo]] )

	rxTest:expectEqual( { coreInfo = 'versionList' }, indexStoreSchema:tablesResetAtInitialization() )

end

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

function WFRxIndexStoreSchemaTest.rxTestResetTablesBySchemaVersionList_newIndexStoreTable( rxTest )

	local indexStoreSchema = exampleSchemaFromApiDocs()

	local db = indexStoreSchema:openOrCreateDatabaseAtPath( ':memory:' )

	-- Purposefully do not add an entry into the indexStatus for the coreInfo table.

	-- Fake existing content in tables.

	db:execOnce
		[[INSERT INTO coreInfo VALUES( 'docId', 1.5, '2009-08-11' )]]

	-- Reset the schema. Because the core info table is "new" and not in the
	-- indexStatus table, we should decide to reindex it.

	indexStoreSchema:resetTablesBySchemaVersionList( db, {} )

	-- Examine the schema.

	rxTest:expectEqual(

		{
			{
				"CREATE TABLE coreInfo( docId, aspectRatio, displayDate )",
			},
			{
				"CREATE INDEX coreInfo_displayDate ON coreInfo( displayDate )",
			},
			{
				"CREATE INDEX coreInfo_docId ON coreInfo( docId )",
			},
			{
				"CREATE TABLE indexStatus(\n\t\t\t\t\tindexTableName UNIQUE,\n\t\t\t\t\tneedsUpdateFrom,\n\t\t\t\t\tsqlSchemaHash,\n\t\t\t\t\tmapFunctionHash)",
					-- Ugh, but white space has to match.
			},
			{
				"CREATE TABLE localState( name UNIQUE NOT NULL, value )",
			},
			{
				"CREATE TABLE schemaVersion( currentVersion, backwardCompatibleToVersion )",
			},
			{
			},
			{
			},
		},

		db:gatherArrayOfArray
			[[SELECT sql FROM sqlite_master ORDER BY name, type]] )

	-- Examine the indexStatus table. It should now contain an entry
	-- for coreInfo.

	rxTest:expectEqual(

		{
			{
				"coreInfo",
				1,
				coreInfoHash,
				exampleFunction_md5,
			},
		},

		db:gatherArrayOfArray
			[[SELECT * FROM indexStatus ORDER BY indexTableName]] )

	-- Make sure the index table was cleared

	rxTest:expectEqual(
		{ { 0 } },
		db:gatherArrayOfArray [[SELECT count() FROM coreInfo]] )

	rxTest:expectEqual( { coreInfo = 'new' }, indexStoreSchema:tablesResetAtInitialization() )

end

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

function WFRxIndexStoreSchemaTest.rxTestGetTypeSubtypeMapForTables( rxTest )

	local indexStoreSchema = WFRxIndexStoreSchema()

	indexStoreSchema:addTable {
		sql = "CREATE TABLE versionsAndWatermarks( foo )",
		map = mapForExampleSchema,
		relevantTypeSubtypeTuples = { { "version", "edit" }, { "watermark", "text" } }
	}

	indexStoreSchema:addTable {
		sql = "CREATE TABLE conflicts( foo )",
		map = mapForExampleSchema,
		relevantTypeSubtypeTuples = { { "asset", "*" } }
	}

	indexStoreSchema:addTable {
		sql = "CREATE TABLE faces( foo )",
		map = mapForExampleSchema,
		relevantTypeSubtypeTuples = { { "asset", "person" } }
	}
	
	indexStoreSchema:addTable {
		sql = "CREATE TABLE conflicts2( foo )",
		map = mapForExampleSchema,
		relevantTypeSubtypeTuples = { { "asset", "image" }, { "album_asset", "NULL" } }
	}
		
	local tableNames = {
		"versionsAndWatermarks",
		"conflicts",
		"faces",
		"conflicts2"
	}
	
	local expectedMap = { 
	
		album_asset = { "NULL" }, 
		asset = { "*" }, 
		version = { "edit" }, 
		watermark = { "text" }
		
	}
		
	rxTest:expectEqual( expectedMap, indexStoreSchema:getTypeSubtypeMapForTables( tableNames ) )
	
	indexStoreSchema:addTable {
		sql = "CREATE TABLE allConflicts( foo )",
		map = mapForExampleSchema,
		relevantTypeSubtypeTuples = { { "*", "*" }, { "album_asset", "NULL" } }
	}
	
	tableNames[ #tableNames + 1 ] = 'allConflicts'

	expectedMap = { [ "*" ] = { "*" } }

	rxTest:expectEqual( expectedMap, indexStoreSchema:getTypeSubtypeMapForTables( tableNames ) )
	
end

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

function WFRxIndexStoreSchemaTest.rxTestRelevantTypeAndSubtypesByTable( rxTest )

	local indexStoreSchema = WFRxIndexStoreSchema()

	indexStoreSchema:addTable {
		sql = "CREATE TABLE versionsAndWatermarks( foo )",
		map = mapForExampleSchema,
		relevantTypeSubtypeTuples = { { "version", "edit" }, { "watermark", "text" } }
	}

	indexStoreSchema:addTable {
		sql = "CREATE TABLE conflicts( foo )",
		map = mapForExampleSchema,
		relevantTypeSubtypeTuples = { { "asset", "*" } }
	}

	indexStoreSchema:addTable {
		sql = "CREATE TABLE faces( foo )",
		map = mapForExampleSchema,
		relevantTypeSubtypeTuples = { { "asset", "person" } }
	}
	
	indexStoreSchema:addTable {
		sql = "CREATE TABLE conflicts2( foo )",
		map = mapForExampleSchema,
		relevantTypeSubtypeTuples = { { "asset", "image" }, { "album_asset", "NULL" } }
	}

	local relevantTypeAndSubtypesByTable = indexStoreSchema:relevantTypeAndSubtypesByTable()

	rxTest:expectEqual( {
		conflicts = {
			asset = {
				["*"] = true,
			},
		},
		conflicts2 = {
			album_asset = {
				NULL = true,
			},
			asset = {
				image = true,
			},
		},
		faces = {
			asset = {
				person = true,
			},
		},
		versionsAndWatermarks = {
			version = {
				edit = true,
			},
			watermark = {
				text = true,
			},
		},
	}, relevantTypeAndSubtypesByTable )

end

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

return WFRxTestCase.wrapSuite( 'WFRxIndexStoreSchemaTest', WFRxIndexStoreSchemaTest )
