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