local mItalicTitle = require('Module:Italic title/sandbox')
local ScribuntoUnit = require('Module:ScribuntoUnit')
local Spy = require('Module:Lua-mock/Spy')
local suite = ScribuntoUnit:new()

local function patchCurrentTitle(page, func)
	local oldGetCurrentTitle = mw.title.getCurrentTitle
	mw.title.getCurrentTitle = function ()
		return mw.title.new(page)
	end
	func()
	mw.title.getCurrentTitle = oldGetCurrentTitle
end

local function patchDisplayTitle(func)
	local oldGetCurrentFrame = mw.getCurrentFrame
	local frame = oldGetCurrentFrame()
	local oldCallParserFunction = frame.callParserFunction
	local callParserFunctionSpy = Spy(oldCallParserFunction)
	mw.getCurrentFrame = function ()
		return frame
	end
	frame.callParserFunction = callParserFunctionSpy
	func(callParserFunctionSpy, frame)
	frame.callParserFunction = oldCallParserFunction
	mw.getCurrentFrame = oldGetCurrentFrame
end

local displayTitleTestData = {
	{
		func = mItalicTitle._main,
		description = 'test _main: Italicize all - single-word titles',
		page = "Example",
		args = {},
		expectedDisplayTitleArgs = {"<i>Example</i>"},
	},
	{
		func = mItalicTitle._main,
		description = 'test _main: Italicize all - multi-word titles',
		page = "Star Wars",
		args = {},
		expectedDisplayTitleArgs = {"<i>Star Wars</i>"},
	},
	{
		func = mItalicTitle._main,
		description = 'test _main: Text in parentheses is not italicized',
		page = "Example (dab)",
		args = {},
		expectedDisplayTitleArgs = {"<i>Example</i> (dab)"},
	},
	{
		func = mItalicTitle._main,
		description = 'test _main: Text in final parentheses is not italicized',
		page = "Example (not dab) (dab)",
		args = {},
		expectedDisplayTitleArgs = {"<i>Example (not dab)</i> (dab)"},
	},
	{
		func = mItalicTitle._main,
		description = 'test _main: Text in disambiguation with parentheses is not italicized',
		page = "Example (dab (dab))",
		args = {},
		expectedDisplayTitleArgs = {"<i>Example</i> (dab (dab))"},
	},
	{
		func = mItalicTitle._main,
		description = 'test _main: When the entire title is in parentheses, it is all italicized',
		page = "(Example page)",
		args = {},
		expectedDisplayTitleArgs = {"<i>(Example page)</i>"},
	},
	{
		func = mItalicTitle._main,
		description = 'test _main: Only specified string argument italicized (string=)',
		page = "List of Ally McBeal episodes",
		args = {string = "Ally McBeal"},
		expectedDisplayTitleArgs = {"List of <i>Ally McBeal</i> episodes"},
	},
	{
		func = mItalicTitle._main,
		description = 'test _main: Only specified string argument italicized - in disambiguation (string= and all=)',
		page = "Peter (Fringe episode)",
		args = {string = "Fringe", all = "yes"},
		expectedDisplayTitleArgs = {"Peter (<i>Fringe</i> episode)"},
	},
	{
		func = mItalicTitle._main,
		description = 'test _main: Title and dismabiguation italicized (all=)',
		page = "Title (dismabiguation)",
		args = {all = "yes"},
		expectedDisplayTitleArgs = {"<i>Title (dismabiguation)</i>"},
	},
	{
		func = mItalicTitle._main,
		description = 'test _main: For pages with a namespace prefix, the namespace prefix is not italicized',
		page = "Wikipedia:Example",
		args = {},
		expectedDisplayTitleArgs = {"Wikipedia:<i>Example</i>"},
	},
	{
		func = mItalicTitle._main,
		description = 'test _main: Only specified string argument italicized (string=) in title with a comma',
		page = "Morceaux de salon, Op. 6 (Rachmaninoff)",
		args = {string = "Morceaux de salon"},
		expectedDisplayTitleArgs = {"<i>Morceaux de salon</i>, Op. 6 (Rachmaninoff)"},
	},
	{
		func = mItalicTitle._main,
		description = 'test _main: Only specified string argument italicized (string= and all=) in title with a comma',
		page = "Morceaux de salon, Op. 6 (Rachmaninoff)",
		args = {string = "Morceaux de salon", all = "yes"},
		expectedDisplayTitleArgs = {"<i>Morceaux de salon</i>, Op. 6 (Rachmaninoff)"},
	},
	{
		func = mItalicTitle._dabonly,
		description = 'test _dabonly: Italicize disambiguation',
		page = "The End (Lost)",
		args = {},
		expectedDisplayTitleArgs = {"The End (<i>Lost</i>)"},
	},
	{
		func = mItalicTitle._dabonly,
		description = 'test _dabonly: Italicize disambiguation with parentheses',
		page = "The Ghost Talks (Randall and Hopkirk (Deceased))",
		args = {},
		expectedDisplayTitleArgs = {"The Ghost Talks (<i>Randall and Hopkirk (Deceased)</i>)"},
	},
	{
		func = mItalicTitle._dabonly,
		description = 'test _dabonly: Italicize final parentheses only',
		page = "Title (not disambiguation) (disambiguation)",
		args = {},
		expectedDisplayTitleArgs = {"Title (not disambiguation) (<i>disambiguation</i>)"},
	},
	{
		func = mItalicTitle._dabonly,
		description = 'test _dabonly: When the entire title is in parentheses, it is not italicized',
		page = "(Example page)",
		args = {},
		expectedDisplayTitleArgs = {"(Example page)"},
	},
	{
		func = mItalicTitle._dabonly,
		description = 'test _dabonly: Only specified string argument italicized - in disambiguation (string=)',
		page = "Hell on Wheels (Hell on Wheels episode)",
		args = {string = "Hell on Wheels"},
		expectedDisplayTitleArgs = {"Hell on Wheels (<i>Hell on Wheels</i> episode)"},
	},
	{
		func = mItalicTitle._main,
		description = 'test _main: When noerror is specified as the first positional argument, it is passed to DISPLAYTITLE',
		page = "Example",
		args = {"noerror"},
		expectedDisplayTitleArgs = {"<i>Example</i>", "noerror"},
	},
	{
		func = mItalicTitle._dabonly,
		description = 'test _dabonly: When noerror is specified as the first positional argument, it is passed to DISPLAYTITLE',
		page = "Example (dab)",
		args = {"noerror"},
		expectedDisplayTitleArgs = {"Example (<i>dab</i>)", "noerror"},
	},
}

for _, testData in ipairs(displayTitleTestData) do
	suite[testData.description] = function (self)
		patchCurrentTitle(
			testData.page,
			function ()
				patchDisplayTitle(
					function (callParserFunctionSpy, frame)
						testData.func(testData.args)
						callParserFunctionSpy:assertCallMatches{
							atIndex = 1,
							arguments = {
								frame,
								'DISPLAYTITLE',
								unpack(testData.expectedDisplayTitleArgs),
							}
						}
					end
				)
			end
		)
	end
end


local categoryTestData = {
	{
		description = "test _main: Tracking category is added when the string argument does not match the title",
		func = mItalicTitle._main,
		page = "Example",
		args = {string = "foo"},
	},
	{
		description = "test _main: Tracking category is added when the string argument does not match the title or dab, and the all argument is specified",
		func = mItalicTitle._main,
		page = "Example (dab)",
		args = {string = "foo", all = "yes"},
	},
	{
		description = "test _dabonly: Tracking category is added when the string argument does not match the disambiguation",
		func = mItalicTitle._dabonly,
		page = "Example (dab)",
		args = {string = "foo"},
	},
	{
		description = "test _dabonly: Tracking category is added when the string argument does not match the disambiguation and no disambiguation is present in title",
		func = mItalicTitle._dabonly,
		page = "Example",
		args = {string = "foo"},
	},
}

for _, testData in ipairs(categoryTestData) do
	suite[testData.description] = function (self)
		patchCurrentTitle(
			testData.page,
			function ()
				self:assertStringContains(
					testData.func(testData.args),
					"[[Category:Pages using italic title with no matching string]]",
					true
				)
			end
		)
	end
end

return suite