1local testframework = require 'Module:TestFramework'
2
3local title, title_copy, title2, title3, title4, title5, title6u, title6s, title4p
4if mw.title.testPageId then
5	title = mw.title.getCurrentTitle()
6	title_copy = mw.title.getCurrentTitle()
7	title2 = mw.title.new( 'Module:TestFramework' )
8	title3 = mw.title.new( 'interwikiprefix:Module:TestFramework' )
9	title4 = mw.title.new( 'Talk:Has/A/Subpage' )
10	title5 = mw.title.new( 'Not/A/Subpage' )
11	title4.fragment = 'frag'
12
13	title4p = mw.title.new( 'Talk:Has/A' )
14
15	title6u = mw.title.new( 'Module_talk:Test_Framework' )
16	title6u.fragment = '__frag__frag__'
17
18	title6s = mw.title.new( 'Module talk:Test Framework' )
19	title6s.fragment = '  frag  frag  '
20end
21
22local function prop_foreach( prop )
23	return title[prop], title2[prop], title3[prop], title4[prop], title5[prop], title6u[prop], title6s[prop]
24end
25
26local function func_foreach( func, ... )
27	return title[func]( title, ... ),
28		title2[func]( title2, ... ),
29		title3[func]( title3, ... ),
30		title4[func]( title4, ... ),
31		title5[func]( title5, ... ),
32		title6u[func]( title6u, ... ),
33		title6s[func]( title6s, ... )
34end
35
36local function identity( ... )
37	return ...
38end
39
40local function test_space_normalization( s )
41	local title = mw.title.new( s )
42	return tostring( title ), tostring( title.fragment )
43end
44
45local function test_expensive_10()
46	for i = 1, 10 do
47		local _ = mw.title.new( tostring( i ) ).id
48	end
49	return 'did not error'
50end
51
52local function test_expensive_11()
53	for i = 1, 11 do
54		local _ = mw.title.new( tostring( i ) ).id
55	end
56	return 'did not error'
57end
58
59local function test_expensive_cached()
60	for i = 1, 100 do
61		local _ = mw.title.new( 'Title' ).id
62	end
63	return 'did not error'
64end
65
66local function test_inexpensive()
67	for i = 1, 100 do
68		local _ = mw.title.new( 'Title' ).prefixedText
69	end
70	return 'did not error'
71end
72
73local function test_getContent()
74	return mw.title.new( 'ScribuntoTestPage' ):getContent(),
75		mw.title.new( 'ScribuntoTestNonExistingPage' ):getContent()
76end
77
78local function test_redirectTarget()
79	local targets = {}
80	local titles = {
81		'ScribuntoTestRedirect',
82		'ScribuntoTestNonRedirect',
83		'ScribuntoTestNonExistingPage'
84	}
85	for _, title in ipairs( titles ) do
86		local target = mw.title.new( title ).redirectTarget
87		if title.prefixedText ~= nil then
88			target = title.prefixedText
89		end
90		table.insert( targets, target )
91	end
92	return unpack( targets )
93end
94
95local function test_getCurrentTitle_fragment()
96	mw.title.getCurrentTitle().fragment = 'bad'
97	return mw.title.getCurrentTitle().fragment
98end
99
100-- Tests
101local tests = {
102	{ name = 'tostring', func = identity, type = 'ToString',
103		args = { title, title2, title3, title4, title5, title6u, title6s },
104		expect = {
105			'Main Page', 'Module:TestFramework', 'interwikiprefix:Module:TestFramework',
106			'Talk:Has/A/Subpage', 'Not/A/Subpage',
107			'Module talk:Test Framework', 'Module talk:Test Framework'
108		}
109	},
110
111	{ name = 'title.equal', func = mw.title.equals,
112		args = { title, title },
113		expect = { true }
114	},
115	{ name = 'title.equal (2)', func = mw.title.equals,
116		args = { title, title_copy },
117		expect = { true }
118	},
119	{ name = 'title.equal (3)', func = mw.title.equals,
120		args = { title, title2 },
121		expect = { false }
122	},
123	{ name = '==', func = function ()
124		return rawequal( title, title_copy ), title == title, title == title_copy, title == title2
125		end,
126		expect = { false, true, true, false }
127	},
128
129	{ name = 'title.compare', func = mw.title.compare,
130		args = { title, title },
131		expect = { 0 }
132	},
133	{ name = 'title.compare (2)', func = mw.title.compare,
134		args = { title, title_copy },
135		expect = { 0 }
136	},
137	{ name = 'title.compare (3)', func = mw.title.compare,
138		args = { title, title2 },
139		expect = { -1 }
140	},
141	{ name = 'title.compare (4)', func = mw.title.compare,
142		args = { title2, title },
143		expect = { 1 }
144	},
145	{ name = 'title.compare (5)', func = mw.title.compare,
146		args = { title2, title3 },
147		expect = { -1 }
148	},
149	{ name = 'title.compare (6)', func = mw.title.compare,
150		args = { title6s, title6u },
151		expect = { 0 }
152	},
153	{ name = '<', func = function ()
154		return title < title, title < title_copy, title < title2, title2 < title
155		end,
156		expect = { false, false, true, false }
157	},
158	{ name = '<=', func = function ()
159		return title <= title, title <= title_copy, title <= title2, title2 <= title
160		end,
161		expect = { true, true, true, false }
162	},
163
164	{ name = 'title.new with namespace', func = mw.title.new, type = 'ToString',
165		args = { 'TestFramework', 'Module' },
166		expect = { 'Module:TestFramework' }
167	},
168	{ name = 'title.new with namespace (2)', func = mw.title.new, type = 'ToString',
169		args = { 'TestFramework', mw.site.namespaces.Module.id },
170		expect = { 'Module:TestFramework' }
171	},
172	{ name = 'title.new with namespace (3)', func = mw.title.new, type = 'ToString',
173		args = { 'Template:TestFramework', 'Module' },
174		expect = { 'Template:TestFramework' }
175	},
176	{ name = 'title.new space normalization', func = test_space_normalization,
177		args = { ' __ Template __ : __ Test _ Framework __ # _ frag _ frag _ ' },
178		expect = { 'Template:Test Framework', ' frag frag' }
179	},
180	{ name = 'title.new with invalid title', func = mw.title.new,
181		args = { '<bad title>' },
182		expect = { nil }
183	},
184	{ name = 'title.new with nonexistent pageid', func = mw.title.new,
185		args = { -1 },
186		expect = { nil }
187	},
188	{ name = 'title.new with pageid 0', func = mw.title.new,
189		args = { 0 },
190		expect = { nil }
191	},
192	{ name = 'title.new with existing pageid', func = mw.title.new, type = 'ToString',
193		args = { mw.title.testPageId },
194		expect = { 'ScribuntoTestPage' }
195	},
196
197	{ name = 'title.makeTitle', func = mw.title.makeTitle, type = 'ToString',
198		args = { 'Module', 'TestFramework' },
199		expect = { 'Module:TestFramework' }
200	},
201	{ name = 'title.makeTitle (2)', func = mw.title.makeTitle, type = 'ToString',
202		args = { mw.site.namespaces.Module.id, 'TestFramework' },
203		expect = { 'Module:TestFramework' }
204	},
205	{ name = 'title.makeTitle (3)', func = mw.title.makeTitle, type = 'ToString',
206		args = { mw.site.namespaces.Module.id, 'Template:TestFramework' },
207		expect = { 'Module:Template:TestFramework' }
208	},
209
210	{ name = '.isLocal', func = prop_foreach,
211		args = { 'isLocal' },
212		expect = { true, true, false, true, true, true, true }
213	},
214	{ name = '.isTalkPage', func = prop_foreach,
215		args = { 'isTalkPage' },
216		expect = { false, false, false, true, false, true, true }
217	},
218	{ name = '.isSubpage', func = prop_foreach,
219		args = { 'isSubpage' },
220		expect = { false, false, false, true, false, false, false }
221	},
222	{ name = '.text', func = prop_foreach,
223		args = { 'text' },
224		expect = {
225			'Main Page', 'TestFramework', 'Module:TestFramework', 'Has/A/Subpage', 'Not/A/Subpage',
226			'Test Framework', 'Test Framework'
227		}
228	},
229	{ name = '.prefixedText', func = prop_foreach,
230		args = { 'prefixedText' },
231		expect = {
232			'Main Page', 'Module:TestFramework', 'interwikiprefix:Module:TestFramework',
233			'Talk:Has/A/Subpage', 'Not/A/Subpage', 'Module talk:Test Framework', 'Module talk:Test Framework',
234		}
235	},
236	{ name = '.rootText', func = prop_foreach,
237		args = { 'rootText' },
238		expect = {
239			'Main Page', 'TestFramework', 'Module:TestFramework', 'Has', 'Not/A/Subpage',
240			'Test Framework', 'Test Framework'
241		}
242	},
243	{ name = '.baseText', func = prop_foreach,
244		args = { 'baseText' },
245		expect = {
246			'Main Page', 'TestFramework', 'Module:TestFramework', 'Has/A', 'Not/A/Subpage',
247			'Test Framework', 'Test Framework'
248		}
249	},
250	{ name = '.subpageText', func = prop_foreach,
251		args = { 'subpageText' },
252		expect = {
253			'Main Page', 'TestFramework', 'Module:TestFramework', 'Subpage', 'Not/A/Subpage',
254			'Test Framework', 'Test Framework'
255		}
256	},
257	{ name = '.fullText', func = prop_foreach,
258		args = { 'fullText' },
259		expect = {
260			'Main Page', 'Module:TestFramework', 'interwikiprefix:Module:TestFramework',
261			'Talk:Has/A/Subpage#frag', 'Not/A/Subpage',
262			'Module talk:Test Framework# frag frag', 'Module talk:Test Framework# frag frag'
263		}
264	},
265	{ name = '.subjectNsText', func = prop_foreach,
266		args = { 'subjectNsText' },
267		expect = { '', 'Module', '', '', '', 'Module', 'Module' }
268	},
269	{ name = '.fragment', func = prop_foreach,
270		args = { 'fragment' },
271		expect = { '', '', '', 'frag', '', ' frag frag', ' frag frag' }
272	},
273	{ name = '.interwiki', func = prop_foreach,
274		args = { 'interwiki' },
275		expect = { '', '', 'interwikiprefix', '', '', '', '' }
276	},
277	{ name = '.namespace', func = prop_foreach,
278		args = { 'namespace' },
279		expect = {
280			0, mw.site.namespaces.Module.id, 0, 1, 0,
281			mw.site.namespaces.Module_talk.id, mw.site.namespaces.Module_talk.id
282		}
283	},
284	{ name = '.protectionLevels', func = prop_foreach,
285		args = { 'protectionLevels' },
286		expect = {
287			{ edit = {}, move = {} }, { edit = { 'sysop', 'bogus' }, move = { 'sysop', 'bogus' } },
288			{}, { create = { 'sysop' } }, { edit = { 'autoconfirmed' }, move = { 'sysop' } },
289			{ edit = {}, move = { 'sysop' } }, { edit = {}, move = { 'sysop' } }
290		}
291	},
292	{ name = '.cascadingProtection', func = prop_foreach,
293		args = { 'cascadingProtection' },
294		expect = {
295			{ restrictions = { edit = { 'sysop' } }, sources = { 'Lockbox', 'Lockbox2' } }, { restrictions = {}, sources = {} },
296			{ restrictions = {}, sources = {} }, { restrictions = {}, sources = {} }, { restrictions = {}, sources = {} },
297			{ restrictions = {}, sources = {} }, { restrictions = {}, sources = {} }
298		}
299	},
300	{ name = '.inNamespace()', func = func_foreach,
301		args = { 'inNamespace', 'Module' },
302		expect = { false, true, false, false, false, false, false }
303	},
304	{ name = '.inNamespace() 2', func = func_foreach,
305		args = { 'inNamespace', mw.site.namespaces.Module.id },
306		expect = { false, true, false, false, false, false, false }
307	},
308	{ name = '.inNamespaces()', func = func_foreach,
309		args = { 'inNamespaces', 0, 1 },
310		expect = { true, false, true, true, true, false, false }
311	},
312	{ name = '.hasSubjectNamespace()', func = func_foreach,
313		args = { 'hasSubjectNamespace', 0 },
314		expect = { true, false, true, true, true, false, false }
315	},
316	{ name = '.isSubpageOf() 1', func = func_foreach,
317		args = { 'isSubpageOf', title },
318		expect = { false, false, false, false, false, false, false }
319	},
320	{ name = '.isSubpageOf() 2', func = func_foreach,
321		args = { 'isSubpageOf', title4p },
322		expect = { false, false, false, true, false, false, false }
323	},
324	{ name = '.partialUrl()', func = func_foreach,
325		args = { 'partialUrl' },
326		expect = {
327			'Main_Page', 'TestFramework', 'Module:TestFramework', 'Has/A/Subpage', 'Not/A/Subpage',
328			'Test_Framework', 'Test_Framework'
329		}
330	},
331	{ name = '.fullUrl()', func = func_foreach,
332		args = { 'fullUrl' },
333		expect = {
334			'//wiki.local/wiki/Main_Page',
335			'//wiki.local/wiki/Module:TestFramework',
336			'//test.wikipedia.org/wiki/Module:TestFramework',
337			'//wiki.local/wiki/Talk:Has/A/Subpage#frag',
338			'//wiki.local/wiki/Not/A/Subpage',
339			'//wiki.local/wiki/Module_talk:Test_Framework#_frag_frag',
340			'//wiki.local/wiki/Module_talk:Test_Framework#_frag_frag',
341		}
342	},
343	{ name = '.fullUrl() 2', func = func_foreach,
344		args = { 'fullUrl', { action = 'test' } },
345		expect = {
346			'//wiki.local/w/index.php?title=Main_Page&action=test',
347			'//wiki.local/w/index.php?title=Module:TestFramework&action=test',
348			'//test.wikipedia.org/wiki/Module:TestFramework?action=test',
349			'//wiki.local/w/index.php?title=Talk:Has/A/Subpage&action=test#frag',
350			'//wiki.local/w/index.php?title=Not/A/Subpage&action=test',
351			'//wiki.local/w/index.php?title=Module_talk:Test_Framework&action=test#_frag_frag',
352			'//wiki.local/w/index.php?title=Module_talk:Test_Framework&action=test#_frag_frag',
353		}
354	},
355	{ name = '.fullUrl() 3', func = func_foreach,
356		args = { 'fullUrl', nil, 'http' },
357		expect = {
358			'http://wiki.local/wiki/Main_Page',
359			'http://wiki.local/wiki/Module:TestFramework',
360			'http://test.wikipedia.org/wiki/Module:TestFramework',
361			'http://wiki.local/wiki/Talk:Has/A/Subpage#frag',
362			'http://wiki.local/wiki/Not/A/Subpage',
363			'http://wiki.local/wiki/Module_talk:Test_Framework#_frag_frag',
364			'http://wiki.local/wiki/Module_talk:Test_Framework#_frag_frag',
365		}
366	},
367	{ name = '.localUrl()', func = func_foreach,
368		args = { 'localUrl' },
369		expect = {
370			'/wiki/Main_Page',
371			'/wiki/Module:TestFramework',
372			'//test.wikipedia.org/wiki/Module:TestFramework',
373			'/wiki/Talk:Has/A/Subpage',
374			'/wiki/Not/A/Subpage',
375			'/wiki/Module_talk:Test_Framework',
376			'/wiki/Module_talk:Test_Framework',
377		}
378	},
379	{ name = '.canonicalUrl()', func = func_foreach,
380		args = { 'canonicalUrl' },
381		expect = {
382			'http://wiki.local/wiki/Main_Page',
383			'http://wiki.local/wiki/Module:TestFramework',
384			'http://test.wikipedia.org/wiki/Module:TestFramework',
385			'http://wiki.local/wiki/Talk:Has/A/Subpage#frag',
386			'http://wiki.local/wiki/Not/A/Subpage',
387			'http://wiki.local/wiki/Module_talk:Test_Framework#_frag_frag',
388			'http://wiki.local/wiki/Module_talk:Test_Framework#_frag_frag',
389		}
390	},
391
392	{ name = '.getContent()', func = test_getContent,
393		expect = {
394			'{{int:mainpage}}<includeonly>...</includeonly><noinclude>...</noinclude>',
395			nil,
396		}
397	},
398
399	{ name = '.redirectTarget', func = test_redirectTarget, type = 'ToString',
400		expect = { 'ScribuntoTestTarget', false, false }
401	},
402
403	{ name = 'not quite too many expensive functions', func = test_expensive_10,
404		expect = { 'did not error' }
405	},
406	{ name = 'too many expensive functions', func = test_expensive_11,
407		expect = 'too many expensive function calls'
408	},
409	{ name = "previously cached titles shouldn't count as expensive", func = test_expensive_cached,
410		expect = { 'did not error' }
411	},
412	{ name = "inexpensive actions shouldn't count as expensive", func = test_inexpensive,
413		expect = { 'did not error' }
414	},
415	{ name = "fragments don't leak via getCurrentTitle()", func = test_getCurrentTitle_fragment,
416		expect = { '' }
417	},
418}
419
420return testframework.getTestProvider( tests )
421