@@ -3726,12 +3946,27 @@ parsoid
!! test
Definition Lists: Nesting: Test 3 (Parsoid only)
-!! options
-parsoid
!! wikitext
:;t1
::::d2
-!! html
+!! html/php+tidy
+
+
+
+t1
+
+
+
+
+d2
+
+
+
+
+
+
+
+!! html/parsoid
@@ -4006,6 +4241,9 @@ Definition Lists: Mixed Lists: Test 11
# Another case where tidy converts a to a (but Parsoid doesn't).
+# From whitelist:
+# * The test is wrong, there are two colons where there should be :;
+# * The PHP parser is wrong to close the after the containing the .
!! test
Definition Lists: Weird Ones: Test 1
!! wikitext
@@ -4063,7 +4301,7 @@ Definition Lists: Weird Ones: Test 1
- foo
+ foo
bar (who uses this?)
@@ -4120,6 +4358,17 @@ Definition Lists: colons occurring in tags
+!! html/parsoid
+a b
+a:b
+a:b
+a:b
+a:b
+a
+b
+a:b
+a:b
+a:b
!! end
!! test
@@ -4440,6 +4689,25 @@ http://example.com/url_with_entity<
http://example.com/url_with_entity<
!! end
+!! test
+External links: Lone protocols are never linked (T105697)
+!! wikitext
+http://
+http://;
+(http://)
+bitcoin:
+bitcoin:;
+(bitcoin:)
+!! html
+http://
+http://;
+(http://)
+bitcoin:
+bitcoin:;
+(bitcoin:)
+
+!! end
+
!! test
External links: No preceding word characters allowed (bug 65278)
!! wikitext
@@ -4981,38 +5249,6 @@ External link containing a single quote. (bug 63947)
bang
!! end
-
-!! test
-External link containing a period in the anchor. (bug 63947)
-!! wikitext
-[//foo.org/bar#baz. bang]
-
-[//foo.org/bar. bang]
-!! html/php
-bang
-
bang
-
-!! html/parsoid
-bang
-bang
-!! end
-
-!! test
-External link containing a single quote. (bug 63947)
-!! wikitext
-[//foo.org/bar'baz]
-
-[//foo.org/bar'baz bang]
-!! html/php
-[1]
-
bang
-
-!! html/parsoid
-
-bang
-!! end
-
-
!! test
External link containing double-single-quotes in text '' (bug 4598 sanity check)
!! wikitext
@@ -5048,9 +5284,22 @@ External link containing double-single-quotes with no space separating the url f
External link with comments in link text
!! wikitext
[http://www.google.com Google ]
-!! html
+!! html/php
Google
+!! html/parsoid
+Google
+!! end
+
+!! test
+External link to bare IPv4 address
+!! wikitext
+[http://192.168.0.1 Link]
+!! html/php
+Link
+
+!! html/parsoid
+Link
!! end
!! test
@@ -5088,14 +5337,129 @@ http://example.com/index.php?foozoid[]=bar
!! end
!! test
-IPv6 urls (bug 21261)
-!! options
-disabled
+IPv6 urls, autolink format (T23261)
!! wikitext
http://[2404:130:0:1000::187:2]/index.php
-!! html
+
+Examples from RFC 2373, section 2.2:
+* http://[1080::8:800:200C:417A]/unicast
+* http://[FF01::101]/multicast
+* http://[::1]/loopback
+* http://[::]/unspecified
+* http://[::13.1.68.3]/ipv4compat
+* http://[::FFFF:129.144.52.38]/ipv4compat
+
+Examples from RFC 2732, section 2:
+* http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html
+* http://[1080:0:0:0:8:800:200C:417A]/index.html
+* http://[3ffe:2a00:100:7031::1]
+* http://[1080::8:800:200C:417A]/foo
+* http://[::192.9.5.5]/ipng
+* http://[::FFFF:129.144.52.38]:80/index.html
+* http://[2010:836B:4179::836B:4179]
+
+!! html/php
http://[2404:130:0:1000::187:2]/index.php
-
+Examples from RFC 2373 , section 2.2:
+
+
+Examples from RFC 2732 , section 2:
+
+
+
+!! html/parsoid
+http://[2404:130:0:1000::187:2]/index.php
+
+Examples from RFC 2373 , section 2.2:
+
+
+Examples from RFC 2732 , section 2:
+
+!! end
+
+!! test
+IPv6 urls, bracketed format (T23261)
+!! wikitext
+[http://[2404:130:0:1000::187:2]/index.php test]
+
+Examples from RFC 2373, section 2.2:
+* [http://[1080::8:800:200C:417A] unicast]
+* [http://[FF01::101] multicast]
+* [http://[::1]/ loopback]
+* [http://[::] unspecified]
+* [http://[::13.1.68.3] ipv4compat]
+* [http://[::FFFF:129.144.52.38] ipv4compat]
+
+Examples from RFC 2732, section 2:
+* [http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html 1]
+* [http://[1080:0:0:0:8:800:200C:417A]/index.html 2]
+* [http://[3ffe:2a00:100:7031::1] 3]
+* [http://[1080::8:800:200C:417A]/foo 4]
+* [http://[::192.9.5.5]/ipng 5]
+* [http://[::FFFF:129.144.52.38]:80/index.html 6]
+* [http://[2010:836B:4179::836B:4179] 7]
+
+!! html/php
+test
+
Examples from RFC 2373 , section 2.2:
+
+
+Examples from RFC 2732 , section 2:
+
+
+
+!! html/parsoid
+test
+
+Examples from RFC 2373 , section 2.2:
+
+
+Examples from RFC 2732 , section 2:
+
!! end
!! test
@@ -5113,7 +5477,8 @@ Non-extlinks in brackets
[{{echo|foo}}l's errand]
[url={{echo|foo}}]
[url=http://example.com]
-!! html
+[http:// bare protocols don't count]
+!! html/php
[foo]
[foo bar]
[foo bar ]
@@ -5126,7 +5491,22 @@ Non-extlinks in brackets
[fool's errand]
[url=foo]
[url=http://example.com ]
+[http:// bare protocols don't count]
+!! html/parsoid
+[foo]
+[foo bar]
+[foo bar ]
+[fool's] errand
+[fool's errand]
+[foo ]
+[foo bar]
+[foo bar ]
+[fool's ] errand
+[fool's errand]
+[url=foo ]
+[url=http://example.com ]
+[http:// bare protocols don't count]
!! end
!! test
@@ -5208,15 +5588,55 @@ Parenthesis in external links, w/ transclusion or comment
!! end
!! test
-Replace invalid link targets when serializing
+Serialize tags with invalid link targets as plain text
!! options
parsoid=html2wt
-!! html
- Manual
+!! html/parsoid
+text
+*text
+[[foo]]
+*a [[foo]]
+!! wikitext
+text
+* text
+[[foo]]
+*a [[foo]]
+!! end
+
+!! test
+mw:ExtLink -vs- mw:WikiLink (T94723)
+!! options
+parsoid=html2wt
+!! html/parsoid
+Bar
+Bar
+Bar
+Bar
+
+European Robin
+European Robin
+
+!! wikitext
+[[Foo|Bar]]
+[[Foo|Bar]]
+[[wikipedia:Foo|Bar]]
+[[wikipedia:Foo|Bar]]
+
+[[wikipedia:European_Robin|European Robin]]
+[[wikipedia:European_Robin|European Robin]]
+!! end
+
+!! test
+mw:ExtLink linking to a interwiki URL can be round-tripped losslessly (T94723)
+!! options
+parsoid=wt2wt
!! wikitext
-[[MediaWiki:Badtitletext|Manual]]
+[http://en.wikipedia.org/wiki/European_Robin European Robin]
+!! html/parsoid
+THIS SECTION IS NOT USED (but Parsoid won't run the test without it)
!! end
+
###
### Quotes
###
@@ -5280,7 +5700,9 @@ Plain ''italic'''s plain
Bold tag left open
Italic tag left open
Normal text.
-
This year' s election should beat last year' s.
+
+
+This year' s election should beat last year' s.
Toms car is bigger than Susan s.
Plain italic' s plain
@@ -5480,6 +5902,7 @@ Simple table but with multiple dashes for row wikitext
!! end
+
!! test
Multiplication table
!! wikitext
@@ -5600,6 +6023,69 @@ Accept "||" in indented table headings
!! end
+!! test
+Accept "!!" in templates
+!! wikitext
+{|
+!a {{echo|b!!c}}
+|}
+!! html/php
+
+
+!! html/parsoid
+
+a b c
+!! end
+
+!! test
+Accept "!!" in table headings after newline
+!! wikitext
+{|
+!a
+b!!c
+|}
+!! html/php
+
+
+!! html/parsoid
+
+!! end
+
+!! test
+Accept "!!" in table data of mixed wikitext / html syntax
+!! wikitext
+{|
+!a
+b!!c
+|}
+!! html+tidy
+
+!! html/parsoid
+
+!! end
+
!! test
Accept empty attributes in td/th cells (td/th cells starting with leading ||)
!! wikitext
@@ -5746,10 +6232,37 @@ Invalid attributes in table cell (bug 1830)
!! end
-# The "|}" to close the table is missing from the input, so parsoid's
-# *2wt modes will fail.
!! test
-Table security: embedded pipes (http://lists.wikimedia.org/mailman/htdig/wikitech-l/2006-April/022293.html)
+Table cell attributes: Pipes protected by nowikis should be treated as a plain character
+!! wikitext
+{|
+| title="foo" |bar
+| title="foo| " |bar
+| title="foo| " bar
+|}
+!! html/php
+
+
+bar
+
+bar
+
+ title="foo|" bar
+
+
+!! html/parsoid
+
+bar
+bar
+ title="foo| " bar
+
+!! end
+
+# See: http://lists.wikimedia.org/mailman/htdig/wikitech-l/2006-April/022293.html
+# N.B. The "|}" to close the table is missing from the input, so parsoid's
+# *2wt modes will fail.
+!! test
+Table security: embedded pipes
!! options
parsoid=wt2html,html2html
!! wikitext
@@ -5767,12 +6280,14 @@ parsoid=wt2html,html2html
!! html/parsoid
- " onmouseover="alert(document.cookie)">test
+ " onmouseover="alert(document.cookie)">test
!! end
-# FIXME: The php output is broken.
+# FIXME: The output seems broken. Filed as T110268.
!! test
! and || in td attributes should not be parsed as /
+!! options
+parsoid=wt2html
!! wikitext
{|
| style="color: red !important;" data-contrived="put this here ||" | foo
@@ -5786,7 +6301,7 @@ parsoid=wt2html,html2html
!! html/parsoid
- foo
+ style="color: red !important;" data-contrived="put this here foo
!! end
@@ -5892,6 +6407,50 @@ Indented table markup mixed with indented pre content (proposed in bug 6200)
!! end
+!! test
+4. Template-generated table cell attributes and cell content inside a templated table
+!! wikitext
+{{tbl-start}}
+!align=center {{table_header_cells}}
+|-
+|align=center {{table_cells}}
+{{tbl-end}}
+!! html/php
+
+
+Foo
+Bar
+Foo and Baz
+
+
+Foo
+Bar
+Foo and Baz
+
+
+!! html/parsoid
+
+Foo Bar Foo and Baz
+
+Foo Bar Foo and Baz
+
+!! end
+
+## Edge case fix to prevent future regressions
+!! test
+T107652: [s in templates that also generate table cell attributes should be rendered properly
+!! wikitext
+{|
+|{{table_attribs_7}}
+|}
+]
+!! html/parsoid
+
+↑ foo
+!! end
+
!! test
Table with row followed by newlines and table heading
!! wikitext
@@ -6305,7 +6864,7 @@ parsoid=wt2html,wt2wt
Parsoid: Default to a newline after tables in new content (bug 51219)
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
bar
@@ -6325,7 +6884,7 @@ parsoid=html2wt
Parsoid: newline inducing block nodes don't suppress
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
afoo
!! wikitext
a
@@ -6359,9 +6918,6 @@ parsoid=wt2html,wt2wt
!! end
-
-# PHP throws away the (semi-broken) "foo" class here; Parsoid
-# preserves it.
!!test
Parsoid: Recover better from broken table attributes
!!options
@@ -6372,7 +6928,7 @@ parsoid=wt2html
foo
|}
!!html/php+tidy
-
+
foo
@@ -6387,11 +6943,28 @@ foo
!!end
+!! test
+Tables: Digest broken attributes on table and tr tag
+!! options
+parsoid=wt2html
+!! wikitext
+{| || |} ++
+|- || || ++ --
+|- > [
+|}
+!! html
+
+!! end
+
!! test
Strip unsupported table tags
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
@@ -6597,8 +7170,10 @@ Link with HTML entity in suffix / tail
Link with 3 brackets
!! wikitext
[[[Main Page]]]
+Foo [[[Main Page]]]
!! html
[[[Main Page]]]
+Foo [[[Main Page]]]
!! end
@@ -6696,7 +7271,7 @@ Namespace takes precedence over interwiki link (bug 51680)
Link to namespace preferred over interwiki with correct rel attribute
!! options
parsoid=html2wt,html2html
-!! html
+!! html/parsoid
MemoryAlpha:AlphaTest
!! wikitext
[[MemoryAlpha:AlphaTest]]
@@ -6810,7 +7385,7 @@ Link containing a tilde
!! wikitext
[[Foo~bar]]
!! html/php
-Foo~bar
+
Foo~bar
!! html/parsoid
Foo~bar
@@ -6884,10 +7459,10 @@ Broken image links with HTML captions (bug 39700)
abc
!! html/parsoid
-
-
-
-
+
+
+
+
!! end
!! test
@@ -7125,7 +7700,7 @@ title=[[User:test/123]]
b
!! html/parsoid
-b
+b
!! end
!! test
@@ -7204,7 +7779,7 @@ mótmælenda[[söfnuður|söfnuðir]]xxx
Parsoid link trail escaping
!! options
parsoid=html2wt,html2html
-!! html
+!! html/parsoid
apple s
!! wikitext
[[apple]] s
@@ -7215,7 +7790,7 @@ Parsoid link prefix escaping
!! options
language=is
parsoid=html2wt,html2html
-!! html
+!! html/parsoid
Aðrir mótmælendasöfnuður
!! wikitext
Aðrir mótmælenda [[söfnuður]]
@@ -7515,7 +8090,6 @@ Blah blah blah
[[ es :Spanish]]
[[ ZH :Chinese]]
[[es:Foo_bar]]
-[[es:Foo bar]]
!! html/php
Blah blah blah
@@ -7524,7 +8098,21 @@ Blah blah blah
-
+!! end
+
+!! test
+Space and question mark encoding in interlanguage links (T95473)
+!! options
+parsoid=wt2html,wt2wt,html2html
+!! wikitext
+Blah blah blah
+[[es:Foo bar?]]
+!! html/php
+Blah blah blah
+
+!! html/parsoid
+Blah blah blah
+
!! end
!! test
@@ -7587,7 +8175,7 @@ language=ln
Parsoid bug 53221: Wikilinks should be properly entity-escaped
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
He llo He llo
He llo He llo
!! wikitext
@@ -7693,7 +8281,7 @@ Blah blah blah
!! html/parsoid
Blah blah blah
-mi:Template:Foo
+mi:Template:Foo
!! end
###
@@ -7702,12 +8290,10 @@ Blah blah blah
!! test
1. Simple redirect to page
-!! options
-parsoid
!! wikitext
#REDIRECT [[Main Page]]
-!! html
-
+!! html/parsoid
+
!! end
!! test
@@ -7718,12 +8304,22 @@ parsoid
!! end
+# Not a valid redirect in PHP (although perhaps it was, once upon a time)
+# This tests the Parsoid bail-out code.
!! test
3. Other redirect variants
!! wikitext
#REDIRECT [[[[Bar]] ]]
!! html/parsoid
-
+REDIRECT [[[[Bar]]]]
+!! end
+
+!! test
+4. Redirect to a templated destination
+!! wikitext
+#REDIRECT [[{{echo|Foo}}bar]]
+!! html/parsoid
+
!! end
!! test
@@ -7732,7 +8328,7 @@ Empty redirect
parsoid=wt2html,wt2wt
!! wikitext
#REDIRECT [[]]
-!! html
+!! html/parsoid
REDIRECT [[]]
!! end
@@ -7745,8 +8341,8 @@ Optional colon in #REDIRECT
parsoid=wt2html,html2html
!! wikitext
#REDIRECT:[[Main Page]]
-!! html
-
+!! html/parsoid
+
!! end
!! test
@@ -7761,8 +8357,8 @@ parsoid=wt2html,html2html
#REDIRECT
:
[[Main Page]]
-!! html
-
+!! html/parsoid
+
!! end
!! test
@@ -7773,89 +8369,90 @@ Piped link in #REDIRECT
parsoid=wt2html
!! wikitext
#REDIRECT [[Main Page|bar]]
-!! html
-
+!! html/parsoid
+
!! end
!! test
-Redirect to category
+Redirect to category (T104502)
!! options
-parsoid=wt2wt,wt2html
+parsoid=wt2html,wt2wt
!! wikitext
#REDIRECT [[Category:Foo]]
-!! html
-
+!! html/parsoid
+
!! end
!! test
-Redirect to category with URL encoding
+Redirect to category with URL encoding (T104502)
!! options
parsoid=wt2html
!! wikitext
#REDIRECT [[Category%3AFoo]]
-!! html
-
+!! html/parsoid
+
!! end
!! test
Redirect to category page
-!! options
-parsoid
!! wikitext
#REDIRECT [[:Category:Foo]]
-!! html
-
+!! html/parsoid
+
!! end
!! test
Redirect to image page (1)
-!! options
-parsoid
!! wikitext
#REDIRECT [[File:Wiki.png]]
-!! html
-
+!! html/parsoid
+
!! end
!! test
Redirect to image page (2)
-!! options
-parsoid
!! wikitext
#REDIRECT [[Image:Wiki.png]]
-!! html
-
+!! html/parsoid
+
!! end
+# html2wt disabled because wts serializes as "#REDIRECT [[:en:File:Wiki.png]]"
+# Next test confirms this.
!! test
-Redirect to language
+Redirect to language (1) (T104918)
!! options
-parsoid
+parsoid=wt2html,wt2wt,html2html
!! wikitext
#REDIRECT [[en:File:Wiki.png]]
-!! html
-
+!! html/parsoid
+
!! end
!! test
-Redirect to interwiki
-!! options
-parsoid
+Redirect to language (2) (T104918)
+!! wikitext
+#REDIRECT [[:en:File:Wiki.png]]
+!! html/parsoid
+
+!! end
+
+!! test
+Redirect to interwiki (T104918)
!! wikitext
#REDIRECT [[meatball:File:Wiki.png]]
-!! html
-
+!! html/parsoid
+
!! end
!! test
Non-English #REDIRECT
!! options
-parsoid
language=is
!! wikitext
#TILVÍSUN [[Main Page]]
-!! html
-
+!! html/parsoid
+
!! end
!! test
@@ -7874,8 +8471,8 @@ some text
New redirect
!! options
parsoid=html2wt
-!! html
-Foo
+!! html/parsoid
+Foo
!! wikitext
Foo
#REDIRECT [[Foo]]
@@ -7980,8 +8577,8 @@ Handling html with a br self-closing tag
!! html/php
-
-
+
+
@@ -8225,7 +8822,7 @@ parsoid
!! wikitext
*
!! html/parsoid
-
+
!! end
!! test
@@ -8258,11 +8855,15 @@ List items are not parsed correctly following a block (bug 785)
* foo
* bar
* zar
-!! html
+!! html/php
+!! html/parsoid
+
!! end
!! test
@@ -9306,7 +9907,7 @@ hi+world%3F%21
Magic Word: prioritize type info over data-parsoid
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
!! wikitext
__FORCETOC__
@@ -9320,7 +9921,7 @@ parsoid=wt2wt,html2wt
foo
__NOTOC__
bar
-!! html
+!! html/parsoid
foo bar
!! end
@@ -9331,10 +9932,19 @@ parsoid=wt2wt
language=de
!! wikitext
__NOEDITSECTION__
-!! html
+!! html/parsoid
!! end
+!!test
+__proto__ is treated as normal wikitext (T105997)
+!!wikitext
+__proto__
+!!html
+__proto__
+
+!!end
+
###
### Magic links
###
@@ -9342,27 +9952,33 @@ __NOEDITSECTION__
Magic links: internal link to RFC (bug 479)
!! wikitext
[[RFC 123]]
-!! html
+!! html/php
RFC 123
+!! html/parsoid
+RFC 123
!! end
!! test
Magic links: RFC (bug 479)
!! wikitext
RFC 822
-!! html
+!! html/php
RFC 822
+!! html/parsoid
+RFC 822
!! end
!! test
Magic links: RFC (bug 65278)
!! wikitext
This is RFC 822 but thisRFC 822 is not RFC 822linked.
-!! html
+!! html/php
This is RFC 822 but thisRFC 822 is not RFC 822linked.
+!! html/parsoid
+This is RFC 822 but thisRFC 822 is not RFC 822linked.
!! end
!! test
@@ -9371,20 +9987,26 @@ Magic links: RFC (w/ non-newline whitespace, bug 28950/29025)
RFC 822
RFC
822
-!! html
+!! html/php
RFC 822
RFC
822
+!! html/parsoid
+RFC 822
+RFC
+822
!! end
!! test
Magic links: ISBN (bug 1937)
!! wikitext
ISBN 0-306-40615-2
-!! html
+!! html/php
ISBN 0-306-40615-2
+!! html/parsoid
+ISBN 0-306-40615-2
!! end
!! test
@@ -9395,7 +10017,7 @@ This is ISBN 978-0-316-09811-3 but thisISBN 978-0-316-09811-3 is not ISBN 978-0-
This is ISBN 978-0-316-09811-3 but thisISBN 978-0-316-09811-3 is not ISBN 978-0-316-09811-3linked.
!! html/parsoid
-This is ISBN 978-0-316-09811-3 but thisISBN 978-0-316-09811-3 is not ISBN 978-0-316-09811-3linked.
+This is ISBN 978-0-316-09811-3 but thisISBN 978-0-316-09811-3 is not ISBN 978-0-316-09811-3linked.
!! end
!! test
@@ -9406,31 +10028,41 @@ ISBN
9780316098113
ISBN 978
0316098113
-!! html
+!! html/php
ISBN 978 0 316 09811 3
ISBN
9780316098113
ISBN 978
0316098113
+!! html/parsoid
+ISBN 978 0 316 09811 3
+ISBN
+9780316098113
+ISBN 978
+0316098113
!! end
!! test
Magic links: PMID incorrectly converts space to underscore
!! wikitext
PMID 1234
-!! html
+!! html/php
PMID 1234
+!! html/parsoid
+PMID 1234
!! end
!! test
Magic links: PMID (bug 65278)
!! wikitext
This is PMID 1234 but thisPMID 1234 is not PMID 1234linked.
-!! html
+!! html/php
This is PMID 1234 but thisPMID 1234 is not PMID 1234linked.
+!! html/parsoid
+This is PMID 1234 but thisPMID 1234 is not PMID 1234linked.
!! end
!! test
@@ -9439,11 +10071,15 @@ Magic links: PMID (w/ non-newline whitespace, bug 28950/29025)
PMID 1234
PMID
1234
-!! html
+!! html/php
PMID 1234
PMID
1234
+!! html/parsoid
+PMID 1234
+PMID
+1234
!! end
###
@@ -9642,9 +10278,11 @@ Template with default value (value set)
Template redirect
!! wikitext
{{templateredirect}}
-!! html
+!! html/php
(test)
+!! html/parsoid
+
!! end
!! test
@@ -9882,6 +10520,24 @@ Template with targets containing wikilinks
!! end
+!! article
+Template:''
+!! text
+bar
+!! endarticle
+
+!! test
+Templates: Double quotes as template target
+!! wikitext
+foo {{''}} baz
+!! html/php
+foo bar baz
+
+!! html/parsoid
+foo bar baz
+
+!! end
+
!! article
Template:MSGNW test
!! text
@@ -9892,6 +10548,7 @@ Template:MSGNW test
File:Foobar.jpg
+
!! endarticle
# hmm, fix this or just deprecate msgnw and document its behavior?
@@ -9899,7 +10556,7 @@ File:Foobar.jpg
msgnw keyword
!! wikitext
{{msgnw:MSGNW test}}
-!! html
+!! html/php
''None'' of '''this''' should be
* interpreted
but rather passed unmodified
@@ -9907,6 +10564,7 @@ msgnw keyword
<gallery>
File:Foobar.jpg
</gallery>
+<!-- comment -->
!! end
@@ -9919,6 +10577,15 @@ int keyword
!! end
+!! test
+int keyword - non-existing message
+!! wikitext
+{{int:var}}
+!! html
+<var>
+
+!! end
+
!! article
Template:Includes
!! text
@@ -10160,7 +10827,7 @@ b}}
!! end
!! test
-Parsoid: Merge double tds (bug 50603)
+Parsoid: Merge double tds (T52603)
!! options
parsoid
!! wikitext
@@ -10174,7 +10841,7 @@ parsoid
!! end
!! test
-Parsoid: Merge double tds in nested transclusion content (bug 50603)
+Parsoid: Merge double tds in nested transclusion content (T52603)
!! options
parsoid
!! wikitext
@@ -10669,6 +11336,43 @@ Templates: Support for templates generating attributes and content
!! end
+!! test
+3. Entities and nowikis inside templated attributes should be handled correctly inside templated tables
+!! wikitext
+{{tbl-start}}
+|{{table_attribs_3}}
+{{tbl-end}}
+!! html/php
+
+
+!! html/parsoid
+
+!! end
+
+# T107622
+!! test
+4. Entities and nowikis inside templated attributes should be handled correctly inside templated tables
+!! wikitext
+{|
+| {{table_attribs_6}} hi
+|}
+!! html/php
+
+
+!! html/parsoid
+
+!! end
+
!!test
Templates: HTML Tables: 1. Generating start of a HTML table
!! wikitext
@@ -10896,6 +11600,46 @@ Templates: Wiki Tables: 6. Templated tags, templated td-tags
!!end
+## This test case is very specific to Parsoid's internals
+## and is hence only tested for Parsoid's code. Parsoid uses
+## a marker tag for [ tags and they are expanded
+## much later. We are verifying that this ] tag usage
+## doesn't prevent foster parenting.
+!!test
+Templates: Wiki Tables: 7. Fosterable [s should get fostered
+!!wikitext
+{{PartialTable}}][foo]
+|}
+
+
+!!html/parsoid
+[1]
+
+↑ foo
+!!end
+
+!! test
+Templates: Wiki Tables: 8. Fosterable meta-tags should get fostered
+!! wikitext
+{{echo|
+{{{!}}
+{{!}}-}}
+
+|foo
+
+{{!}}}
+!! html/parsoid
+
+
+!! end
+
!!test
Templates: Lists: Multi-line list-items via templates
!! wikitext
@@ -11093,41 +11837,40 @@ Parser Functions: 2. Nested use (only outermost should be marked up)
!! test
pre-save transform: subst:
!! options
-PST
+pst
!! wikitext
{{subst:test}}
-!! html
+!! html/php
This is a test template
!! end
!! test
pre-save transform: normal template
!! options
-PST
+pst
!! wikitext
{{test}}
-!! html
+!! html/php
{{test}}
!! end
!! test
pre-save transform: nonexistent template
!! options
-PST
+pst
!! wikitext
{{thistemplatedoesnotexist}}
-!! html
+!! html/php
{{thistemplatedoesnotexist}}
!! end
-
!! test
pre-save transform: subst magic variables
!! options
-PST
+pst
!! wikitext
{{subst:SITENAME}}
-!! html
+!! html/php
MediaWiki
!! end
@@ -11138,7 +11881,7 @@ pre-save transform: subst: templates with parameters
pst
!! wikitext
{{subst:paramtest|param="something else"}}
-!! html
+!! html/php
This is a test template with parameter "something else"
!! end
@@ -11154,11 +11897,10 @@ pre-save transform: nowiki in subst (bug 1188)
pst
!! wikitext
{{subst:nowikitest}}
-!! html
+!! html/php
'''not wiki'''
!! end
-
!! article
Template:commenttest
!! text
@@ -11171,7 +11913,7 @@ pre-save transform: comment in subst (bug 1936)
pst
!! wikitext
{{subst:commenttest}}
-!! html
+!! html/php
This template has in it.
!! end
@@ -11181,7 +11923,7 @@ pre-save transform: unclosed tag
pst noxml
!! wikitext
'''not wiki'''
-!! html
+!! html/php
'''not wiki'''
!! end
@@ -11191,7 +11933,7 @@ pre-save transform: mixed tag case
pst noxml
!! wikitext
'''not wiki'''
-!! html
+!! html/php
'''not wiki'''
!! end
@@ -11201,7 +11943,7 @@ pre-save transform: unclosed comment in
pst noxml
!! wikitext
wikinowiki
-!! html
+!! html/php
!!end
@@ -11239,7 +11981,7 @@ pre-save transform: comment containing extension
pst
!! wikitext
-!! html
+!! html/php
!!end
@@ -11249,7 +11991,7 @@ pre-save transform: comment containing nowiki
pst
!! wikitext
-!! html
+!! html/php
!!end
@@ -11259,7 +12001,7 @@ pre-save transform: in subst (bug 3298)
pst
!! wikitext
{{subst:Includes}}
-!! html
+!! html/php
Foobar
!! end
@@ -11269,7 +12011,7 @@ pre-save transform: in subst (bug 3298)
pst
!! wikitext
{{subst:Includes2}}
-!! html
+!! html/php
Foo
!! end
@@ -11291,7 +12033,7 @@ bug 22297: safesubst: works during PST
pst
!! wikitext
{{subst:SafeSubstTest}}{{safesubst:SubstTest}}
-!! html
+!! html/php
FoobarFoobar
!! end
@@ -11327,7 +12069,7 @@ pst
[[|Article (context)]]
[[Bar:X (Y) Z|]]
[[:Bar:X (Y) Z|]]
-!! html
+!! html/php
[[Article (context)|Article]]
[[Bar:Article|Article]]
[[:Bar:Article|Article]]
@@ -11348,7 +12090,7 @@ pst
[[:interwiki:Article|]]
[[interwiki:Bar:Article|]]
[[:interwiki:Bar:Article|]]
-!! html
+!! html/php
[[interwiki:Article|Article]]
[[:interwiki:Article|Article]]
[[interwiki:Bar:Article|Bar:Article]]
@@ -11361,7 +12103,7 @@ pre-save transform: context links ("pipe trick") with parens in title
pst title=[[Somearticle (context)]]
!! wikitext
[[|Article]]
-!! html
+!! html/php
[[Article (context)|Article]]
!! end
@@ -11373,7 +12115,7 @@ pst title=[[Someplace, Somewhere]]
[[|Otherplace]]
[[Otherplace, Elsewhere|]]
[[Otherplace, Elsewhere, Anywhere|]]
-!! html
+!! html/php
[[Otherplace, Somewhere|Otherplace]]
[[Otherplace, Elsewhere|Otherplace]]
[[Otherplace, Elsewhere, Anywhere|Otherplace]]
@@ -11386,7 +12128,7 @@ pst title=[[Someplace (IGNORED), Somewhere]]
!! wikitext
[[|Otherplace]]
[[Otherplace (place), Elsewhere|]]
-!! html
+!! html/php
[[Otherplace, Somewhere|Otherplace]]
[[Otherplace (place), Elsewhere|Otherplace]]
!! end
@@ -11398,7 +12140,7 @@ pst title=[[Who, me? (context)]]
!! wikitext
[[|Yes, you.]]
[[Me, Myself, and I (1937 song)|]]
-!! html
+!! html/php
[[Yes, you. (context)|Yes, you.]]
[[Me, Myself, and I (1937 song)|Me, Myself, and I]]
!! end
@@ -11409,7 +12151,7 @@ pre-save transform: context links ("pipe trick") with namespace
pst title=[[Ns:Somearticle]]
!! wikitext
[[|Article]]
-!! html
+!! html/php
[[Ns:Article|Article]]
!! end
@@ -11419,7 +12161,7 @@ pre-save transform: context links ("pipe trick") with namespace and parens
pst title=[[Ns:Somearticle (context)]]
!! wikitext
[[|Article]]
-!! html
+!! html/php
[[Ns:Article (context)|Article]]
!! end
@@ -11429,7 +12171,7 @@ pre-save transform: context links ("pipe trick") with namespace and comma
pst title=[[Ns:Somearticle, Context, Whatever]]
!! wikitext
[[|Article]]
-!! html
+!! html/php
[[Ns:Article, Context, Whatever|Article]]
!! end
@@ -11439,7 +12181,7 @@ pre-save transform: context links ("pipe trick") with namespace, comma and paren
pst title=[[Ns:Somearticle, Context (context)]]
!! wikitext
[[|Article]]
-!! html
+!! html/php
[[Ns:Article (context)|Article]]
!! end
@@ -11449,7 +12191,7 @@ pre-save transform: context links ("pipe trick") with namespace, parens and comm
pst title=[[Ns:Somearticle (IGNORED), Context]]
!! wikitext
[[|Article]]
-!! html
+!! html/php
[[Ns:Article, Context|Article]]
!! end
@@ -11464,7 +12206,7 @@ pst
[[|Article(context)]]
[[Bar:X(Y)Z|]]
[[:Bar:X(Y)Z|]]
-!! html
+!! html/php
[[Article(context)|Article]]
[[Bar:Article(context)|Article]]
[[:Bar:Article(context)|Article]]
@@ -11484,7 +12226,7 @@ pst
[[|Article (context)]]
[[Bar:X (Y) Z|]]
[[:Bar:X (Y) Z|]]
-!! html
+!! html/php
[[Article (context)|Article]]
[[Bar:Article (context)|Article]]
[[:Bar:Article (context)|Article]]
@@ -11504,7 +12246,7 @@ pst
[[|Article(context)]]
[[Bar:X(Y)Z|]]
[[:Bar:X(Y)Z|]]
-!! html
+!! html/php
[[Article(context)|Article]]
[[Bar:Article(context)|Article]]
[[:Bar:Article(context)|Article]]
@@ -11524,7 +12266,7 @@ pst
[[Bar:Article (context),context|]]
[[:Bar:Article (context), context|]]
[[:Bar:Article (context),context|]]
-!! html
+!! html/php
[[Article (context), context|Article]]
[[Article (context),context|Article]]
[[Bar:Article (context), context|Article]]
@@ -11543,7 +12285,7 @@ Empty lines are trimmed
-!! html
+!! html/php
Empty lines are trimmed
!! end
@@ -11556,7 +12298,7 @@ pst
* ~~~
* ~~~
* ~~~
-!! html
+!! html/php
* [[Special:Contributions/127.0.0.1|127.0.0.1]]
* [[Special:Contributions/127.0.0.1|127.0.0.1]]
* [[Special:Contributions/127.0.0.1|127.0.0.1]]
@@ -11587,7 +12329,7 @@ As well as inside noinclude/onlyinclude
But not inside includeonly
{{subst:Foo}}
-!! html
+!! html/php
Shall not expand:
~~~~
@@ -11642,7 +12384,7 @@ parsoid=wt2html
Parsoid: Escape nowiki with trailing space in tags
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
<nowiki > foo </nowiki >
a<nowiki />b
c<nowiki/ >d
@@ -11658,7 +12400,7 @@ c<nowiki/ >d
Parsoid: Escape weird noWikI capitalizations
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
<noWikI > foo </NoWikI >
!! wikitext
<noWikI > foo </NoWikI >
@@ -11921,7 +12663,7 @@ parsoid=wt2html,wt2wt,html2html
!! html/parsoid
-This is a caption
+This is a caption
!! end
!! test
@@ -11932,7 +12674,7 @@ parsoid=wt2html,wt2wt,html2html
!! html/parsoid
-This is a caption
+This is a caption
!! end
!! test
@@ -11989,7 +12731,7 @@ thumbsize=220
!! html/parsoid
123 456
123
456
-123
456
+123
456
!! end
!! test
@@ -12011,7 +12753,7 @@ Image with multiple widths -- use last
!! html/parsoid
-
+
!! end
!! test
@@ -12027,7 +12769,7 @@ thumbsize=220
!! html/parsoid
-caption
+caption
!! end
@@ -12043,9 +12785,9 @@ Image with width attribute at different positions
!! html/parsoid
-Caption
-Caption
-Caption
+Caption
+Caption
+Caption
!! end
# a sad bit of backward-compatibility
@@ -12061,7 +12803,7 @@ parsoid=wt2html,wt2wt,html2html
!! html/parsoid
-
+
!! end
!! test
@@ -12100,7 +12842,22 @@ Image with link parameter, protocol-less URL target
!! end
!! test
-Image with link parameter, wgExternalLinkTarget
+Escaping non-block captions (T107435)
+!! options
+parsoid={
+ "modes": ["wt2wt"],
+ "changes": [
+ ["[typeof~='mw:Image']", "attr", "data-mw", "{\"caption\": \"|\"}"]
+ ]
+}
+!! wikitext
+[[Image:Foobar.jpg|caption]]
+!! wikitext/edited
+[[Image:Foobar.jpg|| ]]
+!! end
+
+!! test
+Image with link parameter, wgExternalLinkTarget
!! wikitext
[[Image:foobar.jpg|link=http://example.com/]]
!! config
@@ -12187,7 +12944,7 @@ parsoid=wt2html,wt2wt,html2html
!! html/parsoid
-Title
+Title
!! end
!! test
@@ -12287,8 +13044,6 @@ parsoid=wt2html,wt2wt,html2html
!! test
Image with wiki markup in implicit alt
-!! options
-parsoid=wt2html,wt2wt,html2html
!! wikitext
[[Image:Foobar.jpg|testing '''bold''' in alt]]
@@ -12298,8 +13053,8 @@ parsoid=wt2html,wt2wt,html2html
!! html/parsoid
-
-
+
+
!! end
!! test
@@ -12334,9 +13089,9 @@ parsoid=wt2html,wt2wt,html2html
!! html/parsoid
-
-
-
+
+
+
!! end
!! test
@@ -12372,15 +13127,15 @@ parsoid=wt2html,wt2wt,html2html
!! html/parsoid
-caption
-caption
-caption
+caption
+caption
+caption
!! end
###################
# Image sizing.
# See https://www.mediawiki.org/wiki/Help:Images#Size_and_frame
-# and https://bugzilla.wikimedia.org/show_bug.cgi?id=62258
+# and https://phabricator.wikimedia.org/T64258
# Foobar has actual size of 1941x220
# 1. Thumbs & frameless always reduce, can't be enlarged unless it's
# a scalable format.
@@ -12401,8 +13156,8 @@ parsoid=wt2html,wt2wt,html2html
!! html/parsoid
-
-
+
+
!! end
!! test
@@ -12418,8 +13173,8 @@ parsoid=wt2html,wt2wt,html2html
!! html/parsoid
-
-
+
+
!! end
!! test
@@ -12432,7 +13187,7 @@ parsoid=wt2html,wt2wt,html2html
!! html/parsoid
-
+
!! end
!! test
@@ -12448,8 +13203,8 @@ parsoid=wt2html,wt2wt,html2html
!! html/parsoid
-
-
+
+
!! end
!! test
@@ -12462,7 +13217,7 @@ parsoid=wt2html,wt2wt,html2html
!! html/parsoid
-
+
!! end
!! test
@@ -12478,8 +13233,8 @@ parsoid=wt2html,wt2wt,html2html
!! html/parsoid
-
-
+
+
!! end
!! test
@@ -12537,7 +13292,7 @@ Frameless image caption with a free URL
!! html/parsoid
-
+
!! end
!! test
@@ -12550,7 +13305,7 @@ thumbsize=220
!! html/parsoid
-http://example.com
+http://example.com
!! end
!! test
@@ -12564,7 +13319,7 @@ parsoid=wt2html,wt2wt,html2html
!! html/parsoid
-http://example.com
+http://example.com
!! end
!! test
@@ -12576,7 +13331,7 @@ SVG thumbnails with no language set
!! html/parsoid
-caption
+caption
!! end
!! test
@@ -12589,7 +13344,7 @@ parsoid=wt2html,wt2wt,html2html
!! html/parsoid
-caption
+caption
!! end
!! test
@@ -12613,7 +13368,7 @@ BUG 1887: A ISBN with a thumbnail
!! html/parsoid
-ISBN 1235467890
+ISBN 1235467890
!! end
!! test
@@ -12624,7 +13379,7 @@ BUG 1887: A RFC with a thumbnail
!! html/parsoid
-This is RFC 12354
+This is RFC 12354
!! end
!! test
@@ -12635,7 +13390,7 @@ BUG 1887: A mailto link with a thumbnail
!! html/parsoid
-Please mailto:nobody@example.com
+Please mailto:nobody@example.com
!! end
# Pending resolution to bug 368
@@ -12647,7 +13402,7 @@ BUG 648: Frameless image caption with a link
!! html/parsoid
-
+
!! end
!! test
@@ -12658,7 +13413,7 @@ BUG 648: Frameless image caption with a link (suffix)
!! html/parsoid
-
+
!! end
!! test
@@ -12669,7 +13424,7 @@ BUG 648: Frameless image caption with an interwiki link
!! html/parsoid
-
+
!! end
!! test
@@ -12680,7 +13435,15 @@ BUG 648: Frameless image caption with a piped interwiki link
!! html/parsoid
-
+
+!! end
+
+!! test
+T107474: Frameless image caption with
+!! wikitext
+[[File:Foobar.jpg|text with a [[MeatBall:Link|link]] in it ]]
+!! html/parsoid
+
!! end
!! test
@@ -12691,7 +13454,7 @@ Escape HTML special chars in image alt text
!! html/parsoid
-
+
!! end
!! test
@@ -12702,7 +13465,7 @@ BUG 499: Alt text should have Ӓ, not &1234;
!! html/parsoid
-
+
!! end
!! test
@@ -12726,7 +13489,7 @@ Image caption containing another image
This is a caption with another
inside it!
!! html/parsoid
-This is a caption with another inside it!
+This is a caption with another inside it!
!! end
!! test
@@ -12750,7 +13513,7 @@ Image: caption containing leading space
!! html/parsoid
- bar
+ bar
!!end
!! test
@@ -12769,7 +13532,7 @@ and some more text.]]
This is an example image thumbnail caption with a table
and some more text.
!! html/parsoid
-This is an example image thumbnail caption with a table
+This is an example image thumbnail caption with a table
Foo Bar
@@ -12786,7 +13549,7 @@ Bug 3090: External links other than http: in image captions
This caption has
irc and
Secure ext links in it.
!! html/parsoid
-This caption has irc and Secure ext links in it.
+This caption has irc and Secure ext links in it.
!! end
!! test
@@ -12828,7 +13591,7 @@ language=es
!! html/parsoid
-caption
+caption
!! end
!! test
@@ -12842,7 +13605,7 @@ parsoid=wt2html,wt2wt,html2html
!! html/parsoid
-
+
!! end
# Note that 'right' is the default alignment, despite the misspelled 'righ' below
@@ -12863,9 +13626,9 @@ parsoid=wt2html,wt2wt,html2html
!! html/parsoid
-caption
-caption
-caption
+caption
+caption
+caption
!! end
!! article
@@ -12910,7 +13673,7 @@ Parsoid-specific image handling - simple image with size and middle alignment
!! wikitext
[[File:Foobar.jpg|middle|50px]]
!! html/parsoid
-
+
!! end
!! test
@@ -12921,7 +13684,7 @@ parsoid=wt2wt,wt2html,html2html
!! wikitext
[[Image:Foobar.jpg|middle|50px]]
!! html/parsoid
-
+
!! end
!! test
@@ -12930,7 +13693,7 @@ Parsoid-specific image handling - simple image with size and middle alignment
!! wikitext
[[File:Foobar.jpg|50px|middle]]
!! html/parsoid
-
+
!! end
!! test
@@ -12941,7 +13704,7 @@ parsoid=wt2html,wt2wt,html2html
!! wikitext
[[Image:Foobar.jpg|50px|middle]]
!! html/parsoid
-
+
!! end
!! test
@@ -12965,7 +13728,7 @@ Parsoid-specific image handling - thumbnail with halign, valign, and caption
!! wikitext
[[File:Foobar.jpg|left|baseline|thumb|caption content]]
!! html/parsoid
-caption content
+caption content
!! end
!! test
@@ -12974,7 +13737,7 @@ Parsoid-specific image handling - thumbnail with halign, valign, and caption
!! wikitext
[[File:Foobar.jpg|thumb|left|baseline|caption content]]
!! html/parsoid
-caption content
+caption content
!! end
!! test
@@ -12982,7 +13745,7 @@ Parsoid-specific image handling - thumbnail with specific size, halign, valign,
!! wikitext
[[Image:Foobar.jpg|right|middle|thumb|50x50px|caption]]
!! html/parsoid
-caption
+caption
!! end
!! test
@@ -13029,7 +13792,7 @@ Parsoid-specific image handling - simple image with a formatted caption
!! wikitext
[[File:Foobar.jpg|]]
!! html/parsoid
-
+
!! end
!! test
@@ -13050,7 +13813,7 @@ foo
bar
!! html/parsoid
foo
-This caption has a unbalanced tag in it.
+This caption has a unbalanced tag in it.
bar
!! end
@@ -13061,7 +13824,7 @@ parsoid=wt2html,wt2wt
!! wikitext
[[File:Foobar.jpg|thumb|]]
!! html/parsoid
-
+
!! end
# empty captions don't get serialized unless we're in the "round trip" case
@@ -13088,7 +13851,7 @@ Parsoid-specific image handling - whitespace caption
!! wikitext
[[File:Foobar.jpg|thumb| ]]
!! html/parsoid
-
+
!! end
!! test
@@ -13103,6 +13866,42 @@ bar
bar
!! end
+## Edge case bugs in Parsoid from T93580
+!! test
+T93580: 1. Templated [ inside block images
+!! wikitext
+[[File:Foobar.jpg|thumb|Caption with templated ref: {{echo|][foo]}}]]
+
+
+!! html/parsoid
+Caption with templated ref: [1]
+
+↑ foo
+!! end
+
+!! test
+T93580: 2. [ inside inline images
+!! wikitext
+[[File:Foobar.jpg|Undisplayed caption in inline image with ref: ][foo]]]
+
+
+!! html/parsoid
+
+
+↑ foo
+!! end
+
+!! test
+T93580: 3. Templated [ inside inline images
+!! wikitext
+[[File:Foobar.jpg|Undisplayed caption in inline image with ref: {{echo|][{{echo|foo}}]}}]]
+
+
+!! html/parsoid
+
+
+↑ foo
+!! end
###
### Subpages
@@ -13435,6 +14234,152 @@ Bar
!! end
+## The whitespace on the empty line is part of the test. Please do not delete
+!! test
+1. Categories and newlines: All preceding newlines should be suppressed (courtesy bug 87)
+!! options
+parsoid=wt2html,wt2wt
+!! wikitext
+This
+
+[[Category:Foo]] and this should be part of same paragraph (not an indent-pre)
+
+{{echo|[[Category:Foo]] and so should this!}}
+!! html
+This and this should be part of same paragraph (not an indent-pre) and so should this!
+
+!! html/parsoid
+This
+
+ and this should be part of same paragraph (not an indent-pre)
+
+ and so should this!
+!! end
+
+## Parsoid will not try to wt2wt this while preserving newlines because
+## it suppresses excess newlines within list items -- and we don't want to
+## introduce a special case just for categories, which is, in reality somewhat
+## odd behavior -- categories are unlikely to be used in list items like this
+## in top-level pages and are only likely to show up in template-generated
+## list items where this RT-ing is a non-issue.
+##
+## The whitespace on the empty line is part of the test. Please do not delete
+!! test
+2. Categories and newlines: All preceding newlines should be suppressed (courtesy bug 87)
+!! options
+parsoid=wt2html
+!! wikitext
+* This
+
+[[Category:Foo]] and this should be part of the same list item
+* So should this
+
+{{echo|[[Category:Foo]] and this should be part of the same list item}}
+!! html
+This and this should be part of the same list item
+So should this and this should be part of the same list item
+!! html/parsoid
+
+This and this should be part of the same list item
+So should this and this should be part of the same list item
+
+!! end
+
+## Newlines and categories that follow the last item of a list
+## are treated differently because this (list followed by categories)
+## is an extremely common pattern on wikis.
+!! test
+3. Categories and newlines: newline suppression for last list item should RT properly
+!! wikitext
+* a
+* b
+
+[[Category:Foo]]
+
+[[Category:Bar]]
+[[Category:Baz]]
+!! html/parsoid
+
+
+
+
+
+
+!! end
+
+!! test
+4. Categories and newlines: newline suppression for last list item should RT properly
+!! wikitext
+* a
+**** b
+
+[[Category:Foo]]
+!! html/parsoid
+
+
+
+!! end
+
+## only wt2html for this to make sure the algo only applies to the rightmost path
+!! test
+5. Categories and newlines: migrateTrailingCategories dom pass should only run on the rightmost path of nested lists
+!! options
+parsoid=wt2html
+!! wikitext
+* a
+** b
+[[Category:Foo]]
+* c
+** d
+[[Category:Foo]]
+!! html/parsoid
+
+
+!! end
+
+!! test
+6. Categories and newlines: migrateTrailingCategories dom pass should not migrate categories not preceded by newlines
+!! wikitext
+* a [[Category:Foo]]
+!! html/parsoid
+
+!! end
+
+# This test also demonstrates because of newline+category tunneling
+# through the list hander, template wrapping doesn't expand to the
+# containing list when the list item swallows the category.
+!! test
+7. Categories and newlines: migrateTrailingCategories dom pass should leave template content alone
+!! wikitext
+* {{echo|a
+[[Category:Foo]]}}
+!! html/parsoid
+
+!! end
+
+!! test
+8. Categories and newlines: migrateTrailingCategories dom pass should not get tripped by intervening templates
+!! wikitext
+* a
+
+{{echo|[[Category:Foo]]
+[[Category:Bar]]}}
+[[Category:Baz]]
+!! html/parsoid
+
+
+
+
+
+!! end
+
!! test
Parsoid: Serialize link to category page with colon escape
!! options
@@ -13445,20 +14390,26 @@ parsoid
[[:Category:Foo|Bar]]
!! html
-Category:Foo
-Bar
+Category:Foo
+Bar
!! end
+# html2wt localizes the "Category" namespace.
+# XXX the element needs an empty data-parsoid attribute, or
+# else the html2html test fails because spaces are inserted.
!! test
-Parsoid: Link prefix/suffixes aren't applied to category links
+Link prefix/suffixes aren't applied to category links
!! options
parsoid=wt2html,wt2wt,html2html
language=is
!! wikitext
x[[Category:Foo]]y
-!! html
-x y
+!! html/php
+xy
+
+!! html/parsoid
+x y
!! end
!! test
@@ -13484,15 +14435,15 @@ parsoid
[[Category:Foo]]
[[Category:Foo|Bar]]
!! html
-
-
+
+
!! end
!! test
Normalize hrefs properly before testing for invalid link targets (bug 70894)
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
!! wikitext
[[Category:Toxine bactérienne]]
@@ -13630,7 +14581,7 @@ __FORCETOC__
== Headline ==
== Headline 2 ==
== Headline ==
-!! html
+!! html/php
Contents
1 Headline 2
@@ -13744,6 +14695,22 @@ TOC regression (T11764)
!! end
+!! test
+TOC for heading containing (T96153)
+!! wikitext
+__FORCETOC__
+== New title==
+!! html/php
+
+
+ New title[ edit ]
+
+!! end
+
!! test
TOC with wgMaxTocLevel=3 (bug 6204)
!! options
@@ -14376,11 +15343,8 @@ I always thought &xacute; was a cute letter.
!! end
-# TODO: generalize to PHP parser?
!! test
HTML5 tags
-!! options
-parsoid
!! wikitext
five
The new millenium started
@@ -14388,7 +15352,8 @@ parsoid
!! html
five
The new millenium started
-This highlighted text
+This highlighted text
+
!! end
!! test
@@ -14628,13 +15593,19 @@ Attribute test: unquoted but illegal value (hash)
!! end
+# Parsoid does not serialize to empty attribute syntax,
+# so wt2wt and html2wt cases are skipped
!! test
-Attribute test: no value
+Attribute test: no value (T54330)
+!! options
+parsoid=wt2html,html2html
!! wikitext
foo
-!! html
-foo
+!! html/php
+
foo
+!! html/parsoid
+foo
!! end
!! test
@@ -14932,6 +15903,7 @@ MSIE 6 CSS safety test: sup/sub script (bug 55332)
!! end
+# FIXME: Parsoid fails to sanitize this! See T58846.
!! test
Opera -o-link CSS
!! wikitext
@@ -15006,7 +15978,7 @@ CSS line continuation 2
!! wikitext
!! html
-
+
!! end
@@ -15063,7 +16035,7 @@ evil -wiki-tags without Extension:Math enabled
Parser hook: empty input
!! wikitext
-!! html
+!! html/php
''
array (
@@ -15076,7 +16048,7 @@ array (
Parser hook: empty input using terminated empty elements
!! wikitext
-!! html
+!! html/php
NULL
array (
@@ -15089,7 +16061,7 @@ array (
Parser hook: empty input using terminated empty elements (space before)
!! wikitext
-!! html
+!! html/php
NULL
array (
@@ -15102,7 +16074,7 @@ array (
Parser hook: basic input
!! wikitext
input
-!! html
+!! html/php
'input'
array (
@@ -15116,7 +16088,7 @@ array (
Parser hook: case insensitive
!! wikitext
input
-!! html
+!! html/php
'input'
array (
@@ -15130,7 +16102,7 @@ array (
Parser hook: case insensitive, redux
!! wikitext
input
-!! html
+!! html/php
'input'
array (
@@ -15145,7 +16117,7 @@ Parser hook: nested tags
noxml
!! wikitext
-!! html
+!! html/php
''
array (
@@ -15158,14 +16130,14 @@ array (
Parser hook: basic arguments
!! wikitext
-!! html
+!! html/php
''
array (
'width' => '200',
'height' => '100',
'depth' => '50',
- 'square' => 'square',
+ 'square' => '',
)
@@ -15175,7 +16147,7 @@ array (
Parser hook: argument containing a forward slash (bug 5344)
!! wikitext
-!! html
+!! html/php
''
array (
@@ -15189,7 +16161,7 @@ array (
Parser hook: empty input using terminated empty elements (bug 2374)
!! wikitext
text
-!! html
+!! html/php
NULL
array (
@@ -15206,14 +16178,14 @@ Parser hook: basic arguments using terminated empty elements (bug 2374)
other stuff
-!! html
+!! html/php
NULL
array (
'width' => '200',
'height' => '100',
'depth' => '50',
- 'square' => 'square',
+ 'square' => '',
)
other stuff
@@ -15230,7 +16202,7 @@ Parser hook: static parser hook not inside a comment
!! wikitext
hello, world
-!! html
+!! html/php
hello, world
!! end
@@ -15241,7 +16213,7 @@ Parser hook: static parser hook inside a comment
!! wikitext
-!! html
+!! html/php
!! end
@@ -15300,20 +16272,24 @@ Sanitizer: Closing of open but not closed tags
!! test
Sanitizer: Closing of closed but not open tags
+!! options
+parsoid=wt2html
!! wikitext
-!! html
-</s>
-
+!! html/php+tidy
+!! html/parsoid
!! end
!! test
Sanitizer: Closing of closed but not open table tags
+!! options
+parsoid=wt2html
!! wikitext
Table not started
-!! html
-Table not started</td></tr></table>
-
+!! html/php+tidy
+Table not started
+!! html/parsoid
+Table not started
!! end
!! test
@@ -15360,7 +16336,7 @@ Sanitizer: Validating that and work, but only for Microdata
!! html
-
+
<meta http-equiv="refresh" content="5">
@@ -16112,7 +17088,7 @@ start
===bc===
==c==
===ca===
-!! html
+!! html/php
start
!! end
@@ -16132,7 +17108,7 @@ start
===bc===
==c==
===ca===
-!! html
+!! html/php
==a==
===aa===
====aaa====
@@ -16154,7 +17130,7 @@ start
===bc===
==c==
===ca===
-!! html
+!! html/php
===aa===
====aaa====
!! end
@@ -16175,7 +17151,7 @@ start
===bc===
==c==
===ca===
-!! html
+!! html/php
====aaa====
!! end
@@ -16195,7 +17171,7 @@ start
===bc===
==c==
===ca===
-!! html
+!! html/php
==b==
===ba===
===bb===
@@ -16219,7 +17195,7 @@ start
===bc===
==c==
===ca===
-!! html
+!! html/php
===ba===
!! end
@@ -16239,7 +17215,7 @@ start
===bc===
==c==
===ca===
-!! html
+!! html/php
===bb===
====bba====
!! end
@@ -16260,7 +17236,7 @@ start
===bc===
==c==
===ca===
-!! html
+!! html/php
====bba====
!! end
@@ -16280,7 +17256,7 @@ start
===bc===
==c==
===ca===
-!! html
+!! html/php
===bc===
!! end
@@ -16300,7 +17276,7 @@ start
===bc===
==c==
===ca===
-!! html
+!! html/php
==c==
===ca===
!! end
@@ -16321,7 +17297,7 @@ start
===bc===
==c==
===ca===
-!! html
+!! html/php
===ca===
!! end
@@ -16341,7 +17317,7 @@ start
===bc===
==c==
===ca===
-!! html
+!! html/php
!! end
!! test
@@ -16352,7 +17328,7 @@ section=1
==a==
==bogus== not a legal section
==b==
-!! html
+!! html/php
==a==
==bogus== not a legal section
!! end
@@ -16365,7 +17341,7 @@ section=2
==a==
==bogus== not a legal section
==b==
-!! html
+!! html/php
==b==
!! end
@@ -16377,7 +17353,7 @@ section=1
==a==
==b==
==c==
-!! html
+!! html/php
==a==
!! end
@@ -16389,7 +17365,7 @@ section=2
==a==
==b==
==c==
-!! html
+!! html/php
==b==
!! end
@@ -16401,7 +17377,7 @@ section=1
==a==
==bogus== not a legal section
==b==
-!! html
+!! html/php
==a==
==bogus== not a legal section
!! end
@@ -16414,11 +17390,10 @@ section=2
==a==
==bogus== not a legal section
==b==
-!! html
+!! html/php
==b==
!! end
-
# Formerly testing for bug 2587, now resolved by the use of unmarked sections
# instead of respecting commented sections
!! test
@@ -16428,7 +17403,7 @@ section=1
!! wikitext
==sec1==
==sec2==
-!! html
+!! html/php
==sec2==
!!end
@@ -16439,11 +17414,10 @@ section=2
!! wikitext
==sec1==
==sec2==
-!! html
+!! html/php
!!end
-
# Formerly testing for bug 2607, now resolved by the use of unmarked sections
# instead of respecting HTML-style headings
!! test
@@ -16457,7 +17431,7 @@ unmarked
one
==2==
two
-!! html
+!! html/php
==1==
one
!! end
@@ -16473,7 +17447,7 @@ unmarked
one
==2==
two
-!! html
+!! html/php
==2==
two
!! end
@@ -16487,7 +17461,7 @@ section=1
!! wikitext
==unmarked==
==marked==
-!! html
+!! html/php
==marked==
!!end
@@ -16502,7 +17476,7 @@ The line above must have a trailing space
===
But just in case it doesn't...
-!! html
+!! html/php
===
But just in case it doesn't...
@@ -16524,7 +17498,7 @@ start
===bc===
==c==
===ca===
-!! html
+!! html/php
xxx
==a==
@@ -16555,7 +17529,7 @@ start
===bc===
==c==
===ca===
-!! html
+!! html/php
start
xxx
@@ -16584,7 +17558,7 @@ start
===bc===
==c==
===ca===
-!! html
+!! html/php
start
==a==
xxx
@@ -16614,7 +17588,7 @@ start
===bc===
==c==
===ca===
-!! html
+!! html/php
start
==a==
===aa===
@@ -16645,7 +17619,7 @@ start
===bc===
==c==
===ca===
-!! html
+!! html/php
start
==a==
===aa===
@@ -16672,7 +17646,7 @@ start
===bc===
==c==
===ca===
-!! html
+!! html/php
start
==a==
===aa===
@@ -16703,7 +17677,7 @@ start
===bc===
==c==
===ca===
-!! html
+!! html/php
start
==a==
===aa===
@@ -16733,7 +17707,7 @@ start
===bc===
==c==
===ca===
-!! html
+!! html/php
start
==a==
===aa===
@@ -16764,7 +17738,7 @@ start
===bc===
==c==
===ca===
-!! html
+!! html/php
start
==a==
===aa===
@@ -16795,7 +17769,7 @@ start
===bc===
==c==
===ca===
-!! html
+!! html/php
start
==a==
===aa===
@@ -16824,7 +17798,7 @@ start
===bc===
==c==
===ca===
-!! html
+!! html/php
start
==a==
===aa===
@@ -16846,7 +17820,7 @@ replace=2,"xxx"
Preformatted initial line
==a==
===a===
-!! html
+!! html/php
Preformatted initial line
==a==
xxx
@@ -16860,7 +17834,7 @@ section=1
!! wikitext
==a==
a
-!! html
+!! html/php
==a==
a
!! end
@@ -16872,7 +17846,7 @@ section=1
!! wikitext
==a==
a
-!! html
+!! html/php
==a==
a
!! end
@@ -16890,7 +17864,7 @@ noxml section=2
== Section Two ==
stuff
-!! html
+!! html/php
== Section Two ==
stuff
!! end
@@ -16907,7 +17881,7 @@ noxml replace=2,"xxx"
== Section Two ==
stuff
-!! html
+!! html/php
== Section One ==
=======
@@ -16917,7 +17891,6 @@ xxx
!! end
-
!! test
Handling of
in URLs
!! wikitext
@@ -17338,12 +18311,44 @@ parsoid=wt2html,wt2wt,html2html
î î
!! end
+# See: http://www.w3.org/TR/html5/syntax.html#character-references
+# Note that U+000C (form feed) is not a valid XML character, so
+# it is banned even though allowed in HTML5.
+!! test
+Illegal character references (T106578)
+!! wikitext
+; Null:
+; FF:
+; CR:
+; Control (low):
+; Control (high):
+; Surrogate:
+; This is an okay astral character: 💩
+!! html+tidy
+
+Null
+�
+FF
+
+CR
+
+Control (low)
+
+Control (high)
+ Ÿ
+Surrogate
+��
+This is an okay astral character
+💩
+
+!! end
+
!! test
__FORCETOC__ override
!! wikitext
__NEWSECTIONLINK__
__FORCETOC__
-!! html
+!! html/php
!! end
@@ -17358,7 +18363,7 @@ ISBN 978-0-1234-56 789
!! html+tidy
ISBN 978-0-1234-56 789
!! html/parsoid
-
ISBN 978-0-1234-56 789
+
ISBN 978-0-1234-56 789
!! end
!! test
@@ -17378,24 +18383,34 @@ ISBN ISBN 1234567890
ISBN ISBN 1234567890
!! html/parsoid
-
ISBN ISBN 1234567890
+
ISBN ISBN 1234567890
!! end
+# Uppercase X and lowercase x as well
!! test
ISBN with an X
!! wikitext
ISBN 3-462-04561-X
+ISBN 3-462-04561-x
ISBN 080442957X
+ISBN 080442957x
ISBN 978080442957X
+ISBN 978080442957x
!! html/php
ISBN 3-462-04561-X
+ISBN 3-462-04561-x
ISBN 080442957X
+ISBN 080442957x
ISBN 978080442957X
+ISBN 978080442957x
!! html/parsoid
-
ISBN 3-462-04561-X
-ISBN 080442957X
-ISBN 978080442957X
+
ISBN 3-462-04561-X
+ISBN 3-462-04561-x
+ISBN 080442957X
+ISBN 080442957x
+ISBN 978080442957X
+ISBN 978080442957x
!! end
!! test
@@ -17406,7 +18421,7 @@ ISBN 1234567890
ISBN 1234567890
!! html/parsoid
-
ISBN 1234567890
+
ISBN 1234567890
!! end
!! test
@@ -17417,7 +18432,7 @@ Bug 22905:
followed by ISBN followed by
(fr) ISBN 2753300917 example.com
!! html/parsoid
-(fr) ISBN 2753300917 example.com
+(fr) ISBN 2753300917 example.com
!! end
!! test
@@ -17548,7 +18563,7 @@ Images with the "|" character in the comment
!! html/parsoid
-An external URL
+An external URL
!! end
!! test
@@ -17704,7 +18719,7 @@ Don't fall for the self-closing div
MSGNW magic word
!! wikitext
{{MSGNW:msg}}
-!! html
+!! html/php
[[:Template:Msg]]
!! end
@@ -18293,6 +19308,61 @@ Raw: -{R|zh:China;zh-tw:Taiwan}-
!! end
+!! test
+Strings evaluating false shouldn't be ignored by Language converter (T51072)
+!! options
+language=zh variant=zh-cn
+!! input
+-{zh-cn:0;zh-sg:1;zh-tw:2;zh-hk:3}-
+!! result
+0
+
+!! end
+
+!! test
+Conversion rules from [numeric-only string] to [something else] (T48634)
+!! options
+language=zh variant=zh-cn
+!! input
+-{H|0=>zh-cn:B}--{H|0=>zh-cn:C;0=>zh-cn:D}--{H|0=>zh-hans:A}-012345-{A|zh-tw:0;zh-cn:E;}-012345
+!! result
+D12345EE12345
+
+!! end
+
+!! test
+Bidirectional converter rule entries with an empty value should be ignored (T53551)
+!! options
+language=zh variant=zh-cn
+!! input
+-{H|zh-cn:foo;zh-tw:;}-foobar
+!! result
+foobar
+
+!! end
+
+!! test
+Unidirectional converter rule entries with an empty "from" string should be ignored (T53551)
+!! options
+language=zh variant=zh-cn
+!! input
+-{H|=>zh-cn:foo;}-foobar
+!! result
+foobar
+
+!! end
+
+!! test
+Empty converter rule entries shouldn't be inserted into the conversion table (T53551)
+!! options
+language=zh variant=zh-cn
+!! input
+-{H|}-foobar
+!! result
+foobar
+
+!! end
+
!! test
Nested using of manual convert syntax
!! options
@@ -19038,7 +20108,7 @@ percent-encoding and + signs in comments (Bug 26410)
comment
!! wikitext
[[ABC%33D% ++]] [[ABC%33D% ++|+%20]]
-!! html
+!! html/php
ABC3D% ++ +%20
!! end
@@ -19082,7 +20152,7 @@ wgAllowDisplayTitle=true
wgRestrictDisplayTitle=false
!! wikitext
this is not the the title
-!! html
+!! html/php
Parser test
this is not the the title
@@ -19099,7 +20169,7 @@ wgRestrictDisplayTitle=false
!! wikitext
this is not the the title
{{DISPLAYTITLE:whatever}}
-!! html
+!! html/php
whatever
this is not the the title
@@ -19116,7 +20186,7 @@ wgRestrictDisplayTitle=true
!! wikitext
this is not the the title
{{DISPLAYTITLE:whatever}}
-!! html
+!! html/php
Screen
this is not the the title
@@ -19133,7 +20203,7 @@ wgRestrictDisplayTitle=true
!! wikitext
this is not the the title
{{DISPLAYTITLE:screen}}
-!! html
+!! html/php
screen
this is not the the title
@@ -19149,7 +20219,7 @@ wgAllowDisplayTitle=false
!! wikitext
this is not the the title
{{DISPLAYTITLE:screen}}
-!! html
+!! html/php
Screen
this is not the the title
Template:DISPLAYTITLE:screen
@@ -19165,7 +20235,7 @@ title=[[Screen]]
wgAllowDisplayTitle=false
!! wikitext
this is not the the title
-!! html
+!! html/php
Screen
this is not the the title
@@ -19182,7 +20252,7 @@ wgRestrictDisplayTitle=true
!! wikitext
this is not the the title
{{DISPLAYTITLE:s creen}}
-!! html
+!! html/php
s creen
this is not the the title
@@ -19199,7 +20269,7 @@ wgRestrictDisplayTitle=true
!! wikitext
this is not the the title
{{DISPLAYTITLE:s creen}}
-!! html
+!! html/php
s creen
this is not the the title
@@ -19224,7 +20294,7 @@ Page status indicators: Weird syntaxes that are okay
showindicators
!! wikitext
-
+
!! html
empty=
name=
@@ -19287,7 +20357,7 @@ preload: check and
preload
!! wikitext
Hello cruel kind world.
-!! html
+!! html/php
Hello kind world.
!! end
@@ -19297,7 +20367,7 @@ preload: check
preload
!! wikitext
Goodbye Hello world
-!! html
+!! html/php
Hello world
!! end
@@ -19307,7 +20377,7 @@ preload: can pass tags through if we want to
preload
!! wikitext
< includeonly>Hello world< /includeonly>
-!! html
+!! html/php
Hello world
!! end
@@ -19317,7 +20387,7 @@ preload: check that it doesn't try to do tricks
preload
!! wikitext
* ''{{world}}'' {{subst: How are you}}{{ {{{|safesubst:}}} #if:1|2|3}}
-!! html
+!! html/php
* ''{{world}}'' {{subst:How are you}}{{ {{{|safesubst:}}} #if:1|2|3}}
!! end
@@ -19368,7 +20438,10 @@ percent-encoding and + signs in internal links (Bug 26410)
3E 3E+
!! html/parsoid
-User:+% Page+title% %+ %20 %+ %+r % + 3E 3E+
+User:+% Page+title%
+%+ %20 %+ %+r
+% +
+3E 3E+
!! end
!! test
@@ -19382,7 +20455,7 @@ Special characters in embedded file links (bug 27679)
!! html/parsoid
-
+
!! end
!! test
@@ -19653,14 +20726,18 @@ __TOC__
[ edit ]
!! end
+# Don't expect Parsoid to roundtrip this until the php parser comes closer to
+# html5 tag parsing.
!! test
Tags with parameters in TOC
+!! options
+parsoid=wt2html
!! wikitext
__TOC__
== Hello ==
== Evilbye ==
-!! html
+!! html/php
Contents
1 Hello
@@ -19669,8 +20746,13 @@ __TOC__
- b">Evilbye [ edit ]
+ b">Evilbye [ edit ]
+
+!! html/parsoid
+
+ Hello
+ b">Evilbye
!! end
!! test
@@ -19775,10 +20857,12 @@ Strip marker in urlencode
{{urlencode:x y}}
{{urlencode:x y|wiki}}
{{urlencode:x y|path}}
+{{urlencode:xtwo y}}
!! html
xy
xy
xy
+xy
!! end
@@ -20137,10 +21221,35 @@ parsoid=wt2html,wt2wt
[[Image:Foobar.jpg|right|300px]]
!! html/parsoid
+
foo
-caption
+caption
bar
-
+
+!! end
+
+!! test
+3. Bad treebuilder fixup of formatting elt is cleaned up
+!! options
+parsoid=wt2html,wt2wt
+!! wikitext
+'''foo[[File:Foobar.jpg|thumb|caption]]bar'''
+!! html/parsoid
+foo
+caption
+bar
+!! end
+
+!! test
+4. Bad treebuilder fixup of formatting elt is cleaned up: formatting tags around captionless images are ignored
+!! options
+parsoid=wt2html,wt2wt
+!! wikitext
+'''[[Image:Foobar.jpg|right|300px]] '''
+!! html/parsoid
+
+
+
!! end
#### ----------------------------------------------------------------
@@ -20159,13 +21268,13 @@ B [foo]
C
!! html
-A [1]
-B [2]
-C [3]
-
-↑ foo
-↑ foo
-↑
+A [1]
+B [2]
+C [3]
+
+↑ foo
+↑ foo
+↑
!!end
@@ -20178,10 +21287,10 @@ A [foo]
B
!! html
-A [1]
-B [1]
-
-↑ 1.0 1.1 foo
+A [1]
+B [1]
+
+1 2 foo
!!end
@@ -20195,11 +21304,11 @@ B
C
!! html
-A [1]
-B [1]
-C [1]
-
-↑ 1.0 1.1 1.2 foo
+A [1]
+B [1]
+C [1]
+
+1 2 3 foo
!!end
@@ -20212,9 +21321,9 @@ parsoid
A [foo]
!! html
-A [1]
-
-↑ foo
+A [1]
+
+↑ foo
!!end
@@ -20229,10 +21338,10 @@ A [
]
!! html
-A [1]
+A [1]
-
-↑ This is a bolded link and this is a transclusion
+
+↑ This is a bolded link and this is a transclusion
!!end
@@ -20250,10 +21359,10 @@ A [
]
!! html
-A [1]
+A [1]
-
-↑ foo
+
+↑ foo
bar
baz
@@ -20280,10 +21389,10 @@ booz
!! html
-A [1]
+A [1]
-
-↑ foo
+
+↑ foo
bar
@@ -20306,9 +21415,9 @@ A [ foo {{echo|] B C}}
!! html
-A [1] B C}}
-
-↑ foo {{ echo|
+A [1] B C}}
+
+↑ foo {{ echo|
!!end
@@ -20320,9 +21429,9 @@ parsoid
A [ foo ]
+A [1] B C
+
+↑ foo
!!end
@@ -20335,11 +21444,11 @@ A [ ] foo B C
!! html
-A [1] B C
+A [1] B C
-
-↑ foo
+
+↑ foo
!!end
@@ -20352,37 +21461,35 @@ A [foo] B
C [bar] D
!! html
-A [1] B
-C [2] D
-
-↑ foo
-↑ bar
+A [1] B
+C [2] D
+
+↑ foo
+↑ bar
!!end
!!test
Ref: 12. ref-tags act as trailing newline migration barrier
-!!options
-parsoid
!! wikitext
-a
+a
-b
+b
c
-!! html
-a
+!! html/parsoid
+a
-b [1]
-[2]
+b [1]
+[2]
c
-
-↑
-↑
+
+↑
+↑
!!end
!!test
@@ -20395,11 +21502,11 @@ parsoid
B
!! html
-[1] A
-[2] B
-
-↑ foo
-↑ bar
+[1] A
+[2] B
+
+↑ foo
+↑ bar
!!end
@@ -20413,10 +21520,10 @@ parsoid
!! html
-[1]
+
[1]
-
-↑ foo <ref>bar</ref> baz
+
+↑ foo <ref>bar</ref> baz
!!end
@@ -20430,10 +21537,10 @@ B1 B2 [bar]
!! html
-A1 [1] A2 [1]
-B1 [2] B2 [2]
+A1 [1] A2 [1]
+B1 [2] B2 [2]
-↑ 1.0 1.1 foo ↑ 2.0 2.1 bar
+1 2 foo 1 2 bar
!!end
@@ -20447,9 +21554,9 @@ A [foo]
!! html
-A [1]
-
-↑ foo
+A [1]
+
+↑ foo
!!end
!!test
@@ -20461,11 +21568,11 @@ parsoid
!!html
-[1]
+
[1]
-
-↑ foo
+
+↑ foo
!!end
@@ -20478,11 +21585,11 @@ parsoid
!!html
-[1]
+
[1]
-
-↑ foo
+
+↑ foo
!!end
@@ -20495,10 +21602,10 @@ parsoid
!! html
-1 [1] 2 [1]
+
1 [1] 2 [1]
-
-↑ 1.0 1.1 foo
+
+1 2 foo
!!end
@@ -20513,28 +21620,24 @@ C
!! html
-A [1]
-B [1]
-C [1]
+A [1]
+B [1]
+C [1]
-↑ 1.0 1.1 1.2 Foo one
+1 2 3 Foo one
!!end
!!test
References: 1. references tag without any refs should be handled properly
-!!options
-parsoid
!! wikitext
-!! html
-
+!! html/parsoid
+
!!end
!!test
References: 2. references tag with group only outputs references from that group
-!!options
-parsoid
!! wikitext
A [foo]
B [bar]
@@ -20543,26 +21646,24 @@ C [baz]
-!! html
-A [a 1]
-B [b 1]
-C [1]
+!! html/parsoid
+A [a 1]
+B [b 1]
+C [1]
-
-↑ foo
+
+↑ foo
-
-↑ baz
+
+↑ baz
-
-↑ bar
+
+↑ bar
!!end
!!test
References: 3. ref list should be cleared after processing references
-!!options
-parsoid
!! wikitext
A [foo]
@@ -20571,23 +21672,21 @@ A [foo]
B [bar]
-!! html
-A [1]
+!! html/parsoid
+A [1]
-↑ foo
+↑ foo
-B [1]
+B [1]
-
-↑ bar
+
+↑ bar
!!end
!!test
References: 4. only referenced group should be cleared after processing references
-!!options
-parsoid
!! wikitext
A [afoo]
B [bfoo]
@@ -20597,23 +21696,21 @@ B [bfoo]
C [cfoo]
-!! html
-A [a 1]
-B [1]
+!! html/parsoid
+A [a 1]
+B [1]
-↑ afoo
+↑ afoo
-C [2]
+C [2]
-↑ bfoo ↑ cfoo
+↑ bfoo ↑ cfoo
!!end
!!test
References: 5. ref tags in references should be processed while ignoring all other content
-!!options
-parsoid
!! wikitext
A
B [bar]
@@ -20622,30 +21719,26 @@ B [bar]
[foo]
This should just get lost.
-!! html
-A [1]
-B [2]
+!! html/parsoid
+A [1]
+B [2]
-↑ foo ↑ bar
+↑ foo ↑ bar
!!end
!!test
References: 6. from a transclusion
-!!options
-parsoid
!! wikitext
[Foo] {{echo| }}
-!! html
-[1]
↑ Foo
+!! html/parsoid
+[1]
↑ Foo
!!end
!! test
References: 7. Multiple references tags (one without and one with nested refs) should be correctly handled
-!! options
-parsoid
!! wikitext
A [foo bar for a]
B
@@ -20655,30 +21748,28 @@ B
[foo]
-!! html
-A [1]
-B [X 1]
+!! html/parsoid
+
A [1]
+B [X 1]
-
-↑ foo bar for a
+
+↑ foo bar for a
-
-↑ foo
+
+↑ foo
!! end
!! test
References: 8. T88019: Remove s from templates inside [ that's itself inside a template
-!! options
-parsoid
!! wikitext
X{{echo|][foo {{echo|]bar }} and {{echo|baz}} boo}}
-!! html
-X[1]
-↑ foo bar and baz boo
+!! html/parsoid
+X[1]
+↑ foo bar and baz boo
!!end
@@ -20688,18 +21779,16 @@ X{{echo|[foo {{echo|]bar }} and {{echo|baz}} boo}}
# wt2wt.
!! test
References: 9. Generate missing references list at the end
-!! options
-parsoid
!! wikitext
A [foo]
B [bar]
-!! html
-A [1] B [inexistent 1]
-
-↑ foo
+!! html/parsoid
+A [1] B [inexistent 1]
+
+↑ foo
-
-↑ bar
+
+↑ bar
!! end
@@ -20721,15 +21810,13 @@ A [foo]
!! test
Entities in ref name
-!! options
-parsoid
!! wikitext
[hi]
-!! html
-[1]
-
-↑ hi
+!! html/parsoid
+[1]
+
+↑ hi
!! end
@@ -20743,10 +21830,10 @@ parsoid=wt2html
a[foo]
-!! html
-a[1]
-
-↑ foo
+!! html/parsoid
+a[1]
+
+↑ foo
!! end
!! test
@@ -20756,8 +21843,8 @@ parsoid=wt2wt,html2wt
!! wikitext
foo
-!! html
-foo
+!! html/parsoid
+foo
!! end
#### ----------------------------------------------------------------
@@ -20864,23 +21951,23 @@ Empty TR nodes should not be stripped if they have any attributes set
!! test
Headings: 0. Unnested
!! options
-parsoid
+parsoid=html2wt
+!! html/parsoid
+=foo=
+
+ =foo=
+
+=foo=
+
+=fooa =
!! wikitext
=foo=
- =foo=
+ =foo=
=foo=
=foo''a''=
-!! html
-=foo=
-
- =foo=
-
-=foo=
-
-=fooa =
!!end
# New headings and existing headings are handled differently
@@ -20888,7 +21975,7 @@ parsoid
Headings: 1. Nested inside html
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
=foo=
=foo=
=foo=
@@ -20919,7 +22006,7 @@ parsoid=html2wt
Headings: 2. Outside heading nest on a single line foo *bar
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
foo *bar
foo =bar
foo =bar=
@@ -20937,15 +22024,26 @@ parsoid=html2wt
!! test
Headings: 3. Nested inside html with wikitext split by html tags
!! options
-parsoid=html2wt,wt2wt
-!! wikitext
-= ='''bold'''foo= =
+parsoid=html2wt
!! html/parsoid
=bold foo=
+!! wikitext
+= ='''bold'''foo= =
!!end
!! test
Headings: 4a. No escaping needed (testing just h1 and h2)
+!! options
+parsoid=html2wt
+!! html/parsoid
+=foo
+foo=
+ =foo=
+=foo= bar
+=foo
+foo=
+=
+= foo=
!! wikitext
= =foo =
@@ -20962,22 +22060,13 @@ Headings: 4a. No escaping needed (testing just h1 and h2)
= = =
= ''=''foo= =
-!! html/parsoid
-=foo
-foo=
- =foo=
-=foo= bar
-=foo
-foo=
-=
-= foo=
!!end
!! test
Headings: 4b. No escaping needed (inside p-tags)
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
===
=foo= x
=foo=
@@ -20991,7 +22080,19 @@ parsoid=html2wt
!! test
Headings: 5. Empty headings
!! options
-parsoid
+parsoid=html2wt
+!! html/parsoid
+
+
+
+
+
+
+
+
+
+
+
!! wikitext
= =
@@ -21004,92 +22105,81 @@ parsoid
===== =====
====== ======
-!! html
-
-
-
-
-
-
!!end
!! test
Headings: 6a. Heading chars in SOL context (with trailing spaces)
!! options
-parsoid
+parsoid=html2wt
+!! html/parsoid
+=a=
+
+=a=
+
+=a=
!! wikitext
=a=
=a=
=a=
-
-=a=
-!! html
-=a=
-=a=
-=a=
-=a=
!!end
!! test
Headings: 6b. Heading chars in SOL context (with trailing newlines)
!! options
-parsoid
-!! wikitext
-=a=
-b
-
-=a=
-b
-
-=a=
-b
-
-=a=
-b
-!! html
+parsoid=html2wt
+!! html/parsoid
=a=
b
+
=a=
b
+
=a=
b
-=a=
-b
-
+!! wikitext
+=a=
+b
+
+=a=
+b
+
+=a=
+b
!!end
!! test
Headings: 6c. Heading chars in SOL context (leading newline break)
!! options
-parsoid
+parsoid=html2wt
+!! html/parsoid
+a
+=b=
!! wikitext
a
=b=
-!! html
-a
-=b=
!!end
!! test
Headings: 6d. Heading chars in SOL context (with interspersed comments)
!! options
-parsoid
+parsoid=html2wt
+!! html/parsoid
+=a=
+
+=a=
!! wikitext
=a=
=a=
-!! html
-=a=
-=a=
!!end
!! test
Headings: 6d. Heading chars in SOL context (No escaping needed)
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
=a=b
!! wikitext
=a=b
@@ -21099,11 +22189,11 @@ parsoid=html2wt
Headings: 7. Insert a newline between new content and headings
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
NEW
new
-A
-a
+A
+a
!! wikitext
== NEW ==
new
@@ -21126,23 +22216,38 @@ a
!! test
Lists: 0. Outside nests
+!! options
+parsoid=html2wt
+!! html/parsoid
+*foo
+
+#foo
+
+;Foo:bar
!! wikitext
* foo
# foo
-;Foo: bar
-!! html
-*foo
-
#foo
-
;Foo:bar
-
+; Foo: bar
!!end
!! test
Lists: 1. Nested inside html
-!! wikitext
-**foo
+!! options
+parsoid=html2wt
+!! html/parsoid
+
+
+
+
+*foo
+#foo
+:foo
+;foo
+
+!! wikitext
+**foo
*#foo
@@ -21157,20 +22262,19 @@ Lists: 1. Nested inside html
#:foo
#;foo
-!! html
-
-
-
-
-*foo
-#foo
-:foo
-;foo
-
!!end
!! test
Lists: 2. Inside definition lists
+!! options
+parsoid=html2wt
+!! html/parsoid
+;foo
+:foo
+:foo
+bar
+:foo
+
!! wikitext
;;foo
@@ -21180,40 +22284,27 @@ Lists: 2. Inside definition lists
:bar
::foo
-!! html
-;foo
-:foo
-:foo
-bar
-:foo
-
!!end
!! test
Lists: 3. Only bullets at start of text should be escaped
+!! options
+parsoid=html2wt
+!! html/parsoid
+
+
+
!! wikitext
**foo*bar
**foo ''it''*bar
-!! html
-
-
-
!!end
!! test
Lists: 4. No escapes needed
!! options
-parsoid
-!! wikitext
-*foo*bar
-
-*''foo''*bar
-
-*[[Foo]]: bar
-
-*[[Foo]]*bar
-!! html
+parsoid=html2wt
+!! html/parsoid
foo*bar
@@ -21230,10 +22321,29 @@ parsoid
Foo *bar
+!! wikitext
+*foo*bar
+
+*''foo''*bar
+
+*[[Foo]]: bar
+
+*[[Foo]]*bar
!!end
!! test
Lists: 5. No unnecessary escapes
+!! options
+parsoid=html2wt
+!! html/parsoid
+
+
+
+
+
+
+
+
!! wikitext
* bar [[foo]]
@@ -21248,22 +22358,13 @@ Lists: 5. No unnecessary escapes
* : a
* ''* foo''
-!! html
-
-
-
-
-
-
-
-
!!end
!! test
Lists: 6. Escape bullets in SOL position
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
*foo
!! wikitext
* foo
@@ -21271,20 +22372,22 @@ parsoid=html2wt
!! test
Lists: 7. Escape bullets in a multi-line context
-!! wikitext
-a
-* b
-!! html
+!! options
+parsoid=html2wt
+!! html/parsoid
a
*b
+!! wikitext
+a
+* b
!!end
!! test
Lists: 8. Escape colons only if not present in tags
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
a:bc:d
!! wikitext
; a:b ''c:d''
@@ -21296,17 +22399,16 @@ parsoid=html2wt
!! test
HRs: 1. Single line
+!! options
+parsoid=html2wt
+!! html/parsoid
+ ----
+ =foo=
+ *foo
!! wikitext
--------
----=foo=
----*foo
-!! html+tidy
-
-----
-
-=foo=
-
-*foo
!! end
#### --------------- Tables ---------------
@@ -21330,40 +22432,48 @@ HRs: 1. Single line
!! test
Tables: 1a. Simple example
-!! wikitext
-{|
-|}
-!! html
+!! options
+parsoid=html2wt
+!! html/parsoid
{|
|}
+!! wikitext
+{|
+|}
!! end
!! test
Tables: 1b. No escaping needed
-!! wikitext
-!foo
-!! html
+!! options
+parsoid=html2wt
+!! html/parsoid
!foo
+!! wikitext
+!foo
!! end
!! test
Tables: 1c. No escaping needed
-!! wikitext
-|foo
-!! html
+!! options
+parsoid=html2wt
+!! html/parsoid
|foo
+!! wikitext
+|foo
!! end
!! test
Tables: 1d. No escaping needed
-!! wikitext
-|}foo
-!! html
+!! options
+parsoid=html2wt
+!! html/parsoid
|}foo
+!! wikitext
+|}foo
!! end
!! test
@@ -21424,11 +22534,8 @@ parsoid=html2wt
!! test
Tables: 2c. Nested in td -- no escaping needed
-!! wikitext
-{|
-
-|foo!!bar
-|}
+!! options
+parsoid=html2wt
!! html/*
@@ -21436,15 +22543,17 @@ Tables: 2c. Nested in td -- no escaping needed
foo!!bar
-!! end
-
-!! test
-Tables: 3a. Nested in th
!! wikitext
{|
-!foo!bar
+|foo!!bar
|}
+!! end
+
+!! test
+Tables: 3a. Nested in th
+!! options
+parsoid=html2wt
!! html/*
@@ -21452,6 +22561,11 @@ Tables: 3a. Nested in th
foo!bar
+!! wikitext
+{|
+
+!foo!bar
+|}
!! end
!! test
@@ -21560,6 +22674,19 @@ parsoid=html2wt
!! test
Tables: 4c. No escaping needed
+!! options
+parsoid=html2wt
+!! html/parsoid
+
+foo-bar foo+bar
+foo -barfoo +bar
+foo
+bar|baz
++bar
+-bar
+x
+a|b
+
!! wikitext
{|
|foo-bar
@@ -21600,21 +22727,18 @@ bar|baz
a|b
-!! html/parsoid
-
-foo-bar foo+bar
-foo -barfoo +bar
-foo
-bar|baz
-+bar
--bar
-x
-a|b
-
!! end
!! test
Tables: 4d. No escaping needed
+!! options
+parsoid=html2wt
+!! html/parsoid
+
!! wikitext
{|
|[[Foo]]-bar
@@ -21631,29 +22755,42 @@ Tables: 4d. No escaping needed
-2
+!! end
+
+!! test
+T97430: Don't emit empty nowiki pairs around marker meta tags
+!! options
+parsoid=html2wt
!! html/parsoid
-
+*This is a long sentence here that will make the nowiki algo split up the nowikis into multiple pairs
+|** Make this another long long long sentence forcing the nowiki algo to split up the nowikis.
+!! wikitext
+* This is a long sentence here that will make the nowiki algo split up the nowikis into multiple pairs
+|** Make this another long long long sentence forcing the nowiki algo to split up the nowikis.
!! end
!! test
-Tables: Digest broken attributes on table and tr tag
+Unclosed xmlish element in table line shouldn't eat end delimiters
!! options
-parsoid=wt2html
+parsoid=html2wt
+!! html/parsoid
+
!! wikitext
-{| || |} ++
-|- || || ++ --
-|- > [
+{|
+|
|}
-!! html
+!! html/php
+
+ <foo
+
+ bar>
+
+
!! end
#### --------------- Links ----------------
@@ -21665,6 +22802,12 @@ parsoid=wt2html
#### --------------------------------------
!! test
Links 1. WikiLinks: No escapes needed
+!! options
+parsoid=html2wt
+!! html/parsoid
+Fooboo
+[Foobar]
+x [Foobar] x
!! wikitext
[[Foo|Foo''boo'']]
[[Foo|[Foobar]]]
@@ -21674,10 +22817,6 @@ Links 1. WikiLinks: No escapes needed
[Foobar]
x [Foobar] x
-!! html/parsoid
-Fooboo
-[Foobar]
-x [Foobar] x
!! end
!! test
@@ -21722,6 +22861,11 @@ parsoid=html2wt
!! test
Links 3. WikiLinks: No escapes needed
+!! options
+parsoid=html2wt
+!! html/parsoid
+[Foobar
+foo|bar
!! wikitext
[[Foo|[Foobar]]
[[Foo|foo|bar]]
@@ -21729,9 +22873,6 @@ Links 3. WikiLinks: No escapes needed
[Foobar
foo|bar
-!! html/parsoid
-[Foobar
-foo|bar
!! end
!! test
@@ -21761,18 +22902,22 @@ parsoid=html2wt
!! test
Links 5. ExtLinks: No escapes needed
+!! options
+parsoid=html2wt
+!! html/parsoid
+[google
!! wikitext
[http://google.com [google]
!! html/php
[google
-!! html/parsoid
-[google
!! end
!! test
Links 6. Add s between text-nodes and url-links when required (bug 64300)
-!! html/parsoid
+!! options
+parsoid=html2wt
+!! html/parsoid
xhttp://example.com y
http://example.com ?x
http://example.com &x
@@ -21805,6 +22950,8 @@ http://example.com(x )
!! test
Links 7a. Don't add spurious s between text-nodes and url-links (bug 64300)
+!! options
+parsoid=html2wt
!! html/parsoid
x
http://example.com
@@ -21838,6 +22985,8 @@ y
!! test
Links 7b. Don't add spurious s between text-nodes and url-links (bug 64300)
+!! options
+parsoid=html2wt
!! html/parsoid
http://example.com .,;:!?\
-http://example.com :
@@ -21852,6 +23001,8 @@ http://example.com.,;:!?\
!! test
Links 8. Add s between text-nodes and RFC-links when required (bug 64300)
+!! options
+parsoid=html2wt
!! html/parsoid
RFC 123 4
RFC 123 y
@@ -21864,6 +23015,8 @@ X RFC 123 y
!! test
Links 9. Don't add spurious s between text-nodes and RFC-links (bug 64300)
+!! options
+parsoid=html2wt
!! html/parsoid
RFC 123 ?foo
RFC 123 &foo
@@ -21882,6 +23035,8 @@ RFC 123&foo
!! test
Links 10. Add s between text-nodes and PMID-links when required (bug 64300)
+!! options
+parsoid=html2wt
!! html/parsoid
PMID 123 4
PMID 123 y
@@ -21894,6 +23049,8 @@ X PMID 123 y
!! test
Links 11. Don't add spurious s between text-nodes and PMID-links (bug 64300)
+!! options
+parsoid=html2wt
!! html/parsoid
PMID 123 ?foo
PMID 123 &foo
@@ -21912,10 +23069,12 @@ PMID 123&foo
!! test
Links 12. Add s between text-nodes and ISBN-links when required (bug 64300)
+!! options
+parsoid=html2wt
!! html/parsoid
-
ISBN 1234567890 1
-ISBN 1234567890 x
-aISBN 1234567890 b
+
ISBN 1234567890 1
+ISBN 1234567890 x
+aISBN 1234567890 b
!! wikitext
ISBN 1234567890 1
@@ -21925,8 +23084,10 @@ a ISBN 1234567890 b
!! test
Links 13. Don't add spurious s between text-nodes and ISBN-links (bug 64300)
+!! options
+parsoid=html2wt
!! html/parsoid
--ISBN 1234567890 's
+
-ISBN 1234567890 's
!! wikitext
-ISBN 1234567890's
!! html/php
@@ -21942,20 +23103,21 @@ parsoid=html2wt
this is not a link: http://example.com
!! wikitext
-this is not a link: http://example.com
+this is not a link: http://example.com
!! end
!! test
Links 15. Link trails can't become link prefixes.
!! options
language=is
+parsoid=html2wt
+!! html/parsoid
+Söfnuður- 00
!! wikitext
[[Söfnuður]]-[[00]]
!! html/php
Söfnuður- 00
-!! html/parsoid
-Söfnuður- 00
!! end
#### --------------- Quotes ---------------
@@ -21967,28 +23129,7 @@ language=is
!! test
1a. Quotes inside and
!! options
-parsoid=html2wt,wt2wt
-!! wikitext
-'' 'foo'''
-''''foo'' ''
-'''''foo''' ''
-''foo'' 's
-''' 'foo''''
-'''''foo'' '''
-''''''foo''' '''
-'''foo' ''bar' ''baz'''
-'''foo''' 's
-'''foo''
-''foo'' '
-''foo''' '
-'''foo'' '
-''''foo'''
-'''foo''' '
-''''foo''' '
-''fools' errand ''
-''fool 's errand''
-' ''foo'' bar '''baz''
-a|!*#-:;+-~[]{}b'''x''
+parsoid=html2wt
!! html/*
'foo'
''foo''
@@ -22011,12 +23152,44 @@ a|!*#-:;+-~[]{}b'''x''
'foo bar 'baz
a|!*#-:;+-~[]{}b'x
+!! wikitext
+'' 'foo'''
+''''foo'' ''
+'''''foo''' ''
+''foo'' 's
+''' 'foo''''
+'''''foo'' '''
+''''''foo''' '''
+'''foo' ''bar' ''baz'''
+'''foo''' 's
+'''foo''
+''foo'' '
+''foo''' '
+'''foo'' '
+''''foo'''
+'''foo''' '
+''''foo''' '
+''fools' errand ''
+''fool 's errand''
+' ''foo'' bar '''baz''
+a|!*#-:;+-~[]{}b'''x''
!! end
!! test
1b. Quotes inside and with other tags on same line
!! options
-parsoid=html2wt,wt2wt
+parsoid=html2wt
+!! html/parsoid
+'a foo bar
+a' foo bar
+a' foo bar
+foo x'bar
+'foo [1]
+'foo test
+'foo and bar
+
+↑ test
+
!! wikitext
'''a'' foo ''[[bar]]''
''a''' foo ''[[bar]]''
@@ -22026,56 +23199,49 @@ parsoid=html2wt,wt2wt
'''foo'' test
'''foo'' and bar
-!! html
-'a foo bar
-a' foo bar
-a' foo bar
-foo x'bar
-'foo [1]
-'foo test
-'foo and bar
-
-↑ test
-
!! end
!! test
2. Link fragments separated by and tags
+!! options
+parsoid=html2wt
+!! html/parsoid
+ [[foo hello]]
+[[foo hello]]
!! wikitext
[[''foo''hello]]
[['''foo'''hello]]
-!! html
-[[foo hello]]
-
[[foo hello]]
-
!! end
# FIXME: Escaping one or both of [[ and ]] is also acceptable --
# this is one of the shortcomings of this format
!! test
3. Link fragments inside and
+!! options
+parsoid=html2wt
+!! html/parsoid
+ [[foo ]]
+[[foo ]]
!! wikitext
''[[foo'']]
'''[[foo''']]
-!! html
-[[foo ]]
-
[[foo ]]
-
!! end
!! test
4. No escaping needed
-!! wikitext
-'''bar'' '
-''''bar''' '
-'a:b'foo
-!! html
+!! options
+options=html2wt
+!! html/parsoid
'bar '
'bar '
'a:b'foo
+!! wikitext
+'''bar'' '
+''''bar''' '
+'a:b'foo
!! end
#### ----------- Paragraphs ---------------
@@ -22084,6 +23250,15 @@ parsoid=html2wt,wt2wt
!! test
1. No unnecessary escapes
+!! options
+parsoid=html2wt
+!! html/parsoid
+bar [[foo]]
+
=bar [[foo]]
+
[[bar [[foo]]
+
]]bar [[foo]]
+
=bar foo]] =
+
!! wikitext
bar [[foo]]
@@ -22094,13 +23269,6 @@ bar [[foo]]
]]bar [[foo]]
=bar foo]] =
-!! html
-bar [[foo]]
-
=bar [[foo]]
-
[[bar [[foo]]
-
]]bar [[foo]]
-
=bar foo]] =
-
!!end
#### ----------------------- PRE --------------------------
@@ -22109,101 +23277,136 @@ bar [[foo]]
!! test
1. Leading whitespace in SOL context should be escaped
!! options
-parsoid
+parsoid=html2wt
+!! html/parsoid
+ a
+
+ a
+
+ a(tab)
+
+ a
+
+ a
+
+a
+ b
+
+a
+ b
+
+a
+ b
!! wikitext
a
a
- a(tab)
+ a(tab)
a
- a
+ a
a
b
a
- b
+ b
a
- b
-!! html
- a
- a
- a(tab)
- a
- a
-a
- b
-a
- b
-a
- b
+ b
+!! html/php
+ a
+
a
+
a(tab)
+
a
+ a
+
a
+ b
+
a
+ b
+
a
+ b
+
!! end
!! test
2. Leading whitespace in non-indent-pre contexts should not be escaped
!! options
-parsoid
+parsoid=htm2wt
+!! html/parsoid
+foo [1]
+
+↑ a
+ b
+
!! wikitext
foo [''a''
b]
-!! html
-foo [1]
-
-↑ a
- b
-
!! end
!! test
3. Leading whitespace in indent-pre suppressing contexts should not be escaped
!! options
-parsoid
-!! wikitext
+parsoid=html2wt
+!! html/parsoid
+
a
b
- c
+ c
-!! html
+!! wikitext
-
a
b
- c
+ c
!! end
!! test
4. Leading whitespace in indent-pre suppressing contexts should not be escaped
!! options
-parsoid
+options=html2wt
+!! html/parsoid
+ caption
!! wikitext
[[File:Foobar.jpg|thumb|caption]]
-!! html/parsoid
- caption
!! end
!! test
5. Nowiki escaping should account for indent-pres
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
==foo==
!! wikitext
==foo==
!! end
+!!test
+T95794: nowiki escaping should account for leading space at start-of-line in an indent-pre block
+!! options
+parsoid=html2wt
+!! html/parsoid
+
+* foo
+* bar
+
+!! wikitext
+ * foo
+ * bar
+!! end
+
#### --------------- Behavior Switches --------------------
+
!! test
1. Valid behavior switches should be escaped
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
__TOC__
__TOC__
!! wikitext
@@ -22215,7 +23418,7 @@ __TOC__
2. Invalid behavior switches should not be escaped
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
__TOO__
__|__
!! wikitext
@@ -22223,6 +23426,31 @@ __TOO__
__|__
!! end
+# We use indent-pre as an indirect way to test for sol-transparent behavior.
+!! test
+Behavior switches should be SOL-transparent
+!! options
+parsoid=html2wt
+!! html/parsoid
+
+
+
+__TOO__
+
+ foo
+
+bar
+!! wikitext
+ __TOC__
+
+
+ __TOO__
+
+ __TOC__ foo
+
+__TOC__ bar
+!! end
+
#### --------------- HTML tags ---------------
#### 1. a tags
#### 2. other tags
@@ -22232,75 +23460,85 @@ __|__
!! test
1. a tags
!! options
-parsoid
+parsoid=html2wt
+!! html/parsoid
+<a href="http://google.com">google</a>
!! wikitext
google
-!! html
-<a href="http://google.com">google</a>
!! end
!! test
2. other tags
-!! wikitext
-* foo
-* foo
-*
-!! html
+!! options
+parsoid=html2wt
+!! html/parsoid
<div>foo</div>
<div style="color:red">foo</div>
<td>
+!! wikitext
+* foo
+* foo
+*
!! end
!! test
3. multi-line html tag
-!! wikitext
-foo
-!! html
+!! options
+parsoid=html2wt
+!! html/parsoid
<div
>foo</div
>
+!! wikitext
+foo
!! end
!! test
4. extension tags
+!! options
+parsoid=html2wt
+!! html/parsoid
+<ref>foo</ref>
+
<ref>bar
+
baz</ref>
+
!! wikitext
[foo]
[bar]
baz
-!! html
-<ref>foo</ref>
-
<ref>bar
-
baz</ref>
-
!! end
#### --------------- Others ---------------
!! test
Escaping nowikis
-!! wikitext
-<nowiki>foo</nowiki>
-!! html
+!! options
+parsoid=html2wt
+!! html/parsoid
<nowiki>foo</nowiki>
+!! wikitext
+<nowiki>foo</nowiki>
!! end
## The quote-char in the input is necessary for triggering the bug
!! test
(Bug 52035) Nowiki-escaping should not get tripped by " :" in text
!! options
-parsoid=wt2wt,html2wt
+parsoid=html2wt
+!! html/parsoid
+foo's bar :
!! wikitext
foo's bar :
-!! html
-foo's bar :
!! end
+#----------- End of wikitext escaping tests --------------
+
!! test
Tag-like HTML structures are passed through as text
@@ -22352,20 +23590,9 @@ HTML tag with broken attribute value quoting
!! wikitext
Foo
-!! end
-
-!! test
-Parsoid-only: HTML tag with broken attribute value quoting
-!! options
-parsoid
-!! wikitext
-Foo
!! end
@@ -22379,7 +23606,7 @@ Table with broken attribute value quoting
!! html/php
!! html/parsoid
@@ -22400,9 +23627,9 @@ Table with broken attribute value quoting on consecutive lines
!! html/php
!! html/parsoid
@@ -22415,7 +23642,7 @@ Table with broken attribute value quoting on consecutive lines
!! end
!! test
-Parsoid-only: Don't wrap broken template tags in on wt2wt (Bug 42353)
+2. Parsoid-only: Don't wrap broken template tags in on wt2wt (Bug 42353)
!! options
parsoid
!! wikitext
@@ -22425,7 +23652,7 @@ parsoid
!! end
!! test
-Parsoid-only: Don't wrap broken template tags in on wt2wt (Bug 42353)
+1. Parsoid-only: Don't wrap broken template tags in on wt2wt (Bug 42353)
!! options
parsoid
!! wikitext
@@ -22544,6 +23771,8 @@ bar
!!end
+# Note that the "style" attribute is really a template parameter here.
+# The = would have to be {{=}} if you wanted the literal.
!!test
Empty TD followed by TD with tpl-generated attribute
!! wikitext
@@ -22704,7 +23933,7 @@ Multi-line image caption generated by templates with/without trailing newlines
New element inserted (without intervening newlines) after an old sol-transparent node should serialize correctly
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
new para
new heading
@@ -22721,12 +23950,10 @@ new para
## a Parsoid serializer test, marking this Parsoid only
!!test
Improperly nested inline or quotes tags with whitespace in between
-!!options
-parsoid
!! wikitext
x
''' ''x''' ''
-!! html
+!! html/parsoid
x
x
@@ -22734,12 +23961,10 @@ parsoid
!!test
Encapsulate protected attributes from wt
-!!options
-parsoid
!! wikitext
-foo
-!! html
-foo
+foo
+!! html/parsoid
+foo
!!end
@@ -22752,7 +23977,7 @@ Ensure ParagraphWrapper can deal with stray closing pre tags
parsoid=wt2html
!! wikitext
plain text
-!! html
+!! html/parsoid
plain text
!!end
@@ -22762,7 +23987,7 @@ plain text
parsoid=wt2html
!! wikitext
-!! html
+!! html/parsoid
hi
ho
@@ -22778,7 +24003,7 @@ parsoid=wt2html,wt2wt
|| ||
a
-!! html
+!! html/parsoid
|| ||
a
@@ -22791,7 +24016,7 @@ Encapsulation properly handles null DSR information from foster box
parsoid=wt2html,wt2wt
!! wikitext
{{echo|}}
-!! html
+!! html/parsoid
foo
!!end
@@ -22801,7 +24026,7 @@ parsoid=wt2html,wt2wt
parsoid=wt2wt,wt2html
!! wikitext
-!! html
+!! html/parsoid
foo
@@ -22817,7 +24042,7 @@ parsoid=wt2wt,wt2html
parsoid=wt2wt,wt2html
!! wikitext
-!! html
+!! html/parsoid
foo
@@ -22834,7 +24059,7 @@ parsoid=wt2wt,wt2html
parsoid=wt2wt,wt2html
!! wikitext
-!! html
+!! html/parsoid
@@ -22853,7 +24078,7 @@ parsoid=wt2wt,wt2html
parsoid=wt2wt,wt2html
!! wikitext
-!! html
+!! html/parsoid
@@ -22872,7 +24097,7 @@ parsoid=wt2wt,wt2html
parsoid=wt2wt,wt2html
!! wikitext
-!! html
+!! html/parsoid
foo
@@ -22893,7 +24118,7 @@ parsoid=wt2wt,wt2html
parsoid=wt2wt,wt2html
!! wikitext
}}ok
-!! html
+!! html/parsoid
foo
@@ -22915,7 +24140,7 @@ parsoid=wt2wt,wt2html
parsoid=wt2wt,wt2html
!! wikitext
-!! html
+!! html/parsoid
foo
@@ -22926,6 +24151,8 @@ parsoid=wt2wt,wt2html
!!end
+# Note that the wt is broken on purpose: the = should be {{=}} if you
+# don't want it to be a template parameter key.
!!test
8. Encapsulate foster-parented transclusion content
!!options
@@ -22936,8 +24163,11 @@ parsoid=wt2wt,wt2html
|-
|b
|}
-!! html
-a
{{{1}}}
+!! html/parsoid
+a
+
+{{{1}}}
+
b
@@ -22952,7 +24182,7 @@ parsoid=wt2wt,wt2html
parsoid=wt2wt,wt2html
!! wikitext
hello}}
-!! html
+!! html/parsoid
hi
hello
!!end
@@ -22967,7 +24197,7 @@ parsoid=wt2html,wt2wt
|}
|}
-!! html
+!! html/parsoid
@@ -22995,7 +24225,7 @@ Properly encapsulate empty-content transclusions in fosterable positions
Support element with .data attribute
!!options
parsoid=html2wt
-!! html
+!! html/parsoid
!! wikitext
@@ -23024,7 +24254,7 @@ Don't block XML namespace declaration
Serialize interwiki links pointing to the current wiki as plain wiki links (bug 65869)
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
Foo
!! wikitext
[[Foo]]
@@ -23035,7 +24265,7 @@ parsoid=html2wt
New wikilinks should be serialized properly
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
Foo
Foo
!! wikitext
@@ -23047,7 +24277,7 @@ parsoid=html2wt
New wiki links (href variations)
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
Foo_bar
Foo_bar
Foo_bar
@@ -23063,7 +24293,7 @@ parsoid=html2wt
New wiki links (content string variations)
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
Foo_bar
Foo bar
./Foo_bar
@@ -23077,7 +24307,7 @@ parsoid=html2wt
New category links (href variations)
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
@@ -23092,7 +24322,7 @@ New sol transparent links don't need indent-pre nowiki protection
!! options
parsoid=html2wt
language=de
-!! html
+!! html/parsoid
@@ -23106,7 +24336,7 @@ language=de
New interlanguage links (href variations)
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
@@ -23253,16 +24483,17 @@ parsoid
bar
!! end
-#!! test
-#Image: new attributes should be serialized in wiki's language for RTL languages (bug 51852)
-#!! options
-#parsoid=html2wt
-#language=ar
-#!! html
-#
-#!! wikitext
-#[[Imagen:Foobar.jpg|derecha|miniaturadeimagen]]
-#!! end
+!! test
+Image: new attributes should be serialized in wiki's language for RTL languages (bug 51852)
+!! options
+parsoid=html2wt
+language=ar
+disabled
+!! html/parsoid
+
+!! wikitext
+[[Imagen:Foobar.jpg|derecha|miniaturadeimagen]]
+!! end
!! test
Image: Block level image should have \n before and after
@@ -23272,7 +24503,7 @@ Image: Block level image should have \n before and after
456
!! html/parsoid
123
-
+
456
!!end
@@ -23290,26 +24521,22 @@ Image: New block level image should have \n before and after (existing content)
!! test
Image: upright option (parsoid)
-!! options
-parsoid
!! wikitext
[[File:Foobar.jpg|thumb|upright|caption]]
[[File:Foobar.jpg|thumb|upright=0.5|caption]]
[[File:Foobar.jpg|thumb|500x500px|upright=0.5|caption]]
-!! html
-caption
-caption
-caption
+!! html/parsoid
+caption
+caption
+caption
!!end
!! test
Image: upright option is ignored on inline and frame images (parsoid)
-!! options
-parsoid
!! wikitext
[[File:Foobar.jpg|500x500px|upright=0.5|caption]]
-!! html
-
+!! html/parsoid
+
!!end
!! test
@@ -23358,7 +24585,7 @@ parsoid=html2wt
Lists: Serialize correctly even when list content is wrapped in p-tags (like VE does)
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
@@ -23370,7 +24597,7 @@ parsoid=html2wt
Lists: Serialize correctly even when list tags has unneeded whitespace between tags
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
!! wikitext
* foo
@@ -23380,7 +24607,7 @@ parsoid=html2wt
Don't strip leading whitespace when handling indent-pre suppressing tags
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
@@ -23413,55 +24640,39 @@ foo
Nowiki-wrap leading whitespace when handling indent-pre inducing tags
!! options
parsoid=html2wt
-!! wikitext
-foo
- bar
+!! html/parsoid
+foo
+ bar
foo2
- bar2
+ bar2
foo
- bar
+ bar
- foo
+ foo
-!! html
-foo
- bar
+!! wikitext
+foo
+ bar
foo2
- bar2
+ bar2
foo
- bar
+ bar
- foo
+ foo
!! end
-!! test
-Lists: Add space after bullets
-!! options
-parsoid=html2wt
-!! html
-
-!! wikitext
-* foo
-* bar
-* baz
-!! end
-
!! test
Lists: Dont insert newlines in a serialized list item.
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
!! wikitext
* a b
@@ -23469,49 +24680,106 @@ parsoid=html2wt
!! end
!! test
-Headings: Add space before/after == (Bug 51744)
+1. Headings: Force sol-transparent links and behavior switches to serialize before/after
!! options
-parsoid=html2wt
-!! html
-foo
- bar
-baz
- baz
+parsoid={
+ "modes": ["html2wt"],
+ "scrubWikitext": false
+}
+!! html/parsoid
+hello there
+ hi pal
+
+ how goes it
+it goes well
+
+howdy
+
+ ok
!! wikitext
-== foo ==
+== hello there [[Category:A1]] ==
-== bar ==
+== [[Category:A2]] hi pal ==
-== baz ==
+== [[Category:A3]] how goes it ==
-== baz ==
+== it goes well [[Category:A4]] ==
+
+==howdy [[Category:A5]] ==
+
+== __TOC__ ok ==
!! end
!! test
-Headings: Force metas to serialize before/after
+2. Headings: Force sol-transparent links and behavior switches to serialize before/after
!! options
-parsoid=html2wt
-!! html
-hello there
- hi pal
+parsoid={
+ "modes": ["html2wt"],
+ "scrubWikitext": true
+}
+!! html/parsoid
+hello there
+ hi pal
+
+ how goes it
+it goes well
- how goes it
+ ok
!! wikitext
== hello there ==
[[Category:A1]]
-
[[Category:A2]]
+
== hi pal ==
[[Category:A3]]
+
== how goes it ==
+
+== it goes well ==
+[[Category:A4]]
+
+__TOC__
+
+== ok ==
+!! end
+
+!! test
+Headings: Don't hoist metas that come from templates
+!! options
+parsoid={
+ "modes": ["html2wt"],
+ "scrubWikitext": true
+}
+!! html/parsoid
+foo
+!! wikitext
+== {{echo|foo [[Category:Foo]]}} ==
+!! end
+
+!! test
+Headings: Category in ref isn't hoisted
+!! options
+parsoid={
+ "modes": ["html2wt"],
+ "scrubWikitext": true
+}
+!! html/parsoid
+
+
+↑ bar
+!! wikitext
+== foo [bar
+[[Category:Baz]] ] ==
+
+
!! end
!! test
Parsoid: Serialize positional parameters with = in them as named parameter
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
foo
@@ -23535,7 +24803,7 @@ data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},
Parsoid: Serialize positional parameters with = in extlink as named parameter
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
http://stuff?is=ok
!! wikitext
{{echo|1 = http://stuff?is=ok}}
@@ -23545,7 +24813,7 @@ parsoid=html2wt
Parsoid: Correctly serialize block-node children when they are a combination of text and p-nodes
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
@@ -23570,7 +24838,7 @@ b
Substrings resembling wikitext in hrefs should not get nowiki escapes
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
Foo''bar''baz
!! wikitext
[[Foo''bar''baz]]
@@ -23580,27 +24848,89 @@ parsoid=html2wt
Enforce single-line context in the serializer
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
testing
123
+ hi there
+ you
+
+
+
+↑ hello
+there
+
+
+foo
+bar
+baz
+foo bar
+baz
+
+hi
+ho hi
+ho
+
+
!! wikitext
== testing 123 ==
+== hi {{bogus|there
+you}} ==
+
+== foo [hello
+there] ==
+
+
+
* asd sdf
+
+* foo bar baz
+* foo '''bar''' baz
+
+; hi ho : hi ho
+
+: {|
+| ha
+ha
+ha
+|}
+!! end
+
+!! test
+Serialize new placeholder space without spans
+!! options
+parsoid=html2wt
+!! html/parsoid
+foo : bar
+
+foo : bar
+
+[1] ok
+!! wikitext
+foo : bar
+
+foo : bar
+
+[foo : bar]ok
!! end
-#-----------------------------
-# I/B quote minimization tests
-#-----------------------------
+
+#-----------------------
+# Tag minimization tests
+#-----------------------
!! test
1. I/B quote minimization: wikitext-only tags should be combined
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
A B
A B
A B
@@ -23631,7 +24961,7 @@ parsoid=html2wt
2. I/B quote minimization: wikitext and html tags should not be combined
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
A B
A B
!! wikitext
@@ -23644,7 +24974,7 @@ parsoid=html2wt
3. I/B quote minimization: templated content stops minimization
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
A B
A B
!! wikitext
@@ -23657,7 +24987,7 @@ parsoid=html2wt
4. I/B quote minimization: new content should be mimimized with adjacent old content
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
A B
A B
A B
@@ -23699,28 +25029,71 @@ parsoid={
''ac''
!! end
-#------------------------------------
-# End of I/B quote minimization tests
-#------------------------------------
-
-!!test
-Bug 54262: New entities
+!! test
+1. Merge adjacent link nodes as long as at least one element is new
!! options
-parsoid=html2wt
+parsoid={
+ "modes": ["html2wt"],
+ "scrubWikitext": true
+}
+!! html/parsoid
+Foot ball
+Foot ball
+Foot ball
!! wikitext
-
-!! html
-
+[[Football]]
+[[Football]]
+[[Football|Foot]][[Football|ball]]
!! end
-## Note that there is no wikitext output for 'unknownproperty' ##
-## Unknown magic words are silently dropped ##
-
!! test
-Magic words
+2. Merge adjacent link nodes and enable additional normalizations
+!! options
+parsoid={
+ "modes": ["html2wt"],
+ "scrubWikitext": true
+}
+!! html/parsoid
+Foot ball
+!! wikitext
+[[Football|''Football'']]
+!! end
+
+!! test
+3. Don't merge adjacent link nodes if scrubWikitext is false
+!! options
+parsoid={
+ "modes": ["html2wt"],
+ "scrubWikitext": false
+}
+!! html/parsoid
+Foot ball
+!! wikitext
+[[Football|Foot]][[Football|ball]]
+!! end
+
+#------------------------------
+# End of tag minimization tests
+#------------------------------
+
+!!test
+Bug 54262: New entities
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
+
+!! wikitext
+
+!! end
+
+## Note that there is no wikitext output for 'unknownproperty' ##
+## Unknown magic words are silently dropped ##
+
+!! test
+Magic words
+!! options
+parsoid=html2wt
+!! html/parsoid
@@ -23747,7 +25120,7 @@ __NOCONTENTCONVERT__
Consecutive s should not get merged
!! options
parsoid=html2wt,html2html
-!! html
+!! html/parsoid
a b
c
@@ -23779,8 +25152,8 @@ f
Edited ISBN links not serializable as ISBN links should serialize as wikilinks
!! options
parsoid=html2wt
-!! html
-ISBN 1234567895
+!! html/parsoid
+ISBN 1234567895
!! wikitext
[[Special:BookSources/1234567890|ISBN 1234567895]]
!! end
@@ -23789,7 +25162,7 @@ parsoid=html2wt
Edited RFC links not serializable as RFC links should serialize as extlinks
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
New RFC
!! wikitext
[//tools.ietf.org/html/rfc123 New RFC]
@@ -23799,7 +25172,7 @@ parsoid=html2wt
Edited PMID links not serializable as PMID links should serialize as extlinks
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
New PMID
!! wikitext
[//www.ncbi.nlm.nih.gov/pubmed/123?dopt=Abstract New PMID]
@@ -23855,11 +25228,132 @@ x http://cscott.net x
x http://cscott.net x
!! end
+!! test
+WTS of edited autolink-like text (T103364)
+!! options
+parsoid={
+ "modes": ["wt2wt"],
+ "changes": [
+ [ "span[typeof]", "removeAttr", "typeof" ]
+ ]
+}
+!! wikitext
+Not a link: http://example.com .
+!! wikitext/edited
+Not a link: http://example.com .
+!! end
+
+!! test
+WTS of newly-authored autolink-like text (T103364)
+!! options
+parsoid=html2wt
+!! html/parsoid
+http://example.com is not a link.
+!! wikitext
+http://example.com is not a link.
+!! end
+
+!! test
+WTS of autolink-like text after an autolink (T108563)
+!! options
+parsoid=html2wt
+!! html/parsoid
+http://example.com http://example.com is not a link.
+!! wikitext
+http://example.com http://example.com is not a link.
+!! end
+
+!! test
+Magic links inside links (not autolinked)
+!! wikitext
+[[Foo|http://example.com]]
+[[Foo|RFC 1234]]
+[[Foo|PMID 1234]]
+[[Foo|ISBN 123456789x]]
+
+[http://foo.com http://example.com]
+[http://foo.com RFC 1234]
+[http://foo.com PMID 1234]
+[http://foo.com ISBN 123456789x]
+!! html+tidy
+http://example.com RFC 1234 PMID 1234 ISBN 123456789x
+http://example.com RFC 1234 PMID 1234 ISBN 123456789x
+!! html/parsoid
+http://example.com
+RFC 1234
+PMID 1234
+ISBN 123456789x
+
+http://example.com
+RFC 1234
+PMID 1234
+ISBN 123456789x
+!! end
+
+!! test
+Magic links inside image captions (autolinked)
+!! wikitext
+[[File:Foobar.jpg|thumb|http://example.com]]
+[[File:Foobar.jpg|thumb|RFC 1234]]
+[[File:Foobar.jpg|thumb|PMID 1234]]
+[[File:Foobar.jpg|thumb|ISBN 123456789x]]
+!! html+tidy
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+!! html/parsoid
+http://example.com
+RFC 1234
+PMID 1234
+ISBN 123456789x
+!! end
+
+!! test
+WTS of magic word text (T109371)
+!! options
+parsoid=html2wt
+!! html/parsoid
+RFC 1234
+RFC 1234
+RFC 1234
+!! wikitext
+RFC 1234
+
+[http://foo.com RFC 1234]
+
+[[Foo|RFC 1234]]
+!! end
+
!! test
Edited Redirect link should emit a non-piped wikitext link
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
!! wikitext
#REDIRECT [[Bar]]
@@ -23869,7 +25363,7 @@ parsoid=html2wt
T75121: Infer extension name from typeOf if data-mw is not present
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
!! wikitext
@@ -23929,7 +25423,7 @@ parsoid=html2wt,wt2wt
HTML id attribute with Parsoid-like element ids should not be serialized to wikitext
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
foo
bar
@@ -23945,7 +25439,7 @@ parsoid=html2wt
Parsoid-like element ids should not be serialized to wikitext unless shadowed
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
ok
!! wikitext
ok
@@ -23972,67 +25466,708 @@ parsoid={
Never serialize a-tag as html, regardless of what data-parsoid has to say
!! options
parsoid=html2wt
-!! html
+!! html/parsoid
Foo
!! wikitext
[[Foo]]
!! end
-# -----------------------------------------------------------------
-# End of section for Parsoid-only html2wt tests for serialization
-# of new content
-# -----------------------------------------------------------------
+## SSS FIXME: This is broken output nevertheless.
+## What might be a reasonable non-broken output for this?
+## This is an edge case unlikely to be seen in production
+## that I am not wasting more time on this right now.
+!! test
+Never serialize a-tag as html, no matter what attributes it has
+!! options
+parsoid=html2wt
+!! html/parsoid
+
+!! wikitext
+[http://boo.org http://boohoo.org]
+!! end
-# -----------------------------------------------------------------
-# The following section of tests are primarily to spec behavior of
-# the selective serializer. All these tests have manual selser
-# changes. The automated selser changes for all tests handle the
-# wide variation of changes, but these tests here capture specs
-# deterministically.
-# ----------------------------------------------------------------
+# Misnested is an indication that selser can reuse the source but these have
+# shown to sneak through on occasion. See T101768.
+# The original wikitext here is: [http://test.com [[one]] two three]
+!! test
+Strip span tags added to mark as misnested
+!! options
+parsoid=html2wt
+!! html/parsoid
+one two three
+!! wikitext
+[http://test.com][[one]] two three
+!! end
+
+# --------------------------------------------
+# Tests spec'ing wikitext serialization norms |
+# --------------------------------------------
+
+!! test
+Lists: Add space after bullets
+!! options
+parsoid=html2wt
+!! html/parsoid
+
+!! wikitext
+* foo
+* bar
+* baz
+!! end
+
+!! test
+1. Headings: Add space before/after == (T53744)
+!! options
+parsoid=html2wt
+!! html/parsoid
+foo
+ bar
+baz
+ baz
+!! wikitext
+== foo ==
+
+== bar ==
+
+== baz ==
+
+== baz ==
+!! end
+
+!! test
+2. Headings: Add space before/after == even after hoisted content
+!! options
+parsoid={
+ "modes": ["html2wt"],
+ "scrubWikitext": true
+}
+!! html/parsoid
+ ok
+!! wikitext
+ [[Category:A2]]
+
+== ok ==
+!! end
+
+!! test
+1. Headings: suppress newly created empty headings
+!! options
+parsoid={
+ "modes": ["html2wt"],
+ "scrubWikitext": true
+}
+!! html/parsoid
+
+!! wikitext
+!! end
+
+!! test
+2. Headings: don't suppress empty headings if scrubWikitext is false
+!! options
+parsoid=html2wt
+!! html/parsoid
+
+!! wikitext
+== ==
+!! end
-## T90517
!! test
-1. Selser: New comments should not be lost
+3. Headings: suppress empty headings on edits
!! options
parsoid={
"modes": ["selser"],
+ "scrubWikitext": true,
"changes": [
- [ "#a", "after", "" ],
- [ "#b", "before", "" ]
+ [ "#x", "remove"]
]
}
!! wikitext
-a
-
-b
+==foo ==
!! wikitext/edited
-a
+!! end
-b
+!! test
+1. WT Quote Tags: suppress newly created empty style tags
+!! options
+parsoid={
+ "modes": ["html2wt"],
+ "scrubWikitext": true
+}
+!! html/parsoid
+
+!! wikitext
+!! end
+
+!! test
+2. WT Quote Tags: don't suppress empty style tags if scrubWikitext is false
+!! options
+parsoid=html2wt
+!! html/parsoid
+
+!! wikitext
+'' ''''' '''
!! end
-## T89383
!! test
-2. Selser: Check for validity of DSR before using it
+3. WT Quote Tags: suppress empty style tags on edits
!! options
parsoid={
"modes": ["selser"],
+ "scrubWikitext": true,
"changes": [
- [ "#a", "before", " " ]
+ [ "#x", "remove"]
]
}
!! wikitext
-a
+'''foo '''
!! wikitext/edited
-{{DISPLAYTITLE:foo}}
-a
!! end
+!! test
+1. Anchors: suppress newly created empty anchors
+!! options
+parsoid={
+ "modes": ["html2wt"],
+ "scrubWikitext": true
+}
+!! html/parsoid
+
+!! wikitext
+!! end
+
+!! test
+2. Anchors: don't suppress empty anchors if scrubWikitext is false
+!! options
+parsoid={
+ "modes": ["html2wt"],
+ "scrubWikitext": false
+}
+!! html/parsoid
+
+!! wikitext
+[[Test| ]]
+!! end
-TODO:
-more images
-more tables
-character entities
-and much more
-Try for 100% code coverage
+!! test
+3. Anchors: suppress empty anchors on edits
+!! options
+parsoid={
+ "modes": ["selser"],
+ "scrubWikitext": true,
+ "changes": [
+ [ "#x", "remove"]
+ ]
+}
+!! wikitext
+[[Test|foo ]]
+!! wikitext/edited
+!! end
+
+!! test
+3a. Anchors: do not suppress numbered extlinks
+!! options
+parsoid={
+ "modes": ["wt2wt"],
+ "scrubWikitext": true
+}
+!! wikitext
+[http://foo.com]
+!! html/parsoid
+
+!! end
+
+!! test
+3b. Anchors: do not suppress numbered extlinks
+!! options
+parsoid={
+ "modes": ["wt2wt"],
+ "scrubWikitext": true,
+ "changes": [
+ [ "#x", "remove"]
+ ]
+}
+!! wikitext
+[http://foo.com foo ]
+!! wikitext/edited
+[http://foo.com]
+!! end
+
+!!test
+Normalizations should be restricted to edited content
+!!options
+parsoid={
+ "modes": ["selser"],
+ "scrubWikitext": true,
+ "changes": [
+ [ "h1", "before", " "]
+ ]
+}
+!!wikitext
+a
+= =
+b
+!!wikitext/edited
+a
+= =
+b
+!!end
+
+!! test
+1. Multiple normalizations (html2wt)
+!! options
+parsoid={
+ "modes": ["html2wt"],
+ "scrubWikitext": true
+}
+!! html
+
+foo
+ x
+!! wikitext
+
+[[foo]]
+x
+
+!! end
+
+!! test
+2. Multiple normalizations (selser)
+!! options
+parsoid={
+ "modes": ["selser"],
+ "scrubWikitext": true,
+ "changes": [
+ [ "#x", "after", " \n x
"]
+ ]
+}
+!! wikitext
+foo
+!! wikitext/edited
+foo
+
+x
+!! end
+
+!! test
+1. Indent Pre Nowiki: suppress whitespace at the start of new paragraph
+!! options
+parsoid={
+ "modes": ["html2wt"],
+ "scrubWikitext": true
+}
+!! html/parsoid
+ hi
+ hello
+!! wikitext
+hi
+
+hello
+!! end
+
+!! test
+2. Indent Pre Nowiki: don't suppress whitespace at the start of new paragraph if scrubWikitext is false
+!! options
+parsoid=html2wt
+!! html/parsoid
+ hi
+ hello
+!! wikitext
+ hi
+
+ hello
+!! end
+
+!! test
+3. Indent Pre Nowiki: suppress whitespace after newlines in new paragraph or table cell
+!! options
+parsoid={
+ "modes": ["html2wt"],
+ "scrubWikitext": true
+}
+!! html/parsoid
+Foo
+ bar
+baz
+
+
+
+ foo
+ bar
+
+ foo
+ barboo
+!! wikitext
+Foo
+bar
+baz
+
+{|
+|Foo
+bar
+baz bang
+|}
+
+foo
+bar
+
+foo
+barboo
+!! end
+
+!! test
+4. Indent Pre Nowiki: suppress leading whitespace in edited paragraphs
+!! options
+parsoid={
+ "modes": ["selser"],
+ "scrubWikitext": true,
+ "changes": [
+ [ "p", "html", " a\n b" ]
+ ]
+}
+!! wikitext
+xyz
+!! wikitext/edited
+a
+b
+!! end
+
+!! test
+1. New links that end in spaces
+!! options
+parsoid={
+ "modes": ["html2wt"],
+ "scrubWikitext": false
+}
+!! html/parsoid
+Berlin is the capital of Germany.
+Foo bar
+Boston is a city.
+!! wikitext
+[[Berlin ]] is the capital of Germany.
+
+[[Foo ]]'''bar'''
+
+[[Boston ]] is a city.
+!! end
+
+!! test
+2. New links that end in spaces
+!! options
+parsoid={
+ "modes": ["html2wt"],
+ "scrubWikitext": true
+}
+!! html/parsoid
+Berlin is the capital of Germany.
+Foo bar
+Boston is a city.
+!! wikitext
+[[Berlin]] is the capital of Germany.
+
+[[Foo]] '''bar'''
+
+[[Boston]] is a city.
+!! end
+
+!! test
+1. Table cells with escapable prefixes
+!! options
+parsoid={
+ "modes": ["html2wt"],
+ "scrubWikitext": false
+}
+!! html
+
+!! wikitext
+{|
+|a
+|-
+|-
+|-
+|+
+|}
+!! end
+
+!! test
+2. Table cells with escapable prefixes
+!! options
+parsoid={
+ "modes": ["html2wt"],
+ "scrubWikitext": true
+}
+!! html
+
+!! wikitext
+{|
+|a
+|-
+| -
+|-
+| +
+|}
+!! end
+
+!! test
+3a. Table cells with escapable prefixes after edits
+!! options
+parsoid={
+ "modes": ["selser"],
+ "scrubWikitext": true,
+ "changes": [
+ [ "table tbody tr:first-child td:first-child", "remove"]
+ ]
+}
+!! wikitext
+{|
+|a||-
+|}
+!! wikitext/edited
+{|
+| -
+|}
+!! end
+
+!! test
+3b. Table cells with escapable prefixes after edits
+!! options
+parsoid={
+ "modes": ["selser"],
+ "scrubWikitext": true,
+ "changes": [
+ [ "table tbody tr:first-child td:first-child", "html", "-" ],
+ [ "#x", "remove" ]
+ ]
+}
+!! wikitext
+{|
+|pqr
+|foo +
+|}
+!! wikitext/edited
+{|
+| -
+| +
+|}
+!! end
+
+# FIXME: This test will fail because
+# normalization doesn't realize that the id attribute
+# will eliminate the escapable scenario
+!! test
+4a. Table cells without escapable prefixes after edits
+!! options
+parsoid={
+ "modes": ["selser"],
+ "scrubWikitext": true,
+ "changes": [
+ [ "#x", "html", "-" ]
+ ]
+}
+!! wikitext
+{|
+| id="x" |abcd
+|}
+!! wikitext/edited
+{|
+| id="x" |-
+|}
+!! end
+
+## This tests normalizer's ability to discriminate between
+## cells having identical content.
+!! test
+4b. Table cells without escapable prefixes after edits
+!! options
+parsoid={
+ "modes": ["selser"],
+ "scrubWikitext": true,
+ "changes": [
+ [ "td", "html", "-" ]
+ ]
+}
+!! wikitext
+{|
+|a||b
+|}
+!! wikitext/edited
+{|
+| -||-
+|}
+!! end
+
+## This tests normalizer's ability to not be tripped by
+## comments (and whitespace)
+!! test
+4c. Table cells without escapable prefixes after edits
+!! options
+parsoid={
+ "modes": ["selser"],
+ "scrubWikitext": true,
+ "changes": [
+ [ "table tbody tr td:first-child", "remove" ]
+ ]
+}
+!! wikitext
+{|
+|-
+ |a||-
+|}
+!! wikitext/edited
+{|
+|-
+ | -
+|}
+!! end
+
+## This tests normalizer's ability to handle HTML cells
+!! test
+4d. Table cells without escapable prefixes after edits
+!! options
+parsoid={
+ "modes": ["selser"],
+ "scrubWikitext": true,
+ "changes": [
+ [ "td", "html", "-" ]
+ ]
+}
+!! wikitext
+
+!! wikitext/edited
+
+!! end
+
+!! test
+Escape nowiki DOM elements
+!! options
+parsoid=html2wt
+!! html/parsoid
+foo
+!! wikitext
+<nowiki>''foo''</nowiki>
+!! end
+
+# ---------------------------------------------------
+# End of tests spec'ing wikitext serialization norms |
+# ---------------------------------------------------
+
+# -----------------------------------------------------------------
+# End of section for Parsoid-only html2wt tests for serialization
+# of new content
+# -----------------------------------------------------------------
+
+# -----------------------------------------------------------------
+# The following section of tests are primarily to spec behavior of
+# the selective serializer. All these tests have manual selser
+# changes. The automated selser changes for all tests handle the
+# wide variation of changes, but these tests here capture specs
+# deterministically.
+# ----------------------------------------------------------------
+
+## T90517
+!! test
+Selser: New comments should not be lost
+!! options
+parsoid={
+ "modes": ["selser"],
+ "changes": [
+ [ "#a", "after", "" ],
+ [ "#b", "before", "" ]
+ ]
+}
+!! wikitext
+a
+
+b
+!! wikitext/edited
+a
+
+b
+!! end
+
+## T89383
+!! test
+Selser: Check for validity of DSR before using it
+!! options
+parsoid={
+ "modes": ["selser"],
+ "changes": [
+ [ "#a", "before", " " ]
+ ]
+}
+!! wikitext
+a
+!! wikitext/edited
+{{DISPLAYTITLE:foo}}
+a
+!! end
+
+!! test
+1. DOMDiff: Changes to [ content should be looked up using id
+!! options
+parsoid={
+ "modes": ["selser"],
+ "changes": [
+ ["#X", "after", "bar"],
+ ["#Y", "after", "baz"]
+ ]
+}
+!! wikitext
+X ]foo
+Y
+
+foo
+
+!! wikitext/edited
+X foo bar
+Y
+
+foo baz
+
+!! end
+
+!! test
+2. DOMDiff: Changes to [ content should be looked up using id
+!! options
+parsoid={
+ "modes": ["selser"],
+ "changes": [
+ ["#Z", "after", "bar"]
+ ]
+}
+!! wikitext
+A ][foo bar for a]
+B
+
+
+
+
+foo
+
+!! wikitext/edited
+A [foo bar for a]
+B
+
+
+
+
+foo bar
+
+!! end
diff --git a/tests/parser/preprocess/All_system_messages.expected b/tests/parser/preprocess/All_system_messages.expected
index 3665e3c1..57223da6 100644
--- a/tests/parser/preprocess/All_system_messages.expected
+++ b/tests/parser/preprocess/All_system_messages.expected
@@ -1370,12 +1370,12 @@ Message
</td><td>
int:Emailmessage
</td></tr><tr><td>
-[http://tl.wiktionary.org/w/wiki.phtml?title=MediaWiki:Emailpage&action=edit emailpage]<br>
-[[MediaWiki_talk:Emailpage|Talk]]
+[http://tl.wiktionary.org/w/wiki.phtml?title=MediaWiki:Emailuser&action=edit emailuser]<br>
+[[MediaWiki_talk:Emailuser|Talk]]
</td><td>
E-mail user
</td><td>
-int:Emailpage
+int:Emailuser
</td></tr><tr><td>
[http://tl.wiktionary.org/w/wiki.phtml?title=MediaWiki:Emailpagetext&action=edit emailpagetext]<br>
[[MediaWiki_talk:Emailpagetext|Talk]]
diff --git a/tests/parser/preprocess/All_system_messages.txt b/tests/parser/preprocess/All_system_messages.txt
index c619df7b..cdc223a9 100644
--- a/tests/parser/preprocess/All_system_messages.txt
+++ b/tests/parser/preprocess/All_system_messages.txt
@@ -1370,12 +1370,12 @@ Message
{{int:Emailmessage}}
-[http://tl.wiktionary.org/w/wiki.phtml?title=MediaWiki:Emailpage&action=edit emailpage]
-[[MediaWiki_talk:Emailpage|Talk]]
+[http://tl.wiktionary.org/w/wiki.phtml?title=MediaWiki:Emailuser&action=edit emailuser]
+[[MediaWiki_talk:Emailuser|Talk]]
E-mail user
-{{int:Emailpage}}
+{{int:Emailuser}}
[http://tl.wiktionary.org/w/wiki.phtml?title=MediaWiki:Emailpagetext&action=edit emailpagetext]
[[MediaWiki_talk:Emailpagetext|Talk]]
diff --git a/tests/parserTests.php b/tests/parserTests.php
index 5d21319b..4d84025b 100644
--- a/tests/parserTests.php
+++ b/tests/parserTests.php
@@ -80,7 +80,7 @@ if ( isset( $options['file'] ) ) {
}
# Print out software version to assist with locating regressions
-$version = SpecialVersion::getVersion();
+$version = SpecialVersion::getVersion( 'nodb' );
echo "This is MediaWiki version {$version}.\n\n";
if ( isset( $options['fuzz'] ) ) {
diff --git a/tests/phpunit/LessFileCompilationTest.php b/tests/phpunit/LessFileCompilationTest.php
index df4690a4..eec02edc 100644
--- a/tests/phpunit/LessFileCompilationTest.php
+++ b/tests/phpunit/LessFileCompilationTest.php
@@ -45,11 +45,7 @@ class LessFileCompilationTest extends ResourceLoaderTestCase {
$method->setAccessible( true );
$compiler = $method->invoke( $this->module, $rlContext );
- $this->assertNotNull( $compiler->compileFile( $this->file ) );
- }
-
- public function getName( $withDataSet = true ) {
- return $this->toString();
+ $this->assertNotNull( $compiler->parseFile( $this->file )->getCss() );
}
public function toString() {
diff --git a/tests/phpunit/Makefile b/tests/phpunit/Makefile
index a33b86a3..e1537bf5 100644
--- a/tests/phpunit/Makefile
+++ b/tests/phpunit/Makefile
@@ -73,7 +73,6 @@ help:
#
# Targets:
# phpunit (default) Run all the tests with phpunit
- # install Install PHPUnit from phpunit.de
# tap Run the tests individually through Test::Harness's prove(1)
# help You're looking at it!
# coverage Run the tests and generates an HTML code coverage report
diff --git a/tests/phpunit/MediaWikiTestCase.php b/tests/phpunit/MediaWikiTestCase.php
index 72cac051..7dc7027a 100644
--- a/tests/phpunit/MediaWikiTestCase.php
+++ b/tests/phpunit/MediaWikiTestCase.php
@@ -204,13 +204,11 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
while ( $this->db->trxLevel() > 0 ) {
$this->db->rollback();
}
-
- // don't ignore DB errors
- $this->db->ignoreErrors( false );
}
DeferredUpdates::clearPendingUpdates();
+ ob_start( 'MediaWikiTestCase::wfResetOutputBuffersBarrier' );
}
protected function addTmpFiles( $files ) {
@@ -218,6 +216,11 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
}
protected function tearDown() {
+ $status = ob_get_status();
+ if ( isset( $status['name'] ) && $status['name'] === 'MediaWikiTestCase::wfResetOutputBuffersBarrier' ) {
+ ob_end_flush();
+ }
+
$this->called['tearDown'] = true;
// Cleaning up temporary files
foreach ( $this->tmpFiles as $fileName ) {
@@ -233,9 +236,6 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
while ( $this->db->trxLevel() > 0 ) {
$this->db->rollback();
}
-
- // don't ignore DB errors
- $this->db->ignoreErrors( false );
}
// Restore mw globals
@@ -716,9 +716,9 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
* @param string $function
*/
public function hideDeprecated( $function ) {
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
wfDeprecated( $function );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
}
/**
@@ -1002,9 +1002,9 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
# This check may also protect against code injection in
# case of broken installations.
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$haveDiff3 = $wgDiff3 && file_exists( $wgDiff3 );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !$haveDiff3 ) {
$this->markTestSkipped( "Skip test, since diff3 is not configured" );
@@ -1117,7 +1117,7 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
// of tidy. In that case however, we can not reliably detect whether a failing validation
// is due to malformed HTML, or caused by tidy not being installed as a command line tool.
// That would cause all HTML assertions to fail on a system that has no tidy installed.
- if ( !$GLOBALS['wgTidyInternal'] ) {
+ if ( !$GLOBALS['wgTidyInternal'] || !MWTidy::isEnabled() ) {
$this->markTestSkipped( 'Tidy extension not installed' );
}
@@ -1180,4 +1180,12 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
self::assertFalse( self::tagMatch( $matcher, $actual, $isHtml ), $message );
}
+
+ /**
+ * Used as a marker to prevent wfResetOutputBuffers from breaking PHPUnit.
+ * @return string
+ */
+ public static function wfResetOutputBuffersBarrier( $buffer ) {
+ return $buffer;
+ }
}
diff --git a/tests/phpunit/README b/tests/phpunit/README
index 0a32ba17..f555812d 100644
--- a/tests/phpunit/README
+++ b/tests/phpunit/README
@@ -14,16 +14,13 @@ TO RETAIN YOUR DATA.
== Installation ==
-If PHPUnit is not installed, follow the installation instructions in the
-PHPUnit Manual at:
-
- http://www.phpunit.de/manual/current/en/installation.html
+If you used composer to install MediaWiki's dependencies PHPUnit will already be available, unless
+you explicitly specified the --no-dev flag during the install. In this case just run "composer update".
-- or -
-
-On Unix-like operating systems, run:
+Otherwise follow the installation instructions in the
+PHPUnit Manual at:
- make install
+ https://phpunit.de/manual/current/en/installation.html
== Running tests ==
@@ -47,7 +44,7 @@ On Windows-family operating systems, run the 'run-tests.bat' batch file.
=== Writing tests ===
-A guide to writing unit tests for MediaWiki can be found at:
+A guide to writing PHP unit tests for MediaWiki can be found at:
- http://mediawiki.org/wiki/Unit_Testing
+ https://www.mediawiki.org/wiki/Manual:PHP_unit_testing
diff --git a/tests/phpunit/ResourceLoaderTestCase.php b/tests/phpunit/ResourceLoaderTestCase.php
index deecb31e..325b20ee 100644
--- a/tests/phpunit/ResourceLoaderTestCase.php
+++ b/tests/phpunit/ResourceLoaderTestCase.php
@@ -25,27 +25,35 @@ abstract class ResourceLoaderTestCase extends MediaWikiTestCase {
return $ctx;
}
- protected function setUp() {
- parent::setUp();
-
- ResourceLoader::clearCache();
-
- $this->setMwGlobals( array(
+ public static function getSettings() {
+ return array(
// For ResourceLoader::inDebugMode since it doesn't have context
- 'wgResourceLoaderDebug' => true,
+ 'ResourceLoaderDebug' => true,
// Avoid influence from wgInvalidateCacheOnLocalSettingsChange
- 'wgCacheEpoch' => '20140101000000',
+ 'CacheEpoch' => '20140101000000',
// For ResourceLoader::__construct()
- 'wgResourceLoaderSources' => array(),
+ 'ResourceLoaderSources' => array(),
// For wfScript()
- 'wgScriptPath' => '/w',
- 'wgScriptExtension' => '.php',
- 'wgScript' => '/w/index.php',
- 'wgLoadScript' => '/w/load.php',
- ) );
+ 'ScriptPath' => '/w',
+ 'ScriptExtension' => '.php',
+ 'Script' => '/w/index.php',
+ 'LoadScript' => '/w/load.php',
+ );
+ }
+
+ protected function setUp() {
+ parent::setUp();
+
+ ResourceLoader::clearCache();
+
+ $globals = array();
+ foreach ( self::getSettings() as $key => $value ) {
+ $globals['wg' . $key] = $value;
+ }
+ $this->setMwGlobals( $globals );
}
}
@@ -68,14 +76,14 @@ class ResourceLoaderTestModule extends ResourceLoaderModule {
}
public function getScript( ResourceLoaderContext $context ) {
- return $this->script;
+ return $this->validateScriptFile( 'input', $this->script );
}
public function getStyles( ResourceLoaderContext $context ) {
return array( '' => $this->styles );
}
- public function getDependencies() {
+ public function getDependencies( ResourceLoaderContext $context = null ) {
return $this->dependencies;
}
@@ -94,6 +102,10 @@ class ResourceLoaderTestModule extends ResourceLoaderModule {
public function isRaw() {
return $this->isRaw;
}
+
+ public function enableModuleContentVersion() {
+ return true;
+ }
}
class ResourceLoaderFileModuleTestModule extends ResourceLoaderFileModule {
diff --git a/tests/phpunit/data/css/comments.css b/tests/phpunit/data/css/comments.css
new file mode 100644
index 00000000..744a14c7
--- /dev/null
+++ b/tests/phpunit/data/css/comments.css
@@ -0,0 +1,7 @@
+/* url expressions in comments should be ignored */
+
+.selector { /*@noflip*/ background-image: /*@embed*/ url(not-commented.gif); }
+
+/*
+.selector { background-image: url(commented-out.gif); }
+*/
diff --git a/tests/phpunit/data/helpers/WellProtectedClass.php b/tests/phpunit/data/helpers/WellProtectedClass.php
index 99c7f642..a45cfbbf 100644
--- a/tests/phpunit/data/helpers/WellProtectedClass.php
+++ b/tests/phpunit/data/helpers/WellProtectedClass.php
@@ -1,20 +1,47 @@
privateParentProperty = 9000;
+ }
+
+ private function incrementPrivateParentPropertyValue() {
+ $this->privateParentProperty++;
+ }
+
+ public function getPrivateParentProperty() {
+ return $this->privateParentProperty;
+ }
+}
+
+class WellProtectedClass extends WellProtectedParentClass {
protected $property;
+ private $privateProperty;
public function __construct() {
+ parent::__construct();
$this->property = 1;
+ $this->privateProperty = 42;
}
protected function incrementPropertyValue() {
$this->property++;
}
+ private function incrementPrivatePropertyValue() {
+ $this->privateProperty++;
+ }
+
public function getProperty() {
return $this->property;
}
+ public function getPrivateProperty() {
+ return $this->privateProperty;
+ }
+
protected function whatSecondArg( $a, $b = false ) {
return $b;
}
diff --git a/tests/phpunit/data/import/ImportLinkCacheIntegrationTest.xml b/tests/phpunit/data/import/ImportLinkCacheIntegrationTest.xml
new file mode 100644
index 00000000..8949f406
--- /dev/null
+++ b/tests/phpunit/data/import/ImportLinkCacheIntegrationTest.xml
@@ -0,0 +1,43 @@
+
+
+ MW-19
+ http://localhost:8080/w/index.php/Main_Page
+ MediaWiki 1.19.7
+ first-letter
+
+
+ Lorem ipsum
+ 0
+ 493
+ 94lztkh4kgb0mvjr87iyjfq4iv7ltlh
+
+ 1358
+ 2014-04-04T22:55:04Z
+
+ Tester
+ 1
+
+ [[Has text::Lorem ipsum dolor sit amet consectetuer Maecenas adipiscing Pellentesque id sem]]. [[Has page::Elit Aliquam urna interdum]] morbi faucibus id tellus ipsum semper wisi. [[Has page::Platea enim hendrerit]] pellentesque consectetuer scelerisque Sed est felis felis quis. Auctor Proin In dolor id et ipsum vel at vitae ut. Praesent elit convallis Praesent aliquet pellentesque vel dolor pellentesque lacinia vitae. At tortor lacus Sed In interdum pulvinar et.
+
+[[Has number::1001]] [[Has quantity::10.25 km²]] [[Has date::1 Jan 2014]] [[Has Url::http://loremipsum.org/]] [[Has annotation uri::http://loremipsum.org/foaf.rdf]] [[Has email::Lorem@ipsum.org]] [[Has temperature::100 °C]] [[Has boolean::true]]
+
+[[Category:Lorem ipsum]]
+
+
+
+ Category:Lorem ipsum
+ 14
+ 496
+ sir97j6uzt9ev2uyhaz1aj4i3spogih
+
+ 1355
+ 2014-04-04T22:29:18Z
+
+ Tester
+ 1
+
+ [[Category:Main]]
+
+
+
+
diff --git a/tests/phpunit/data/less/common/test.common.mixins.less b/tests/phpunit/data/less/common/test.common.mixins.less
index 2fbe9b79..40647291 100644
--- a/tests/phpunit/data/less/common/test.common.mixins.less
+++ b/tests/phpunit/data/less/common/test.common.mixins.less
@@ -1,5 +1,4 @@
.test-mixin (@value) {
color: @value;
border: @foo solid @Foo;
- line-height: test-sum(@bar, 10, 20);
}
diff --git a/tests/phpunit/data/less/module/styles.css b/tests/phpunit/data/less/module/styles.css
index b78780a9..bac695b9 100644
--- a/tests/phpunit/data/less/module/styles.css
+++ b/tests/phpunit/data/less/module/styles.css
@@ -1,6 +1,5 @@
/* @noflip */
.unit-tests {
- color: green;
+ color: #008000;
border: 2px solid #eeeeee;
- line-height: 35;
}
diff --git a/tests/phpunit/data/media/2_webp_a.webp b/tests/phpunit/data/media/2_webp_a.webp
new file mode 100644
index 00000000..8764f066
Binary files /dev/null and b/tests/phpunit/data/media/2_webp_a.webp differ
diff --git a/tests/phpunit/data/media/2_webp_ll.webp b/tests/phpunit/data/media/2_webp_ll.webp
new file mode 100644
index 00000000..5794bbf2
Binary files /dev/null and b/tests/phpunit/data/media/2_webp_ll.webp differ
diff --git a/tests/phpunit/data/media/srgb.jpg b/tests/phpunit/data/media/srgb.jpg
new file mode 100644
index 00000000..b965dc4f
Binary files /dev/null and b/tests/phpunit/data/media/srgb.jpg differ
diff --git a/tests/phpunit/data/media/tinyrgb.icc b/tests/phpunit/data/media/tinyrgb.icc
new file mode 100644
index 00000000..eab973f5
Binary files /dev/null and b/tests/phpunit/data/media/tinyrgb.icc differ
diff --git a/tests/phpunit/data/media/tinyrgb.jpg b/tests/phpunit/data/media/tinyrgb.jpg
new file mode 100644
index 00000000..12a8e09f
Binary files /dev/null and b/tests/phpunit/data/media/tinyrgb.jpg differ
diff --git a/tests/phpunit/data/media/webp_animated.webp b/tests/phpunit/data/media/webp_animated.webp
new file mode 100644
index 00000000..25c6a4dd
Binary files /dev/null and b/tests/phpunit/data/media/webp_animated.webp differ
diff --git a/tests/phpunit/data/templates/bad_partial.mustache b/tests/phpunit/data/templates/bad_partial.mustache
new file mode 100644
index 00000000..d2767f0f
--- /dev/null
+++ b/tests/phpunit/data/templates/bad_partial.mustache
@@ -0,0 +1 @@
+Partial {{>nonexistenttemplate}} in here
diff --git a/tests/phpunit/data/templates/has_partial.mustache b/tests/phpunit/data/templates/has_partial.mustache
new file mode 100644
index 00000000..504387a4
--- /dev/null
+++ b/tests/phpunit/data/templates/has_partial.mustache
@@ -0,0 +1 @@
+Partial {{>foobar_args}} in here
diff --git a/tests/phpunit/includes/BlockTest.php b/tests/phpunit/includes/BlockTest.php
index 19741621..7b0de866 100644
--- a/tests/phpunit/includes/BlockTest.php
+++ b/tests/phpunit/includes/BlockTest.php
@@ -38,9 +38,13 @@ class BlockTest extends MediaWikiLangTestCase {
$oldBlock->delete();
}
- $this->block = new Block( 'UTBlockee', $user->getID(), 0,
- 'Parce que', 0, false, time() + 100500
+ $blockOptions = array(
+ 'address' => 'UTBlockee',
+ 'user' => $user->getID(),
+ 'reason' => 'Parce que',
+ 'expiry' => time() + 100500,
);
+ $this->block = new Block( $blockOptions );
$this->madeAt = wfTimestamp( TS_MW );
$this->block->insert();
@@ -151,22 +155,19 @@ class BlockTest extends MediaWikiLangTestCase {
);
// Foreign perspective (blockee not on current wiki)...
- $block = new Block(
- /* $address */ $username,
- /* $user */ 14146,
- /* $by */ 0,
- /* $reason */ 'crosswiki block...',
- /* $timestamp */ wfTimestampNow(),
- /* $auto */ false,
- /* $expiry */ $this->db->getInfinity(),
- /* anonOnly */ false,
- /* $createAccount */ true,
- /* $enableAutoblock */ true,
- /* $hideName (ipb_deleted) */ true,
- /* $blockEmail */ true,
- /* $allowUsertalk */ false,
- /* $byName */ 'MetaWikiUser'
+ $blockOptions = array(
+ 'address' => $username,
+ 'user' => 14146,
+ 'reason' => 'crosswiki block...',
+ 'timestamp' => wfTimestampNow(),
+ 'expiry' => $this->db->getInfinity(),
+ 'createAccount' => true,
+ 'enableAutoblock' => true,
+ 'hideName' => true,
+ 'blockEmail' => true,
+ 'byText' => 'MetaWikiUser',
);
+ $block = new Block( $blockOptions );
$block->insert();
// Reload block from DB
@@ -208,22 +209,19 @@ class BlockTest extends MediaWikiLangTestCase {
$this->db->update( 'user', array( 'user_id' => 14146 ), array( 'user_id' => $user->getId() ) );
// Foreign perspective (blockee not on current wiki)...
- $block = new Block(
- /* $address */ 'UserOnForeignWiki',
- /* $user */ 14146,
- /* $by */ 0,
- /* $reason */ 'crosswiki block...',
- /* $timestamp */ wfTimestampNow(),
- /* $auto */ false,
- /* $expiry */ $this->db->getInfinity(),
- /* anonOnly */ false,
- /* $createAccount */ true,
- /* $enableAutoblock */ true,
- /* $hideName (ipb_deleted) */ true,
- /* $blockEmail */ true,
- /* $allowUsertalk */ false,
- /* $byName */ 'MetaWikiUser'
+ $blockOptions = array(
+ 'address' => 'UserOnForeignWiki',
+ 'user' => 14146,
+ 'reason' => 'crosswiki block...',
+ 'timestamp' => wfTimestampNow(),
+ 'expiry' => $this->db->getInfinity(),
+ 'createAccount' => true,
+ 'enableAutoblock' => true,
+ 'hideName' => true,
+ 'blockEmail' => true,
+ 'byText' => 'MetaWikiUser',
);
+ $block = new Block( $blockOptions );
$res = $block->insert( $this->db );
$this->assertTrue( (bool)$res['id'], 'Block succeeded' );
@@ -367,4 +365,56 @@ class BlockTest extends MediaWikiLangTestCase {
$block = Block::chooseBlock( $xffblocks, $list );
$this->assertEquals( $exResult, $block->mReason, 'Correct block type for XFF header ' . $xff );
}
+
+ public function testDeprecatedConstructor() {
+ $this->hideDeprecated( 'Block::__construct with multiple arguments' );
+ $username = 'UnthinkablySecretRandomUsername';
+ $reason = 'being irrational';
+
+ # Set up the target
+ $u = User::newFromName( $username );
+ if ( $u->getID() == 0 ) {
+ $u->setPassword( 'TotallyObvious' );
+ $u->addToDatabase();
+ }
+ unset( $u );
+
+ # Make sure the user isn't blocked
+ $this->assertNull(
+ Block::newFromTarget( $username ),
+ "$username should not be blocked"
+ );
+
+ # Perform the block
+ $block = new Block(
+ /* address */ $username,
+ /* user */ 0,
+ /* by */ 0,
+ /* reason */ $reason,
+ /* timestamp */ 0,
+ /* auto */ false,
+ /* expiry */ 0
+ );
+ $block->insert();
+
+ # Check target
+ $this->assertEquals(
+ $block->getTarget()->getName(),
+ $username,
+ "Target should be set properly"
+ );
+
+ # Check supplied parameter
+ $this->assertEquals(
+ $block->mReason,
+ $reason,
+ "Reason should be non-default"
+ );
+
+ # Check default parameter
+ $this->assertFalse(
+ (bool)$block->prevents( 'createaccount' ),
+ "Account creation should not be blocked by default"
+ );
+ }
}
diff --git a/tests/phpunit/includes/ConsecutiveParametersMatcher.php b/tests/phpunit/includes/ConsecutiveParametersMatcher.php
new file mode 100644
index 00000000..adf74bb4
--- /dev/null
+++ b/tests/phpunit/includes/ConsecutiveParametersMatcher.php
@@ -0,0 +1,123 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Invocation matcher which looks for sets of specific parameters in the invocations.
+ *
+ * Checks the parameters of the incoming invocations, the parameter list is
+ * checked against the defined constraints in $parameters. If the constraint
+ * is met it will return true in matches().
+ *
+ * It takes a list of match groups and and increases a call index after each invocation.
+ * So the first invocation uses the first group of constraints, the second the next and so on.
+ */
+class PHPUnit_Framework_MockObject_Matcher_ConsecutiveParameters extends PHPUnit_Framework_MockObject_Matcher_StatelessInvocation
+{
+ /**
+ * @var array
+ */
+ private $_parameterGroups = array();
+
+ /**
+ * @var array
+ */
+ private $_invocations = array();
+
+ /**
+ * @param array $parameterGroups
+ */
+ public function __construct(array $parameterGroups)
+ {
+ foreach ($parameterGroups as $index => $parameters) {
+ foreach ($parameters as $parameter) {
+ if (!($parameter instanceof \PHPUnit_Framework_Constraint)) {
+ $parameter = new \PHPUnit_Framework_Constraint_IsEqual($parameter);
+ }
+ $this->_parameterGroups[$index][] = $parameter;
+ }
+ }
+ }
+
+ /**
+ * @return string
+ */
+ public function toString()
+ {
+ $text = 'with consecutive parameters';
+
+ return $text;
+ }
+
+ /**
+ * @param PHPUnit_Framework_MockObject_Invocation $invocation
+ * @return bool
+ */
+ public function matches(PHPUnit_Framework_MockObject_Invocation $invocation)
+ {
+ $this->_invocations[] = $invocation;
+ $callIndex = count($this->_invocations) - 1;
+ $this->verifyInvocation($invocation, $callIndex);
+
+ return false;
+ }
+
+ public function verify()
+ {
+ foreach ($this->_invocations as $callIndex => $invocation) {
+ $this->verifyInvocation($invocation, $callIndex);
+ }
+ }
+
+ /**
+ * Verify a single invocation
+ *
+ * @param PHPUnit_Framework_MockObject_Invocation $invocation
+ * @param int $callIndex
+ * @throws PHPUnit_Framework_ExpectationFailedException
+ */
+ private function verifyInvocation(PHPUnit_Framework_MockObject_Invocation $invocation, $callIndex)
+ {
+
+ if (isset($this->_parameterGroups[$callIndex])) {
+ $parameters = $this->_parameterGroups[$callIndex];
+ } else {
+ // no parameter assertion for this call index
+ return;
+ }
+
+ if ($invocation === null) {
+ throw new PHPUnit_Framework_ExpectationFailedException(
+ 'Mocked method does not exist.'
+ );
+ }
+
+ if (count($invocation->parameters) < count($parameters)) {
+ throw new PHPUnit_Framework_ExpectationFailedException(
+ sprintf(
+ 'Parameter count for invocation %s is too low.',
+ $invocation->toString()
+ )
+ );
+ }
+
+ foreach ($parameters as $i => $parameter) {
+ $parameter->evaluate(
+ $invocation->parameters[$i],
+ sprintf(
+ 'Parameter %s for invocation #%d %s does not match expected ' .
+ 'value.',
+ $i,
+ $callIndex,
+ $invocation->toString()
+ )
+ );
+ }
+ }
+}
diff --git a/tests/phpunit/includes/EditPageTest.php b/tests/phpunit/includes/EditPageTest.php
index 15778e40..27959b1d 100644
--- a/tests/phpunit/includes/EditPageTest.php
+++ b/tests/phpunit/includes/EditPageTest.php
@@ -11,6 +11,28 @@
*/
class EditPageTest extends MediaWikiLangTestCase {
+ protected function setUp() {
+ global $wgExtraNamespaces, $wgNamespaceContentModels, $wgContentHandlers, $wgContLang;
+
+ parent::setUp();
+
+ $this->setMwGlobals( array(
+ 'wgExtraNamespaces' => $wgExtraNamespaces,
+ 'wgNamespaceContentModels' => $wgNamespaceContentModels,
+ 'wgContentHandlers' => $wgContentHandlers,
+ 'wgContLang' => $wgContLang,
+ ) );
+
+ $wgExtraNamespaces[12312] = 'Dummy';
+ $wgExtraNamespaces[12313] = 'Dummy_talk';
+
+ $wgNamespaceContentModels[12312] = "testing";
+ $wgContentHandlers["testing"] = 'DummyContentHandlerForTesting';
+
+ MWNamespace::getCanonicalNamespaces( true ); # reset namespace cache
+ $wgContLang->resetNamespaces(); # reset namespace cache
+ }
+
/**
* @dataProvider provideExtractSectionTitle
* @covers EditPage::extractSectionTitle
@@ -499,4 +521,37 @@ hello
$this->assertEdit( 'EditPageTest_testAutoMerge', null, 'Berta', $bertasEdit,
$expectedCode, $expectedText, $message );
}
+
+ /**
+ * @depends testAutoMerge
+ */
+ public function testCheckDirectEditingDisallowed_forNonTextContent() {
+ $title = Title::newFromText( 'Dummy:NonTextPageForEditPage' );
+ $page = WikiPage::factory( $title );
+
+ $article = new Article( $title );
+ $article->getContext()->setTitle( $title );
+ $ep = new EditPage( $article );
+ $ep->setContextTitle( $title );
+
+ $user = $GLOBALS['wgUser'];
+
+ $edit = array(
+ 'wpTextbox1' => serialize( 'non-text content' ),
+ 'wpEditToken' => $user->getEditToken(),
+ 'wpEdittime' => '',
+ 'wpStarttime' => wfTimestampNow()
+ );
+
+ $req = new FauxRequest( $edit, true );
+ $ep->importFormData( $req );
+
+ $this->setExpectedException(
+ 'MWException',
+ 'This content model is not supported: testing'
+ );
+
+ $ep->internalAttemptSave( $result, false );
+ }
+
}
diff --git a/tests/phpunit/includes/ExtraParserTest.php b/tests/phpunit/includes/ExtraParserTest.php
index 4a4130e0..7b60fb3f 100644
--- a/tests/phpunit/includes/ExtraParserTest.php
+++ b/tests/phpunit/includes/ExtraParserTest.php
@@ -2,6 +2,8 @@
/**
* Parser-related tests that don't suit for parserTests.txt
+ *
+ * @group Database
*/
class ExtraParserTest extends MediaWikiTestCase {
@@ -20,7 +22,6 @@ class ExtraParserTest extends MediaWikiTestCase {
'wgContLang' => $contLang,
'wgLang' => Language::factory( 'en' ),
'wgMemc' => new EmptyBagOStuff,
- 'wgAlwaysUseTidy' => false,
'wgCleanSignatures' => true,
) );
diff --git a/tests/phpunit/includes/FauxRequestTest.php b/tests/phpunit/includes/FauxRequestTest.php
index 745a5b42..07214b21 100644
--- a/tests/phpunit/includes/FauxRequestTest.php
+++ b/tests/phpunit/includes/FauxRequestTest.php
@@ -6,13 +6,46 @@ class FauxRequestTest extends MediaWikiTestCase {
* @covers FauxRequest::getHeader
*/
public function testGetSetHeader() {
- $value = 'test/test';
+ $value = 'text/plain, text/html';
$request = new FauxRequest();
- $request->setHeader( 'Content-Type', $value );
+ $request->setHeader( 'Accept', $value );
- $this->assertEquals( $request->getHeader( 'Content-Type' ), $value );
- $this->assertEquals( $request->getHeader( 'CONTENT-TYPE' ), $value );
- $this->assertEquals( $request->getHeader( 'content-type' ), $value );
+ $this->assertEquals( $request->getHeader( 'Nonexistent' ), false );
+ $this->assertEquals( $request->getHeader( 'Accept' ), $value );
+ $this->assertEquals( $request->getHeader( 'ACCEPT' ), $value );
+ $this->assertEquals( $request->getHeader( 'accept' ), $value );
+ $this->assertEquals(
+ $request->getHeader( 'Accept', WebRequest::GETHEADER_LIST ),
+ array( 'text/plain', 'text/html' )
+ );
+ }
+
+ /**
+ * @covers FauxRequest::getAllHeaders
+ */
+ public function testGetAllHeaders() {
+ $_SERVER['HTTP_TEST'] = 'Example';
+
+ $request = new FauxRequest();
+
+ $this->assertEquals(
+ array(),
+ $request->getAllHeaders()
+ );
+ }
+
+ /**
+ * @covers FauxRequest::getHeader
+ */
+ public function testGetHeader() {
+ $_SERVER['HTTP_TEST'] = 'Example';
+
+ $request = new FauxRequest();
+
+ $this->assertEquals(
+ false,
+ $request->getHeader( 'test' )
+ );
}
}
diff --git a/tests/phpunit/includes/FauxResponseTest.php b/tests/phpunit/includes/FauxResponseTest.php
index 4a974ba2..39a0effa 100644
--- a/tests/phpunit/includes/FauxResponseTest.php
+++ b/tests/phpunit/includes/FauxResponseTest.php
@@ -108,6 +108,13 @@ class FauxResponseTest extends MediaWikiTestCase {
'Third parameter overrides the HTTP/... header'
);
+ $this->response->statusHeader( 210 );
+ $this->assertEquals(
+ 210,
+ $this->response->getStatusCode(),
+ 'Handle statusHeader method'
+ );
+
$this->response->header( 'Location: http://localhost/', false, 206 );
$this->assertEquals(
206,
diff --git a/tests/phpunit/includes/GlobalFunctions/GlobalTest.php b/tests/phpunit/includes/GlobalFunctions/GlobalTest.php
index 1e30273e..e89e36f6 100644
--- a/tests/phpunit/includes/GlobalFunctions/GlobalTest.php
+++ b/tests/phpunit/includes/GlobalFunctions/GlobalTest.php
@@ -666,9 +666,9 @@ class GlobalTest extends MediaWikiTestCase {
public function testWfMkdirParents() {
// Should not return true if file exists instead of directory
$fname = $this->getNewTempFile();
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$ok = wfMkdirParents( $fname );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
$this->assertFalse( $ok );
}
@@ -687,6 +687,105 @@ class GlobalTest extends MediaWikiTestCase {
$this->assertEquals( $expected, $actual, $description );
}
+ public function wfWikiID() {
+ $this->setMwGlobals( array(
+ 'wgDBname' => 'example',
+ 'wgDBprefix' => '',
+ ) );
+ $this->assertEquals(
+ wfWikiID(),
+ 'example'
+ );
+
+ $this->setMwGlobals( array(
+ 'wgDBname' => 'example',
+ 'wgDBprefix' => 'mw_',
+ ) );
+ $this->assertEquals(
+ wfWikiID(),
+ 'example-mw_'
+ );
+ }
+
+ public function testWfMemcKey() {
+ // Just assert the exact output so we can catch unintentional changes to key
+ // construction, which would effectively invalidate all existing cache.
+
+ $this->setMwGlobals( array(
+ 'wgCachePrefix' => false,
+ 'wgDBname' => 'example',
+ 'wgDBprefix' => '',
+ ) );
+ $this->assertEquals(
+ wfMemcKey( 'foo', '123', 'bar' ),
+ 'example:foo:123:bar'
+ );
+
+ $this->setMwGlobals( array(
+ 'wgCachePrefix' => false,
+ 'wgDBname' => 'example',
+ 'wgDBprefix' => 'mw_',
+ ) );
+ $this->assertEquals(
+ wfMemcKey( 'foo', '123', 'bar' ),
+ 'example-mw_:foo:123:bar'
+ );
+
+ $this->setMwGlobals( array(
+ 'wgCachePrefix' => 'custom',
+ 'wgDBname' => 'example',
+ 'wgDBprefix' => 'mw_',
+ ) );
+ $this->assertEquals(
+ wfMemcKey( 'foo', '123', 'bar' ),
+ 'custom:foo:123:bar'
+ );
+ }
+
+ public function testWfForeignMemcKey() {
+ $this->setMwGlobals( array(
+ 'wgCachePrefix' => false,
+ 'wgDBname' => 'example',
+ 'wgDBprefix' => '',
+ ) );
+ $local = wfMemcKey( 'foo', 'bar' );
+
+ $this->setMwGlobals( array(
+ 'wgDBname' => 'other',
+ 'wgDBprefix' => 'mw_',
+ ) );
+ $this->assertEquals(
+ wfForeignMemcKey( 'example', '', 'foo', 'bar' ),
+ $local,
+ 'Match output of wfMemcKey from local wiki'
+ );
+ }
+
+ public function testWfGlobalCacheKey() {
+ $this->setMwGlobals( array(
+ 'wgCachePrefix' => 'ignored',
+ 'wgDBname' => 'example',
+ 'wgDBprefix' => ''
+ ) );
+ $one = wfGlobalCacheKey( 'some', 'thing' );
+ $this->assertEquals(
+ $one,
+ 'global:some:thing'
+ );
+
+ $this->setMwGlobals( array(
+ 'wgDBname' => 'other',
+ 'wgDBprefix' => 'mw_'
+ ) );
+ $two = wfGlobalCacheKey( 'some', 'thing' );
+
+ $this->assertEquals(
+ $one,
+ $two,
+ 'Not fragmented by wiki id'
+ );
+ }
+
public static function provideWfShellWikiCmdList() {
global $wgPhpCli;
diff --git a/tests/phpunit/includes/GlobalFunctions/wfArrayPlus2dTest.php b/tests/phpunit/includes/GlobalFunctions/wfArrayPlus2dTest.php
new file mode 100644
index 00000000..88875bb0
--- /dev/null
+++ b/tests/phpunit/includes/GlobalFunctions/wfArrayPlus2dTest.php
@@ -0,0 +1,94 @@
+assertEquals(
+ $expected,
+ wfArrayPlus2d( $baseArray, $newValues ),
+ $testName
+ );
+ }
+
+ /**
+ * Provider for testing wfArrayPlus2d
+ *
+ * @return array
+ */
+ public static function provideArrays() {
+ return array(
+ // target array, new values array, expected result
+ array(
+ array( 0 => '1dArray' ),
+ array( 1 => '1dArray' ),
+ array( 0 => '1dArray', 1 => '1dArray' ),
+ "Test simple union of two arrays with different keys",
+ ),
+ array(
+ array(
+ 0 => array( 0 => '2dArray' ),
+ ),
+ array(
+ 0 => array( 1 => '2dArray' ),
+ ),
+ array(
+ 0 => array( 0 => '2dArray', 1 => '2dArray' ),
+ ),
+ "Test union of 2d arrays with different keys in the value array",
+ ),
+ array(
+ array(
+ 0 => array( 0 => '2dArray' ),
+ ),
+ array(
+ 0 => array( 0 => '1dArray' ),
+ ),
+ array(
+ 0 => array( 0 => '2dArray' ),
+ ),
+ "Test union of 2d arrays with same keys in the value array",
+ ),
+ array(
+ array(
+ 0 => array( 0 => array( 0 => '3dArray' ) ),
+ ),
+ array(
+ 0 => array( 0 => array( 1 => '2dArray' ) ),
+ ),
+ array(
+ 0 => array( 0 => array( 0 => '3dArray' ) ),
+ ),
+ "Test union of 3d array with different keys",
+ ),
+ array(
+ array(
+ 0 => array( 0 => array( 0 => '3dArray' ) ),
+ ),
+ array(
+ 0 => array( 1 => array( 0 => '2dArray' ) ),
+ ),
+ array(
+ 0 => array( 0 => array( 0 => '3dArray' ), 1 => array( 0 => '2dArray' ) ),
+ ),
+ "Test union of 3d array with different keys in the value array",
+ ),
+ array(
+ array(
+ 0 => array( 0 => array( 0 => '3dArray' ) ),
+ ),
+ array(
+ 0 => array( 0 => array( 0 => '2dArray' ) ),
+ ),
+ array(
+ 0 => array( 0 => array( 0 => '3dArray' ) ),
+ ),
+ "Test union of 3d array with same keys in the value array",
+ ),
+ );
+ }
+}
diff --git a/tests/phpunit/includes/GlobalFunctions/wfTimestampTest.php b/tests/phpunit/includes/GlobalFunctions/wfTimestampTest.php
index bea496c4..4ce51c6a 100644
--- a/tests/phpunit/includes/GlobalFunctions/wfTimestampTest.php
+++ b/tests/phpunit/includes/GlobalFunctions/wfTimestampTest.php
@@ -21,6 +21,7 @@ class WfTimestampTest extends MediaWikiTestCase {
array( -30281104, TS_MW, '19690115123456', 'Negative TS_UNIX to TS_MW' ),
array( $t, TS_UNIX, 979562096, 'TS_UNIX to TS_UNIX' ),
array( $t, TS_DB, '2001-01-15 12:34:56', 'TS_UNIX to TS_DB' ),
+ array( $t + .01, TS_MW, '20010115123456', 'TS_UNIX float to TS_MW' ),
array( $t, TS_ISO_8601_BASIC, '20010115T123456Z', 'TS_ISO_8601_BASIC to TS_DB' ),
diff --git a/tests/phpunit/includes/GlobalFunctions/wfUrlencodeTest.php b/tests/phpunit/includes/GlobalFunctions/wfUrlencodeTest.php
index d11668b7..d4df7b00 100644
--- a/tests/phpunit/includes/GlobalFunctions/wfUrlencodeTest.php
+++ b/tests/phpunit/includes/GlobalFunctions/wfUrlencodeTest.php
@@ -112,6 +112,8 @@ class WfUrlencodeTest extends MediaWikiTestCase {
### Other tests
// slash remain unchanged. %2F seems to break things
array( '/', '/' ),
+ // T105265
+ array( '~', '~' ),
// Other 'funnies' chars
array( '[]', '%5B%5D' ),
diff --git a/tests/phpunit/includes/ImportLinkCacheIntegrationTest.php b/tests/phpunit/includes/ImportLinkCacheIntegrationTest.php
new file mode 100644
index 00000000..1433b898
--- /dev/null
+++ b/tests/phpunit/includes/ImportLinkCacheIntegrationTest.php
@@ -0,0 +1,112 @@
+importStreamSource = ImportStreamSource::newFromFile( $file );
+
+ if ( !$this->importStreamSource->isGood() ) {
+ throw new Exception( "Import source for {$file} failed" );
+ }
+ }
+
+ public function testImportForImportSource() {
+
+ $this->doImport( $this->importStreamSource );
+
+ // Imported title
+ $loremIpsum = Title::newFromText( 'Lorem ipsum' );
+
+ $this->assertSame(
+ $loremIpsum->getArticleID(),
+ $loremIpsum->getArticleID( Title::GAID_FOR_UPDATE )
+ );
+
+ $categoryLoremIpsum = Title::newFromText( 'Category:Lorem ipsum' );
+
+ $this->assertSame(
+ $categoryLoremIpsum->getArticleID(),
+ $categoryLoremIpsum->getArticleID( Title::GAID_FOR_UPDATE )
+ );
+
+ $page = new WikiPage( $loremIpsum );
+ $page->doDeleteArticle( 'import test: delete page' );
+
+ $page = new WikiPage( $categoryLoremIpsum );
+ $page->doDeleteArticle( 'import test: delete page' );
+ }
+
+ /**
+ * @depends testImportForImportSource
+ */
+ public function testReImportForImportSource() {
+
+ $this->doImport( $this->importStreamSource );
+
+ // ReImported title
+ $loremIpsum = Title::newFromText( 'Lorem ipsum' );
+
+ $this->assertSame(
+ $loremIpsum->getArticleID(),
+ $loremIpsum->getArticleID( Title::GAID_FOR_UPDATE )
+ );
+
+ $categoryLoremIpsum = Title::newFromText( 'Category:Lorem ipsum' );
+
+ $this->assertSame(
+ $categoryLoremIpsum->getArticleID(),
+ $categoryLoremIpsum->getArticleID( Title::GAID_FOR_UPDATE )
+ );
+ }
+
+ private function doImport( $importStreamSource ) {
+
+ $importer = new WikiImporter(
+ $importStreamSource->value,
+ ConfigFactory::getDefaultInstance()->makeConfig( 'main' )
+ );
+ $importer->setDebug( true );
+
+ $reporter = new ImportReporter(
+ $importer,
+ false,
+ '',
+ false
+ );
+
+ $reporter->setContext( new RequestContext() );
+ $reporter->open();
+ $exception = false;
+
+ try {
+ $importer->doImport();
+ } catch ( Exception $e ) {
+ $exception = $e;
+ }
+
+ $result = $reporter->close();
+
+ $this->assertFalse(
+ $exception
+ );
+
+ $this->assertTrue(
+ $result->isGood()
+ );
+ }
+
+}
diff --git a/tests/phpunit/includes/LinkFilterTest.php b/tests/phpunit/includes/LinkFilterTest.php
index f2c9cb43..68081059 100644
--- a/tests/phpunit/includes/LinkFilterTest.php
+++ b/tests/phpunit/includes/LinkFilterTest.php
@@ -76,7 +76,7 @@ class LinkFilterTest extends MediaWikiLangTestCase {
array( 'https://', '*.com', 'https://name:pass@secure.com/index.html' ),
array( 'http://', 'name:pass@test.com', 'http://test.com' ),
array( 'http://', 'test.com', 'http://name:pass@test.com' ),
- array( 'http://', '*.test.com', 'http://a.b.c.test.com/dir/dir/file?a=6'),
+ array( 'http://', '*.test.com', 'http://a.b.c.test.com/dir/dir/file?a=6' ),
array( null, 'http://*.test.com', 'http://www.test.com' ),
array( 'mailto:', 'name@mail.test123.com', 'mailto:name@mail.test123.com' ),
array( '',
@@ -122,8 +122,8 @@ class LinkFilterTest extends MediaWikiLangTestCase {
array( '', 'git://github.com/prwef/abc-def.git', 'git://github.com/prwef/abc-def.git' ),
array( 'git://', 'github.com/', 'git://github.com/prwef/abc-def.git' ),
array( 'git://', '*.github.com/', 'git://a.b.c.d.e.f.github.com/prwef/abc-def.git' ),
- array( '', 'gopher://*.test.com/', 'gopher://gopher.test.com/0/v2/vstat'),
- array( 'telnet://', '*.test.com', 'telnet://shell.test.com/~home/'),
+ array( '', 'gopher://*.test.com/', 'gopher://gopher.test.com/0/v2/vstat' ),
+ array( 'telnet://', '*.test.com', 'telnet://shell.test.com/~home/' ),
//
// The following only work in PHP >= 5.3.7, due to a bug in parse_url which eats
@@ -243,10 +243,10 @@ class LinkFilterTest extends MediaWikiLangTestCase {
array( 'http://*.test.*' ),
array( 'http://*test.com' ),
array( 'https://*' ),
- array( '*://test.com'),
+ array( '*://test.com' ),
array( 'mailto:name:pass@t*est.com' ),
- array( 'http://*:888/'),
- array( '*http://'),
+ array( 'http://*:888/' ),
+ array( '*http://' ),
array( 'test.com/*/index' ),
array( 'test.com/dir/index?arg=*' ),
);
diff --git a/tests/phpunit/includes/LinkerTest.php b/tests/phpunit/includes/LinkerTest.php
index 823c9330..a3efbb8d 100644
--- a/tests/phpunit/includes/LinkerTest.php
+++ b/tests/phpunit/includes/LinkerTest.php
@@ -93,12 +93,26 @@ class LinkerTest extends MediaWikiLangTestCase {
* @covers Linker::formatAutocomments
* @covers Linker::formatLinksInComment
*/
- public function testFormatComment( $expected, $comment, $title = false, $local = false ) {
+ public function testFormatComment( $expected, $comment, $title = false, $local = false, $wikiId = null ) {
+ $conf = new SiteConfiguration();
+ $conf->settings = array(
+ 'wgServer' => array(
+ 'enwiki' => '//en.example.org',
+ 'dewiki' => '//de.example.org',
+ ),
+ 'wgArticlePath' => array(
+ 'enwiki' => '/w/$1',
+ 'dewiki' => '/w/$1',
+ ),
+ );
+ $conf->suffixes = array( 'wiki' );
+
$this->setMwGlobals( array(
'wgScript' => '/wiki/index.php',
'wgArticlePath' => '/wiki/$1',
'wgWellFormedXml' => true,
'wgCapitalLinks' => true,
+ 'wgConf' => $conf,
) );
if ( $title === false ) {
@@ -108,11 +122,13 @@ class LinkerTest extends MediaWikiLangTestCase {
$this->assertEquals(
$expected,
- Linker::formatComment( $comment, $title, $local )
+ Linker::formatComment( $comment, $title, $local, $wikiId )
);
}
- public static function provideCasesForFormatComment() {
+ public function provideCasesForFormatComment() {
+ $wikiId = 'enwiki'; // $wgConf has a fake entry for this
+
return array(
// Linker::formatComment
array(
@@ -127,6 +143,10 @@ class LinkerTest extends MediaWikiLangTestCase {
"'''not bolded'''",
"'''not bolded'''",
),
+ array(
+ "try <script>evil</scipt> things",
+ "try */"
+ ),
array(
'→ ',
"/* autocomment */",
@@ -166,6 +194,16 @@ class LinkerTest extends MediaWikiLangTestCase {
"/* autocomment */",
null
),
+ array(
+ '→ ',
+ "/* autocomment */",
+ false, false
+ ),
+ array(
+ '→ ',
+ "/* autocomment */",
+ false, false, $wikiId
+ ),
// Linker::formatLinksInComment
array(
'abc link def',
@@ -191,6 +229,28 @@ class LinkerTest extends MediaWikiLangTestCase {
'abc /subpage def',
"abc [[/subpage]] def",
),
+ array(
+ 'abc "evil!" def',
+ "abc [[\"evil!\"]] def",
+ ),
+ array(
+ 'abc [[<script>very evil</script>]] def',
+ "abc [[]] def",
+ ),
+ array(
+ 'abc [[|]] def',
+ "abc [[|]] def",
+ ),
+ array(
+ 'abc link def',
+ "abc [[link]] def",
+ false, false
+ ),
+ array(
+ 'abc link def',
+ "abc [[link]] def",
+ false, false, $wikiId
+ )
);
}
diff --git a/tests/phpunit/includes/MediaWikiTest.php b/tests/phpunit/includes/MediaWikiTest.php
new file mode 100644
index 00000000..e1962436
--- /dev/null
+++ b/tests/phpunit/includes/MediaWikiTest.php
@@ -0,0 +1,157 @@
+setMwGlobals( array(
+ 'wgServer' => 'http://example.org',
+ 'wgScriptPath' => '/w',
+ 'wgScript' => '/w/index.php',
+ 'wgArticlePath' => '/wiki/$1',
+ 'wgActionPaths' => array(),
+ ) );
+ }
+
+ public static function provideTryNormaliseRedirect() {
+ return array(
+ array(
+ // View: Canonical
+ 'url' => 'http://example.org/wiki/Foo_Bar',
+ 'query' => array(),
+ 'title' => 'Foo_Bar',
+ 'redirect' => false,
+ ),
+ array(
+ // View: Escaped title
+ 'url' => 'http://example.org/wiki/Foo%20Bar',
+ 'query' => array(),
+ 'title' => 'Foo_Bar',
+ 'redirect' => 'http://example.org/wiki/Foo_Bar',
+ ),
+ array(
+ // View: Script path
+ 'url' => 'http://example.org/w/index.php?title=Foo_Bar',
+ 'query' => array( 'title' => 'Foo_Bar' ),
+ 'title' => 'Foo_Bar',
+ 'redirect' => 'http://example.org/wiki/Foo_Bar',
+ ),
+ array(
+ // View: Script path with implicit title from page id
+ 'url' => 'http://example.org/w/index.php?curid=123',
+ 'query' => array( 'curid' => '123' ),
+ 'title' => 'Foo_Bar',
+ 'redirect' => false,
+ ),
+ array(
+ // View: Script path with implicit title from revision id
+ 'url' => 'http://example.org/w/index.php?oldid=123',
+ 'query' => array( 'oldid' => '123' ),
+ 'title' => 'Foo_Bar',
+ 'redirect' => false,
+ ),
+ array(
+ // View: Script path without title
+ 'url' => 'http://example.org/w/index.php',
+ 'query' => array(),
+ 'title' => 'Main_Page',
+ 'redirect' => 'http://example.org/wiki/Main_Page',
+ ),
+ array(
+ // View: Script path with empty title
+ 'url' => 'http://example.org/w/index.php?title=',
+ 'query' => array( 'title' => '' ),
+ 'title' => 'Main_Page',
+ 'redirect' => 'http://example.org/wiki/Main_Page',
+ ),
+ array(
+ // View: Index with escaped title
+ 'url' => 'http://example.org/w/index.php?title=Foo%20Bar',
+ 'query' => array( 'title' => 'Foo Bar' ),
+ 'title' => 'Foo_Bar',
+ 'redirect' => 'http://example.org/wiki/Foo_Bar',
+ ),
+ array(
+ // View: Script path with escaped title
+ 'url' => 'http://example.org/w/?title=Foo_Bar',
+ 'query' => array( 'title' => 'Foo_Bar' ),
+ 'title' => 'Foo_Bar',
+ 'redirect' => 'http://example.org/wiki/Foo_Bar',
+ ),
+ array(
+ // View: Root path with escaped title
+ 'url' => 'http://example.org/?title=Foo_Bar',
+ 'query' => array( 'title' => 'Foo_Bar' ),
+ 'title' => 'Foo_Bar',
+ 'redirect' => 'http://example.org/wiki/Foo_Bar',
+ ),
+ array(
+ // View: Canonical with redundant query
+ 'url' => 'http://example.org/wiki/Foo_Bar?action=view',
+ 'query' => array( 'action' => 'view' ),
+ 'title' => 'Foo_Bar',
+ 'redirect' => 'http://example.org/wiki/Foo_Bar',
+ ),
+ array(
+ // Edit: Canonical view url with action query
+ 'url' => 'http://example.org/wiki/Foo_Bar?action=edit',
+ 'query' => array( 'action' => 'edit' ),
+ 'title' => 'Foo_Bar',
+ 'redirect' => false,
+ ),
+ array(
+ // View: Index with action query
+ 'url' => 'http://example.org/w/index.php?title=Foo_Bar&action=view',
+ 'query' => array( 'title' => 'Foo_Bar', 'action' => 'view' ),
+ 'title' => 'Foo_Bar',
+ 'redirect' => 'http://example.org/wiki/Foo_Bar',
+ ),
+ array(
+ // Edit: Index with action query
+ 'url' => 'http://example.org/w/index.php?title=Foo_Bar&action=edit',
+ 'query' => array( 'title' => 'Foo_Bar', 'action' => 'edit' ),
+ 'title' => 'Foo_Bar',
+ 'redirect' => false,
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideTryNormaliseRedirect
+ * @covers MediaWiki::tryNormaliseRedirect
+ */
+ public function testTryNormaliseRedirect( $url, $query, $title, $expectedRedirect = false ) {
+ // Set SERVER because interpolateTitle() doesn't use getRequestURL(),
+ // whereas tryNormaliseRedirect does().
+ $_SERVER['REQUEST_URI'] = $url;
+
+ $req = new FauxRequest( $query );
+ $req->setRequestURL( $url );
+ // This adds a virtual 'title' query parameter. Normally called from Setup.php
+ $req->interpolateTitle();
+
+ $titleObj = Title::newFromText( $title );
+
+ // Set global context since some involved code paths don't yet have context
+ $context = RequestContext::getMain();
+ $context->setRequest( $req );
+ $context->setTitle( $titleObj );
+
+ $mw = new MediaWiki( $context );
+
+ $method = new ReflectionMethod( $mw, 'tryNormaliseRedirect' );
+ $method->setAccessible( true );
+ $ret = $method->invoke( $mw, $titleObj );
+
+ $this->assertEquals(
+ $expectedRedirect !== false,
+ $ret,
+ 'Return true only when redirecting'
+ );
+
+ $this->assertEquals(
+ $expectedRedirect ?: '',
+ $context->getOutput()->getRedirect()
+ );
+ }
+}
diff --git a/tests/phpunit/includes/MessageTest.php b/tests/phpunit/includes/MessageTest.php
index 99ec2e42..9c953a6d 100644
--- a/tests/phpunit/includes/MessageTest.php
+++ b/tests/phpunit/includes/MessageTest.php
@@ -21,6 +21,17 @@ class MessageTest extends MediaWikiLangTestCase {
$this->assertEquals( $key, $message->getKey() );
$this->assertEquals( $params, $message->getParams() );
$this->assertEquals( $expectedLang, $message->getLanguage() );
+
+ $messageSpecifier = $this->getMockForAbstractClass( 'MessageSpecifier' );
+ $messageSpecifier->expects( $this->any() )
+ ->method( 'getKey' )->will( $this->returnValue( $key ) );
+ $messageSpecifier->expects( $this->any() )
+ ->method( 'getParams' )->will( $this->returnValue( $params ) );
+ $message = new Message( $messageSpecifier, array(), $language );
+
+ $this->assertEquals( $key, $message->getKey() );
+ $this->assertEquals( $params, $message->getParams() );
+ $this->assertEquals( $expectedLang, $message->getLanguage() );
}
public static function provideConstructor() {
@@ -548,4 +559,26 @@ class MessageTest extends MediaWikiLangTestCase {
public function testInLanguageThrows() {
wfMessage( 'foo' )->inLanguage( 123 );
}
+
+ /**
+ * @covers Message::serialize
+ * @covers Message::unserialize
+ */
+ public function testSerialization() {
+ $msg = new Message( 'parentheses' );
+ $msg->rawParams( 'foo ' );
+ $msg->title( Title::newFromText( 'Testing' ) );
+ $this->assertEquals( '(foo )', $msg->parse(), 'Sanity check' );
+ $msg = unserialize( serialize( $msg ) );
+ $this->assertEquals( '(foo )', $msg->parse() );
+ $title = TestingAccessWrapper::newFromObject( $msg )->title;
+ $this->assertInstanceOf( 'Title', $title );
+ $this->assertEquals( 'Testing', $title->getFullText() );
+
+ $msg = new Message( 'mainpage' );
+ $msg->inLanguage( 'de' );
+ $this->assertEquals( 'Hauptseite', $msg->plain(), 'Sanity check' );
+ $msg = unserialize( serialize( $msg ) );
+ $this->assertEquals( 'Hauptseite', $msg->plain() );
+ }
}
diff --git a/tests/phpunit/includes/MimeMagicTest.php b/tests/phpunit/includes/MimeMagicTest.php
index 742d3827..3c45f305 100644
--- a/tests/phpunit/includes/MimeMagicTest.php
+++ b/tests/phpunit/includes/MimeMagicTest.php
@@ -1,5 +1,5 @@
getRevision()
);
$this->assertNotNull(
- WikiPage::factory( $newTitle)->getRevision()
+ WikiPage::factory( $newTitle )->getRevision()
);
}
}
diff --git a/tests/phpunit/includes/OutputPageTest.php b/tests/phpunit/includes/OutputPageTest.php
index 6c6d95ee..f0d905e5 100644
--- a/tests/phpunit/includes/OutputPageTest.php
+++ b/tests/phpunit/includes/OutputPageTest.php
@@ -141,53 +141,36 @@ class OutputPageTest extends MediaWikiTestCase {
// Load module script only
array(
array( 'test.foo', ResourceLoaderModule::TYPE_SCRIPTS ),
- '
-'
+ ""
),
array(
// Don't condition wrap raw modules (like the startup module)
array( 'test.raw', ResourceLoaderModule::TYPE_SCRIPTS ),
- '
-'
+ ''
),
// Load module styles only
// This also tests the order the modules are put into the url
array(
array( array( 'test.baz', 'test.foo', 'test.bar' ), ResourceLoaderModule::TYPE_STYLES ),
- '
-'
+
+ ' '
),
// Load private module (only=scripts)
array(
array( 'test.quux', ResourceLoaderModule::TYPE_SCRIPTS ),
- '
-'
+ ""
),
// Load private module (combined)
array(
array( 'test.quux', ResourceLoaderModule::TYPE_COMBINED ),
- '
-'
- ),
- // Load module script with ESI
- array(
- array( 'test.foo', ResourceLoaderModule::TYPE_SCRIPTS, true ),
- '
-'
- ),
- // Load module styles with ESI
- array(
- array( 'test.foo', ResourceLoaderModule::TYPE_STYLES, true ),
- '
-',
+ ""
),
// Load no modules
array(
@@ -197,19 +180,17 @@ mw.loader.implement("test.quux",function($,jQuery){mw.test.baz({token:123});},{"
// noscript group
array(
array( 'test.noscript', ResourceLoaderModule::TYPE_STYLES ),
- '
-'
+ ' '
),
// Load two modules in separate groups
array(
array( array( 'test.group.foo', 'test.group.bar' ), ResourceLoaderModule::TYPE_COMBINED ),
- '
-
-'
+ "\n"
+ . ""
),
);
}
@@ -226,7 +207,6 @@ document.write("\u003Cscript src=\"http://127.0.0.1:8080/w/load.php?debug=false\
public function testMakeResourceLoaderLink( $args, $expectedHtml ) {
$this->setMwGlobals( array(
'wgResourceLoaderDebug' => false,
- 'wgResourceLoaderUseESI' => true,
'wgLoadScript' => 'http://127.0.0.1:8080/w/load.php',
// Affects whether CDATA is inserted
'wgWellFormedXml' => false,
@@ -244,63 +224,141 @@ document.write("\u003Cscript src=\"http://127.0.0.1:8080/w/load.php?debug=false\
'test.foo' => new ResourceLoaderTestModule( array(
'script' => 'mw.test.foo( { a: true } );',
'styles' => '.mw-test-foo { content: "style"; }',
- )),
+ ) ),
'test.bar' => new ResourceLoaderTestModule( array(
'script' => 'mw.test.bar( { a: true } );',
'styles' => '.mw-test-bar { content: "style"; }',
- )),
+ ) ),
'test.baz' => new ResourceLoaderTestModule( array(
'script' => 'mw.test.baz( { a: true } );',
'styles' => '.mw-test-baz { content: "style"; }',
- )),
+ ) ),
'test.quux' => new ResourceLoaderTestModule( array(
'script' => 'mw.test.baz( { token: 123 } );',
'styles' => '/* pref-animate=off */ .mw-icon { transition: none; }',
'group' => 'private',
- )),
+ ) ),
'test.raw' => new ResourceLoaderTestModule( array(
'script' => 'mw.test.baz( { token: 123 } );',
'isRaw' => true,
- )),
+ ) ),
'test.noscript' => new ResourceLoaderTestModule( array(
'styles' => '.mw-test-noscript { content: "style"; }',
'group' => 'noscript',
- )),
+ ) ),
'test.group.bar' => new ResourceLoaderTestModule( array(
'styles' => '.mw-group-bar { content: "style"; }',
'group' => 'bar',
- )),
+ ) ),
'test.group.foo' => new ResourceLoaderTestModule( array(
'styles' => '.mw-group-foo { content: "style"; }',
'group' => 'foo',
- )),
+ ) ),
) );
$links = $method->invokeArgs( $out, $args );
- // Strip comments to avoid variation due to wgDBname in WikiID and cache key
- $actualHtml = preg_replace( '#/\*[^*]+\*/#', '', $links['html'] );
+ $actualHtml = implode( "\n", $links['html'] );
$this->assertEquals( $expectedHtml, $actualHtml );
}
+
+ /**
+ * @dataProvider provideVaryHeaders
+ * @covers OutputPage::addVaryHeader
+ * @covers OutputPage::getVaryHeader
+ * @covers OutputPage::getXVO
+ */
+ public function testVaryHeaders( $calls, $vary, $xvo ) {
+ // get rid of default Vary fields
+ $outputPage = $this->getMockBuilder( 'OutputPage' )
+ ->setConstructorArgs( array( new RequestContext() ) )
+ ->setMethods( array( 'getCacheVaryCookies' ) )
+ ->getMock();
+ $outputPage->expects( $this->any() )
+ ->method( 'getCacheVaryCookies' )
+ ->will( $this->returnValue( array() ) );
+ TestingAccessWrapper::newFromObject( $outputPage )->mVaryHeader = array();
+
+ foreach ( $calls as $call ) {
+ call_user_func_array( array( $outputPage, 'addVaryHeader' ), $call );
+ }
+ $this->assertEquals( $vary, $outputPage->getVaryHeader(), 'Vary:' );
+ $this->assertEquals( $xvo, $outputPage->getXVO(), 'X-Vary-Options:' );
+ }
+
+ public function provideVaryHeaders() {
+ // note: getXVO() automatically adds Vary: Cookie
+ return array(
+ array( // single header
+ array(
+ array( 'Cookie' ),
+ ),
+ 'Vary: Cookie',
+ 'X-Vary-Options: Cookie',
+ ),
+ array( // non-unique headers
+ array(
+ array( 'Cookie' ),
+ array( 'Accept-Language' ),
+ array( 'Cookie' ),
+ ),
+ 'Vary: Cookie, Accept-Language',
+ 'X-Vary-Options: Cookie,Accept-Language',
+ ),
+ array( // two headers with single options
+ array(
+ array( 'Cookie', array( 'string-contains=phpsessid' ) ),
+ array( 'Accept-Language', array( 'string-contains=en' ) ),
+ ),
+ 'Vary: Cookie, Accept-Language',
+ 'X-Vary-Options: Cookie;string-contains=phpsessid,Accept-Language;string-contains=en',
+ ),
+ array( // one header with multiple options
+ array(
+ array( 'Cookie', array( 'string-contains=phpsessid', 'string-contains=userId' ) ),
+ ),
+ 'Vary: Cookie',
+ 'X-Vary-Options: Cookie;string-contains=phpsessid;string-contains=userId',
+ ),
+ array( // Duplicate option
+ array(
+ array( 'Cookie', array( 'string-contains=phpsessid' ) ),
+ array( 'Cookie', array( 'string-contains=phpsessid' ) ),
+ array( 'Accept-Language', array( 'string-contains=en', 'string-contains=en' ) ),
+
+
+ ),
+ 'Vary: Cookie, Accept-Language',
+ 'X-Vary-Options: Cookie;string-contains=phpsessid,Accept-Language;string-contains=en',
+ ),
+ array( // Same header, different options
+ array(
+ array( 'Cookie', array( 'string-contains=phpsessid' ) ),
+ array( 'Cookie', array( 'string-contains=userId' ) ),
+ ),
+ 'Vary: Cookie',
+ 'X-Vary-Options: Cookie;string-contains=phpsessid;string-contains=userId',
+ ),
+ );
+ }
}
/**
* MessageBlobStore that doesn't do anything
*/
class NullMessageBlobStore extends MessageBlobStore {
- public function get ( ResourceLoader $resourceLoader, $modules, $lang ) {
+ public function get( ResourceLoader $resourceLoader, $modules, $lang ) {
return array();
}
- public function insertMessageBlob ( $name, ResourceLoaderModule $module, $lang ) {
+ public function insertMessageBlob( $name, ResourceLoaderModule $module, $lang ) {
return false;
}
- public function updateModule ( $name, ResourceLoaderModule $module, $lang ) {
+ public function updateModule( $name, ResourceLoaderModule $module, $lang ) {
return;
}
- public function updateMessage ( $key ) {
+ public function updateMessage( $key ) {
}
public function clear() {
}
}
-
diff --git a/tests/phpunit/includes/PrefixSearchTest.php b/tests/phpunit/includes/PrefixSearchTest.php
index d63541b7..afd10e9a 100644
--- a/tests/phpunit/includes/PrefixSearchTest.php
+++ b/tests/phpunit/includes/PrefixSearchTest.php
@@ -6,6 +6,11 @@
class PrefixSearchTest extends MediaWikiLangTestCase {
public function addDBData() {
+ if ( !$this->isWikitextNS( NS_MAIN ) ) {
+ // tests are skipped if NS_MAIN is not wikitext
+ return;
+ }
+
$this->insertPage( 'Sandbox' );
$this->insertPage( 'Bar' );
$this->insertPage( 'Example' );
diff --git a/tests/phpunit/includes/SanitizerTest.php b/tests/phpunit/includes/SanitizerTest.php
index c615c460..d3dc512b 100644
--- a/tests/phpunit/includes/SanitizerTest.php
+++ b/tests/phpunit/includes/SanitizerTest.php
@@ -6,6 +6,11 @@
*/
class SanitizerTest extends MediaWikiTestCase {
+ protected function tearDown() {
+ MWTidy::destroySingleton();
+ parent::tearDown();
+ }
+
/**
* @covers Sanitizer::decodeCharReferences
*/
@@ -93,9 +98,7 @@ class SanitizerTest extends MediaWikiTestCase {
* @param bool $escaped Whether sanitizer let the tag in or escape it (ie: '<video>')
*/
public function testRemovehtmltagsOnHtml5Tags( $tag, $escaped ) {
- $this->setMwGlobals( array(
- 'wgUseTidy' => false
- ) );
+ MWTidy::setInstance( false );
if ( $escaped ) {
$this->assertEquals( "<$tag>",
@@ -157,7 +160,7 @@ class SanitizerTest extends MediaWikiTestCase {
* @covers Sanitizer::removeHTMLtags
*/
public function testRemoveHTMLtags( $input, $output, $msg = null ) {
- $GLOBALS['wgUseTidy'] = false;
+ MWTidy::setInstance( false );
$this->assertEquals( $output, Sanitizer::removeHTMLtags( $input ), $msg );
}
@@ -360,5 +363,4 @@ class SanitizerTest extends MediaWikiTestCase {
array( '<script>foo</script>', '' ),
);
}
-
}
diff --git a/tests/phpunit/includes/SanitizerValidateEmailTest.php b/tests/phpunit/includes/SanitizerValidateEmailTest.php
index 14911f04..f47e74e2 100644
--- a/tests/phpunit/includes/SanitizerValidateEmailTest.php
+++ b/tests/phpunit/includes/SanitizerValidateEmailTest.php
@@ -5,7 +5,7 @@
* @todo all test methods in this class should be refactored and...
* use a single test method and a single data provider...
*/
-class SanitizerValidateEmailTest extends MediaWikiTestCase {
+class SanitizerValidateEmailTest extends PHPUnit_Framework_TestCase {
private function checkEmail( $addr, $expected = true, $msg = '' ) {
if ( $msg == '' ) {
diff --git a/tests/phpunit/includes/StatusTest.php b/tests/phpunit/includes/StatusTest.php
index c013f4fc..291ed315 100644
--- a/tests/phpunit/includes/StatusTest.php
+++ b/tests/phpunit/includes/StatusTest.php
@@ -372,7 +372,7 @@ class StatusTest extends MediaWikiLangTestCase {
);
$status = new Status();
- $status->warning( new Message( 'fooBar!', array( 'foo', 'bar' ) ) );
+ $status->warning( new Message( 'fooBar!', array( 'foo', 'bar' ) ) );
$testCases['1MessageWarning'] = array(
$status,
"",
@@ -449,7 +449,7 @@ class StatusTest extends MediaWikiLangTestCase {
// );
$status = new Status();
- $status->warning( new Message( 'fooBar!', array( 'foo', 'bar' ) ) );
+ $status->warning( new Message( 'fooBar!', array( 'foo', 'bar' ) ) );
$testCases['1MessageWarning'] = array(
$status,
array( 'foo', 'bar' ),
diff --git a/tests/phpunit/includes/TemplateParserTest.php b/tests/phpunit/includes/TemplateParserTest.php
index 81854ff3..3b37f4a4 100644
--- a/tests/phpunit/includes/TemplateParserTest.php
+++ b/tests/phpunit/includes/TemplateParserTest.php
@@ -57,7 +57,20 @@ class TemplateParserTest extends MediaWikiTestCase {
array(),
false,
'RuntimeException',
- )
+ ),
+ array(
+ 'has_partial',
+ array(
+ 'planet' => 'world',
+ ),
+ "Partial hello world!\n in here\n",
+ ),
+ array(
+ 'bad_partial',
+ array(),
+ false,
+ 'Exception',
+ ),
);
}
}
diff --git a/tests/phpunit/includes/TestingAccessWrapper.php b/tests/phpunit/includes/TestingAccessWrapper.php
index 84c0f9b5..63d89719 100644
--- a/tests/phpunit/includes/TestingAccessWrapper.php
+++ b/tests/phpunit/includes/TestingAccessWrapper.php
@@ -34,16 +34,42 @@ class TestingAccessWrapper {
return $methodReflection->invokeArgs( $this->object, $args );
}
- public function __set( $name, $value ) {
+ /**
+ * ReflectionClass::getProperty() fails if the private property is defined
+ * in a parent class. This works more like ReflectionClass::getMethod().
+ */
+ private function getProperty( $name ) {
$classReflection = new ReflectionClass( $this->object );
- $propertyReflection = $classReflection->getProperty( $name );
+ try {
+ return $classReflection->getProperty( $name );
+ } catch ( ReflectionException $ex ) {
+ while ( true ) {
+ $classReflection = $classReflection->getParentClass();
+ if ( !$classReflection ) {
+ throw $ex;
+ }
+ try {
+ $propertyReflection = $classReflection->getProperty( $name );
+ } catch ( ReflectionException $ex2 ) {
+ continue;
+ }
+ if ( $propertyReflection->isPrivate() ) {
+ return $propertyReflection;
+ } else {
+ throw $ex;
+ }
+ }
+ }
+ }
+
+ public function __set( $name, $value ) {
+ $propertyReflection = $this->getProperty( $name );
$propertyReflection->setAccessible( true );
$propertyReflection->setValue( $this->object, $value );
}
public function __get( $name ) {
- $classReflection = new ReflectionClass( $this->object );
- $propertyReflection = $classReflection->getProperty( $name );
+ $propertyReflection = $this->getProperty( $name );
$propertyReflection->setAccessible( true );
return $propertyReflection->getValue( $this->object );
}
diff --git a/tests/phpunit/includes/TestingAccessWrapperTest.php b/tests/phpunit/includes/TestingAccessWrapperTest.php
index 7e5b91a1..fc54afae 100644
--- a/tests/phpunit/includes/TestingAccessWrapperTest.php
+++ b/tests/phpunit/includes/TestingAccessWrapperTest.php
@@ -14,18 +14,36 @@ class TestingAccessWrapperTest extends MediaWikiTestCase {
function testGetProperty() {
$this->assertSame( 1, $this->wrapped->property );
+ $this->assertSame( 42, $this->wrapped->privateProperty );
+ $this->assertSame( 9000, $this->wrapped->privateParentProperty );
}
function testSetProperty() {
$this->wrapped->property = 10;
$this->assertSame( 10, $this->wrapped->property );
$this->assertSame( 10, $this->raw->getProperty() );
+
+ $this->wrapped->privateProperty = 11;
+ $this->assertSame( 11, $this->wrapped->privateProperty );
+ $this->assertSame( 11, $this->raw->getPrivateProperty() );
+
+ $this->wrapped->privateParentProperty = 12;
+ $this->assertSame( 12, $this->wrapped->privateParentProperty );
+ $this->assertSame( 12, $this->raw->getPrivateParentProperty() );
}
function testCallMethod() {
$this->wrapped->incrementPropertyValue();
$this->assertSame( 2, $this->wrapped->property );
$this->assertSame( 2, $this->raw->getProperty() );
+
+ $this->wrapped->incrementPrivatePropertyValue();
+ $this->assertSame( 43, $this->wrapped->privateProperty );
+ $this->assertSame( 43, $this->raw->getPrivateProperty() );
+
+ $this->wrapped->incrementPrivateParentPropertyValue();
+ $this->assertSame( 9001, $this->wrapped->privateParentProperty );
+ $this->assertSame( 9001, $this->raw->getPrivateParentProperty() );
}
function testCallMethodTwoArgs() {
diff --git a/tests/phpunit/includes/TitleArrayFromResultTest.php b/tests/phpunit/includes/TitleArrayFromResultTest.php
index 0f7069ae..6654a5b6 100644
--- a/tests/phpunit/includes/TitleArrayFromResultTest.php
+++ b/tests/phpunit/includes/TitleArrayFromResultTest.php
@@ -4,7 +4,7 @@
* @author Adam Shorland
* @covers TitleArrayFromResult
*/
-class TitleArrayFromResultTest extends MediaWikiTestCase {
+class TitleArrayFromResultTest extends PHPUnit_Framework_TestCase {
private function getMockResultWrapper( $row = null, $numRows = 1 ) {
$resultWrapper = $this->getMockBuilder( 'ResultWrapper' )
diff --git a/tests/phpunit/includes/TitlePermissionTest.php b/tests/phpunit/includes/TitlePermissionTest.php
index 022c7d53..f588ed63 100644
--- a/tests/phpunit/includes/TitlePermissionTest.php
+++ b/tests/phpunit/includes/TitlePermissionTest.php
@@ -664,7 +664,7 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
$this->setTitle( NS_MAIN, "test page" );
$this->title->mTitleProtection['permission'] = '';
$this->title->mTitleProtection['user'] = $this->user->getID();
- $this->title->mTitleProtection['expiry'] = wfGetDB( DB_SLAVE )->getInfinity();
+ $this->title->mTitleProtection['expiry'] = 'infinity';
$this->title->mTitleProtection['reason'] = 'test';
$this->title->mCascadeRestriction = false;
@@ -753,8 +753,14 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
$prev = time();
$now = time() + 120;
$this->user->mBlockedby = $this->user->getId();
- $this->user->mBlock = new Block( '127.0.8.1', 0, $this->user->getId(),
- 'no reason given', $prev + 3600, 1, 0 );
+ $this->user->mBlock = new Block( array(
+ 'address' => '127.0.8.1',
+ 'by' => $this->user->getId(),
+ 'reason' => 'no reason given',
+ 'timestamp' => $prev + 3600,
+ 'auto' => true,
+ 'expiry' => 0
+ ) );
$this->user->mBlock->mTimestamp = 0;
$this->assertEquals( array( array( 'autoblockedtext',
'[[User:Useruser|Useruser]]', 'no reason given', '127.0.0.1',
@@ -770,8 +776,14 @@ class TitlePermissionTest extends MediaWikiLangTestCase {
global $wgLocalTZoffset;
$wgLocalTZoffset = -60;
$this->user->mBlockedby = $this->user->getName();
- $this->user->mBlock = new Block( '127.0.8.1', 0, $this->user->getId(),
- 'no reason given', $now, 0, 10 );
+ $this->user->mBlock = new Block( array(
+ 'address' => '127.0.8.1',
+ 'by' => $this->user->getId(),
+ 'reason' => 'no reason given',
+ 'timestamp' => $now,
+ 'auto' => false,
+ 'expiry' => 10,
+ ) );
$this->assertEquals( array( array( 'blockedtext',
'[[User:Useruser|Useruser]]', 'no reason given', '127.0.0.1',
'Useruser', null, '23:00, 31 December 1969', '127.0.8.1',
diff --git a/tests/phpunit/includes/TitleTest.php b/tests/phpunit/includes/TitleTest.php
index d55f958b..a2c6f23d 100644
--- a/tests/phpunit/includes/TitleTest.php
+++ b/tests/phpunit/includes/TitleTest.php
@@ -1,6 +1,7 @@
B' ),
- array( 'A | B' ),
+ array( 'A [ B', 'title-invalid-characters' ),
+ array( 'A ] B', 'title-invalid-characters' ),
+ array( 'A { B', 'title-invalid-characters' ),
+ array( 'A } B', 'title-invalid-characters' ),
+ array( 'A < B', 'title-invalid-characters' ),
+ array( 'A > B', 'title-invalid-characters' ),
+ array( 'A | B', 'title-invalid-characters' ),
// URL encoding
- array( 'A%20B' ),
- array( 'A%23B' ),
- array( 'A%2523B' ),
+ array( 'A%20B', 'title-invalid-characters' ),
+ array( 'A%23B', 'title-invalid-characters' ),
+ array( 'A%2523B', 'title-invalid-characters' ),
// XML/HTML character entity references
// Note: Commented out because they are not marked invalid by the PHP test as
// Title::newFromText runs Sanitizer::decodeCharReferencesAndNormalize first.
@@ -102,29 +103,30 @@ class TitleTest extends MediaWikiTestCase {
//'A é B',
//'A é B',
// Subject of NS_TALK does not roundtrip to NS_MAIN
- array( 'Talk:File:Example.svg' ),
+ array( 'Talk:File:Example.svg', 'title-invalid-talk-namespace' ),
// Directory navigation
- array( '.' ),
- array( '..' ),
- array( './Sandbox' ),
- array( '../Sandbox' ),
- array( 'Foo/./Sandbox' ),
- array( 'Foo/../Sandbox' ),
- array( 'Sandbox/.' ),
- array( 'Sandbox/..' ),
+ array( '.', 'title-invalid-relative' ),
+ array( '..', 'title-invalid-relative' ),
+ array( './Sandbox', 'title-invalid-relative' ),
+ array( '../Sandbox', 'title-invalid-relative' ),
+ array( 'Foo/./Sandbox', 'title-invalid-relative' ),
+ array( 'Foo/../Sandbox', 'title-invalid-relative' ),
+ array( 'Sandbox/.', 'title-invalid-relative' ),
+ array( 'Sandbox/..', 'title-invalid-relative' ),
// Tilde
- array( 'A ~~~ Name' ),
- array( 'A ~~~~ Signature' ),
- array( 'A ~~~~~ Timestamp' ),
- array( str_repeat( 'x', 256 ) ),
+ array( 'A ~~~ Name', 'title-invalid-magic-tilde' ),
+ array( 'A ~~~~ Signature', 'title-invalid-magic-tilde' ),
+ array( 'A ~~~~~ Timestamp', 'title-invalid-magic-tilde' ),
+ // Length
+ array( str_repeat( 'x', 256 ), 'title-invalid-too-long' ),
// Namespace prefix without actual title
- array( 'Talk:' ),
- array( 'Talk:#' ),
- array( 'Category: ' ),
- array( 'Category: #bar' ),
+ array( 'Talk:', 'title-invalid-empty' ),
+ array( 'Talk:#', 'title-invalid-empty' ),
+ array( 'Category: ', 'title-invalid-empty' ),
+ array( 'Category: #bar', 'title-invalid-empty' ),
// interwiki prefix
- array( 'localtestiw: Talk: # anchor' ),
- array( 'localtestiw: Talk:' )
+ array( 'localtestiw: Talk: # anchor', 'title-invalid-empty' ),
+ array( 'localtestiw: Talk:', 'title-invalid-empty' )
);
}
@@ -143,7 +145,7 @@ class TitleTest extends MediaWikiTestCase {
}
)
)
- ));
+ ) );
}
/**
@@ -163,9 +165,14 @@ class TitleTest extends MediaWikiTestCase {
* @dataProvider provideInvalidSecureAndSplit
* @note This mainly tests MediaWikiTitleCodec::parseTitle().
*/
- public function testSecureAndSplitInvalid( $text ) {
+ public function testSecureAndSplitInvalid( $text, $expectedErrorMessage ) {
$this->secureAndSplitGlobals();
- $this->assertNull( Title::newFromText( $text ), "Invalid: $text" );
+ try {
+ Title::newFromTextThrow( $text ); // should throw
+ $this->assertTrue( false, "Invalid: $text" );
+ } catch ( MalformedTitleException $ex ) {
+ $this->assertEquals( $expectedErrorMessage, $ex->getErrorMessage(), "Invalid: $text" );
+ }
}
public static function provideConvertByteClassToUnicodeClass() {
@@ -631,4 +638,26 @@ class TitleTest extends MediaWikiTestCase {
$title = Title::makeTitle( NS_MAIN, 'Interwiki link', '', 'externalwiki' );
$this->assertTrue( $title->isAlwaysKnown() );
}
+
+ /**
+ * @covers Title::exists
+ */
+ public function testExists() {
+ $title = Title::makeTitle( NS_PROJECT, 'New page' );
+ $linkCache = LinkCache::singleton();
+
+ $article = new Article( $title );
+ $page = $article->getPage();
+ $page->doEditContent( new WikitextContent( 'Some [[link]]' ), 'summary' );
+
+ // Tell Title it doesn't know whether it exists
+ $title->mArticleID = -1;
+
+ // Tell the link cache it doesn't exists when it really does
+ $linkCache->clearLink( $title );
+ $linkCache->addBadLinkObj( $title );
+
+ $this->assertEquals( false, $title->exists(), 'exists() should rely on link cache unless GAID_FOR_UPDATE is used' );
+ $this->assertEquals( true, $title->exists( Title::GAID_FOR_UPDATE ), 'exists() should re-query database when GAID_FOR_UPDATE is used' );
+ }
}
diff --git a/tests/phpunit/includes/UserTest.php b/tests/phpunit/includes/UserTest.php
index b74a7ead..77132bbb 100644
--- a/tests/phpunit/includes/UserTest.php
+++ b/tests/phpunit/includes/UserTest.php
@@ -307,9 +307,30 @@ class UserTest extends MediaWikiTestCase {
*/
public function testCheckPasswordValidity() {
$this->setMwGlobals( array(
- 'wgMinimalPasswordLength' => 6,
- 'wgMaximalPasswordLength' => 30,
+ 'wgPasswordPolicy' => array(
+ 'policies' => array(
+ 'sysop' => array(
+ 'MinimalPasswordLength' => 8,
+ 'MinimumPasswordLengthToLogin' => 1,
+ 'PasswordCannotMatchUsername' => 1,
+ ),
+ 'default' => array(
+ 'MinimalPasswordLength' => 6,
+ 'PasswordCannotMatchUsername' => true,
+ 'PasswordCannotMatchBlacklist' => true,
+ 'MaximalPasswordLength' => 30,
+ ),
+ ),
+ 'checks' => array(
+ 'MinimalPasswordLength' => 'PasswordPolicyChecks::checkMinimalPasswordLength',
+ 'MinimumPasswordLengthToLogin' => 'PasswordPolicyChecks::checkMinimumPasswordLengthToLogin',
+ 'PasswordCannotMatchUsername' => 'PasswordPolicyChecks::checkPasswordCannotMatchUsername',
+ 'PasswordCannotMatchBlacklist' => 'PasswordPolicyChecks::checkPasswordCannotMatchBlacklist',
+ 'MaximalPasswordLength' => 'PasswordPolicyChecks::checkMaximalPasswordLength',
+ ),
+ ),
) );
+
$user = User::newFromName( 'Useruser' );
// Sanity
$this->assertTrue( $user->isValidPassword( 'Password1234' ) );
@@ -425,4 +446,109 @@ class UserTest extends MediaWikiTestCase {
$this->assertFalse( $user->isLoggedIn() );
$this->assertTrue( $user->isAnon() );
}
+
+ /**
+ * @covers User::checkAndSetTouched
+ */
+ public function testCheckAndSetTouched() {
+ $user = TestingAccessWrapper::newFromObject( User::newFromName( 'UTSysop' ) );
+ $this->assertTrue( $user->isLoggedIn() );
+
+ $touched = $user->getDBTouched();
+ $this->assertTrue(
+ $user->checkAndSetTouched(), "checkAndSetTouched() succeded" );
+ $this->assertGreaterThan(
+ $touched, $user->getDBTouched(), "user_touched increased with casOnTouched()" );
+
+ $touched = $user->getDBTouched();
+ $this->assertTrue(
+ $user->checkAndSetTouched(), "checkAndSetTouched() succeded #2" );
+ $this->assertGreaterThan(
+ $touched, $user->getDBTouched(), "user_touched increased with casOnTouched() #2" );
+ }
+
+ public static function setExtendedLoginCookieDataProvider() {
+ $data = array();
+ $now = time();
+
+ $secondsInDay = 86400;
+
+ // Arbitrary durations, in units of days, to ensure it chooses the
+ // right one. There is a 5-minute grace period (see testSetExtendedLoginCookie)
+ // to work around slow tests, since we're not currently mocking time() for PHP.
+
+ $durationOne = $secondsInDay * 5;
+ $durationTwo = $secondsInDay * 29;
+ $durationThree = $secondsInDay * 17;
+
+ // If $wgExtendedLoginCookieExpiration is null, then the expiry passed to
+ // set cookie is time() + $wgCookieExpiration
+ $data[] = array(
+ null,
+ $durationOne,
+ $now + $durationOne,
+ );
+
+ // If $wgExtendedLoginCookieExpiration isn't null, then the expiry passed to
+ // set cookie is $now + $wgExtendedLoginCookieExpiration
+ $data[] = array(
+ $durationTwo,
+ $durationThree,
+ $now + $durationTwo,
+ );
+
+ return $data;
+ }
+
+ /**
+ * @dataProvider setExtendedLoginCookieDataProvider
+ * @covers User::getRequest
+ * @covers User::setCookie
+ * @backupGlobals enabled
+ */
+ public function testSetExtendedLoginCookie(
+ $extendedLoginCookieExpiration,
+ $cookieExpiration,
+ $expectedExpiry
+ ) {
+ $this->setMwGlobals( array(
+ 'wgExtendedLoginCookieExpiration' => $extendedLoginCookieExpiration,
+ 'wgCookieExpiration' => $cookieExpiration,
+ ) );
+
+ $response = $this->getMock( 'WebResponse' );
+ $setcookieSpy = $this->any();
+ $response->expects( $setcookieSpy )
+ ->method( 'setcookie' );
+
+ $request = new MockWebRequest( $response );
+ $user = new UserProxy( User::newFromSession( $request ) );
+ $user->setExtendedLoginCookie( 'name', 'value', true );
+
+ $setcookieInvocations = $setcookieSpy->getInvocations();
+ $setcookieInvocation = end( $setcookieInvocations );
+ $actualExpiry = $setcookieInvocation->parameters[ 2 ];
+
+ // TODO: ± 300 seconds compensates for
+ // slow-running tests. However, the dependency on the time
+ // function should be removed. This requires some way
+ // to mock/isolate User->setExtendedLoginCookie's call to time()
+ $this->assertEquals( $expectedExpiry, $actualExpiry, '', 300 );
+ }
+}
+
+class UserProxy extends User {
+
+ /**
+ * @var User
+ */
+ protected $user;
+
+ public function __construct( User $user ) {
+ $this->user = $user;
+ }
+
+ public function setExtendedLoginCookie( $name, $value, $secure ) {
+ $this->user->setExtendedLoginCookie( $name, $value, $secure );
+ }
}
diff --git a/tests/phpunit/includes/WikiMapTest.php b/tests/phpunit/includes/WikiMapTest.php
new file mode 100644
index 00000000..9233416c
--- /dev/null
+++ b/tests/phpunit/includes/WikiMapTest.php
@@ -0,0 +1,108 @@
+settings = array(
+ 'wgServer' => array(
+ 'enwiki' => 'http://en.example.org',
+ 'ruwiki' => '//ru.example.org',
+ ),
+ 'wgArticlePath' => array(
+ 'enwiki' => '/w/$1',
+ 'ruwiki' => '/wiki/$1',
+ ),
+ );
+ $conf->suffixes = array( 'wiki' );
+ $this->setMwGlobals( array(
+ 'wgConf' => $conf,
+ ) );
+ }
+
+ public function provideGetWiki() {
+ $enwiki = new WikiReference( 'wiki', 'en', 'http://en.example.org', '/w/$1' );
+ $ruwiki = new WikiReference( 'wiki', 'ru', '//ru.example.org', '/wiki/$1' );
+
+ return array(
+ 'unknown' => array( false, 'xyzzy' ),
+ 'enwiki' => array( $enwiki, 'enwiki' ),
+ 'ruwiki' => array( $ruwiki, 'ruwiki' ),
+ );
+ }
+
+ /**
+ * @dataProvider provideGetWiki
+ */
+ public function testGetWiki( $expected, $wikiId ) {
+ $this->assertEquals( $expected, WikiMap::getWiki( $wikiId ) );
+ }
+
+ public function provideGetWikiName() {
+ return array(
+ 'unknown' => array( 'xyzzy', 'xyzzy' ),
+ 'enwiki' => array( 'en.example.org', 'enwiki' ),
+ 'ruwiki' => array( 'ru.example.org', 'ruwiki' ),
+ );
+ }
+
+ /**
+ * @dataProvider provideGetWikiName
+ */
+ public function testGetWikiName( $expected, $wikiId ) {
+ $this->assertEquals( $expected, WikiMap::getWikiName( $wikiId ) );
+ }
+
+ public function provideMakeForeignLink() {
+ return array(
+ 'unknown' => array( false, 'xyzzy', 'Foo' ),
+ 'enwiki' => array( 'Foo ', 'enwiki', 'Foo', ),
+ 'ruwiki' => array( 'вар ', 'ruwiki', 'Фу', 'вар' ),
+ );
+ }
+
+ /**
+ * @dataProvider provideMakeForeignLink
+ */
+ public function testMakeForeignLink( $expected, $wikiId, $page, $text = null ) {
+ $this->assertEquals( $expected, WikiMap::makeForeignLink( $wikiId, $page, $text ) );
+ }
+
+ public function provideForeignUserLink() {
+ return array(
+ 'unknown' => array( false, 'xyzzy', 'Foo' ),
+ 'enwiki' => array( 'User:Foo ', 'enwiki', 'Foo', ),
+ 'ruwiki' => array( 'вар ', 'ruwiki', 'Фу', 'вар' ),
+ );
+ }
+
+ /**
+ * @dataProvider provideForeignUserLink
+ */
+ public function testForeignUserLink( $expected, $wikiId, $user, $text = null ) {
+ $this->assertEquals( $expected, WikiMap::foreignUserLink( $wikiId, $user, $text ) );
+ }
+
+ public function provideGetForeignURL() {
+ return array(
+ 'unknown' => array( false, 'xyzzy', 'Foo' ),
+ 'enwiki' => array( 'http://en.example.org/w/Foo', 'enwiki', 'Foo', ),
+ 'ruwiki with fragement' => array( '//ru.example.org/wiki/%D0%A4%D1%83#%D0%B2%D0%B0%D1%80', 'ruwiki', 'Фу', 'вар' ),
+ );
+ }
+
+ /**
+ * @dataProvider provideGetForeignURL
+ */
+ public function testGetForeignURL( $expected, $wikiId, $page, $fragment = null ) {
+ $this->assertEquals( $expected, WikiMap::getForeignURL( $wikiId, $page, $fragment ) );
+ }
+
+}
+
diff --git a/tests/phpunit/includes/WikiReferenceTest.php b/tests/phpunit/includes/WikiReferenceTest.php
new file mode 100644
index 00000000..4fe2e855
--- /dev/null
+++ b/tests/phpunit/includes/WikiReferenceTest.php
@@ -0,0 +1,80 @@
+ array( 'foo.bar', 'http://foo.bar' ),
+ 'https' => array( 'foo.bar', 'http://foo.bar' ),
+
+ // apparently, this is the expected behavior
+ 'invalid' => array( 'purple kittens', 'purple kittens' ),
+ );
+ }
+
+ /**
+ * @dataProvider provideGetDisplayName
+ */
+ public function testGetDisplayName( $expected, $canonicalServer ) {
+ $reference = new WikiReference( 'wiki', 'xx', $canonicalServer, '/wiki/$1' );
+ $this->assertEquals( $expected, $reference->getDisplayName() );
+ }
+
+ public function testGetCanonicalServer() {
+ $reference = new WikiReference( 'wiki', 'xx', 'https://acme.com', '/wiki/$1', '//acme.com' );
+ $this->assertEquals( 'https://acme.com', $reference->getCanonicalServer() );
+ }
+
+ public function provideGetCanonicalUrl() {
+ return array(
+ 'no fragement' => array( 'https://acme.com/wiki/Foo', 'https://acme.com', '//acme.com', '/wiki/$1', 'Foo', null ),
+ 'empty fragement' => array( 'https://acme.com/wiki/Foo', 'https://acme.com', '//acme.com', '/wiki/$1', 'Foo', '' ),
+ 'fragment' => array( 'https://acme.com/wiki/Foo#Bar', 'https://acme.com', '//acme.com', '/wiki/$1', 'Foo', 'Bar' ),
+ 'double fragment' => array( 'https://acme.com/wiki/Foo#Bar%23Xus', 'https://acme.com', '//acme.com', '/wiki/$1', 'Foo', 'Bar#Xus' ),
+ 'escaped fragement' => array( 'https://acme.com/wiki/Foo%23Bar', 'https://acme.com', '//acme.com', '/wiki/$1', 'Foo#Bar', null ),
+ 'empty path' => array( 'https://acme.com/Foo', 'https://acme.com', '//acme.com', '/$1', 'Foo', null ),
+ );
+ }
+
+ /**
+ * @dataProvider provideGetCanonicalUrl
+ */
+ public function testGetCanonicalUrl( $expected, $canonicalServer, $server, $path, $page, $fragmentId ) {
+ $reference = new WikiReference( 'wiki', 'xx', $canonicalServer, $path, $server );
+ $this->assertEquals( $expected, $reference->getCanonicalUrl( $page, $fragmentId ) );
+ }
+
+ /**
+ * @dataProvider provideGetCanonicalUrl
+ * @note getUrl is an alias for getCanonicalUrl
+ */
+ public function testGetUrl( $expected, $canonicalServer, $server, $path, $page, $fragmentId ) {
+ $reference = new WikiReference( 'wiki', 'xx', $canonicalServer, $path, $server );
+ $this->assertEquals( $expected, $reference->getUrl( $page, $fragmentId ) );
+ }
+
+ public function provideGetFullUrl() {
+ return array(
+ 'no fragement' => array( '//acme.com/wiki/Foo', 'https://acme.com', '//acme.com', '/wiki/$1', 'Foo', null ),
+ 'empty fragement' => array( '//acme.com/wiki/Foo', 'https://acme.com', '//acme.com', '/wiki/$1', 'Foo', '' ),
+ 'fragment' => array( '//acme.com/wiki/Foo#Bar', 'https://acme.com', '//acme.com', '/wiki/$1', 'Foo', 'Bar' ),
+ 'double fragment' => array( '//acme.com/wiki/Foo#Bar%23Xus', 'https://acme.com', '//acme.com', '/wiki/$1', 'Foo', 'Bar#Xus' ),
+ 'escaped fragement' => array( '//acme.com/wiki/Foo%23Bar', 'https://acme.com', '//acme.com', '/wiki/$1', 'Foo#Bar', null ),
+ 'empty path' => array( '//acme.com/Foo', 'https://acme.com', '//acme.com', '/$1', 'Foo', null ),
+ );
+ }
+
+ /**
+ * @dataProvider provideGetFullUrl
+ */
+ public function testGetFullUrl( $expected, $canonicalServer, $server, $path, $page, $fragmentId ) {
+ $reference = new WikiReference( 'wiki', 'xx', $canonicalServer, $path, $server );
+ $this->assertEquals( $expected, $reference->getFullUrl( $page, $fragmentId ) );
+ }
+
+}
+
diff --git a/tests/phpunit/includes/XmlJsTest.php b/tests/phpunit/includes/XmlJsTest.php
index 0dbb0109..21819b7e 100644
--- a/tests/phpunit/includes/XmlJsTest.php
+++ b/tests/phpunit/includes/XmlJsTest.php
@@ -3,7 +3,7 @@
/**
* @group Xml
*/
-class XmlJs extends MediaWikiTestCase {
+class XmlJs extends PHPUnit_Framework_TestCase {
/**
* @covers XmlJsCode::__construct
diff --git a/tests/phpunit/includes/XmlTest.php b/tests/phpunit/includes/XmlTest.php
index 382e3d89..bea338de 100644
--- a/tests/phpunit/includes/XmlTest.php
+++ b/tests/phpunit/includes/XmlTest.php
@@ -154,7 +154,7 @@ class XmlTest extends MediaWikiTestCase {
'From year (and earlier): ' .
' ' .
'From month (and earlier): ' .
- '' .
+ '' .
'all ' . "\n" .
'January ' . "\n" .
'February ' . "\n" .
@@ -175,7 +175,7 @@ class XmlTest extends MediaWikiTestCase {
'From year (and earlier): ' .
' ' .
'From month (and earlier): ' .
- '' .
+ '' .
'all ' . "\n" .
'January ' . "\n" .
'February ' . "\n" .
@@ -209,7 +209,7 @@ class XmlTest extends MediaWikiTestCase {
'From year (and earlier): ' .
' ' .
'From month (and earlier): ' .
- '' .
+ '' .
'all ' . "\n" .
'January ' . "\n" .
'February ' . "\n" .
diff --git a/tests/phpunit/includes/api/ApiBlockTest.php b/tests/phpunit/includes/api/ApiBlockTest.php
index d98eec6a..575efd6d 100644
--- a/tests/phpunit/includes/api/ApiBlockTest.php
+++ b/tests/phpunit/includes/api/ApiBlockTest.php
@@ -53,7 +53,7 @@ class ApiBlockTest extends ApiTestCase {
'action' => 'block',
'user' => 'UTApiBlockee',
'reason' => 'Some reason',
- 'token' => $tokens['blocktoken'] ), null, false, self::$users['sysop']->user );
+ 'token' => $tokens['blocktoken'] ), null, false, self::$users['sysop']->getUser() );
$block = Block::newFromTarget( 'UTApiBlockee' );
@@ -68,7 +68,7 @@ class ApiBlockTest extends ApiTestCase {
* @expectedException UsageException
* @expectedExceptionMessage The token parameter must be set
*/
- public function testBlockingActionWithNoToken( ) {
+ public function testBlockingActionWithNoToken() {
$this->doApiRequest(
array(
'action' => 'block',
@@ -77,7 +77,7 @@ class ApiBlockTest extends ApiTestCase {
),
null,
false,
- self::$users['sysop']->user
+ self::$users['sysop']->getUser()
);
}
}
diff --git a/tests/phpunit/includes/api/ApiEditPageTest.php b/tests/phpunit/includes/api/ApiEditPageTest.php
index 3179a452..61a8ad11 100644
--- a/tests/phpunit/includes/api/ApiEditPageTest.php
+++ b/tests/phpunit/includes/api/ApiEditPageTest.php
@@ -27,9 +27,14 @@ class ApiEditPageTest extends ApiTestCase {
$wgExtraNamespaces[12312] = 'Dummy';
$wgExtraNamespaces[12313] = 'Dummy_talk';
+ $wgExtraNamespaces[12314] = 'DummyNonText';
+ $wgExtraNamespaces[12315] = 'DummyNonText_talk';
$wgNamespaceContentModels[12312] = "testing";
+ $wgNamespaceContentModels[12314] = "testing-nontext";
+
$wgContentHandlers["testing"] = 'DummyContentHandlerForTesting';
+ $wgContentHandlers["testing-nontext"] = 'DummyNonTextContentHandler';
MWNamespace::getCanonicalNamespaces( true ); # reset namespace cache
$wgContLang->resetNamespaces(); # reset namespace cache
@@ -96,33 +101,6 @@ class ApiEditPageTest extends ApiTestCase {
);
}
- public function testNonTextEdit() {
- $name = 'Dummy:ApiEditPageTest_testNonTextEdit';
- $data = serialize( 'some bla bla text' );
-
- // -- test new page --------------------------------------------
- $apiResult = $this->doApiRequestWithToken( array(
- 'action' => 'edit',
- 'title' => $name,
- 'text' => $data, ) );
- $apiResult = $apiResult[0];
-
- // Validate API result data
- $this->assertArrayHasKey( 'edit', $apiResult );
- $this->assertArrayHasKey( 'result', $apiResult['edit'] );
- $this->assertEquals( 'Success', $apiResult['edit']['result'] );
-
- $this->assertArrayHasKey( 'new', $apiResult['edit'] );
- $this->assertArrayNotHasKey( 'nochange', $apiResult['edit'] );
-
- $this->assertArrayHasKey( 'pageid', $apiResult['edit'] );
-
- // validate resulting revision
- $page = WikiPage::factory( Title::newFromText( $name ) );
- $this->assertEquals( "testing", $page->getContentModel() );
- $this->assertEquals( $data, $page->getContent()->serialize() );
- }
-
/**
* @return array
*/
@@ -240,7 +218,7 @@ class ApiEditPageTest extends ApiTestCase {
'section' => 'new',
'text' => 'test',
'summary' => 'header',
- ));
+ ) );
$this->assertEquals( 'Success', $re['edit']['result'] );
// Check the page text is correct
@@ -257,7 +235,7 @@ class ApiEditPageTest extends ApiTestCase {
'section' => 'new',
'text' => 'test',
'summary' => 'header',
- ));
+ ) );
$this->assertEquals( 'Success', $re2['edit']['result'] );
$text = WikiPage::factory( Title::newFromText( $name ) )
@@ -284,18 +262,18 @@ class ApiEditPageTest extends ApiTestCase {
// base edit for content
$page->doEditContent( new WikitextContent( "Foo" ),
- "testing 1", EDIT_NEW, false, self::$users['sysop']->user );
+ "testing 1", EDIT_NEW, false, self::$users['sysop']->getUser() );
$this->forceRevisionDate( $page, '20120101000000' );
$baseTime = $page->getRevision()->getTimestamp();
// base edit for redirect
$rpage->doEditContent( new WikitextContent( "#REDIRECT [[$name]]" ),
- "testing 1", EDIT_NEW, false, self::$users['sysop']->user );
+ "testing 1", EDIT_NEW, false, self::$users['sysop']->getUser() );
$this->forceRevisionDate( $rpage, '20120101000000' );
// conflicting edit to redirect
$rpage->doEditContent( new WikitextContent( "#REDIRECT [[$name]]\n\n[[Category:Test]]" ),
- "testing 2", EDIT_UPDATE, $page->getLatest(), self::$users['uploader']->user );
+ "testing 2", EDIT_UPDATE, $page->getLatest(), self::$users['uploader']->getUser() );
$this->forceRevisionDate( $rpage, '20120101020202' );
// try to save edit, following the redirect
@@ -306,7 +284,7 @@ class ApiEditPageTest extends ApiTestCase {
'basetimestamp' => $baseTime,
'section' => 'new',
'redirect' => true,
- ), null, self::$users['sysop']->user );
+ ), null, self::$users['sysop']->getUser() );
$this->assertEquals( 'Success', $re['edit']['result'],
"no problems expected when following redirect" );
@@ -330,18 +308,18 @@ class ApiEditPageTest extends ApiTestCase {
// base edit for content
$page->doEditContent( new WikitextContent( "Foo" ),
- "testing 1", EDIT_NEW, false, self::$users['sysop']->user );
+ "testing 1", EDIT_NEW, false, self::$users['sysop']->getUser() );
$this->forceRevisionDate( $page, '20120101000000' );
$baseTime = $page->getRevision()->getTimestamp();
// base edit for redirect
$rpage->doEditContent( new WikitextContent( "#REDIRECT [[$name]]" ),
- "testing 1", EDIT_NEW, false, self::$users['sysop']->user );
+ "testing 1", EDIT_NEW, false, self::$users['sysop']->getUser() );
$this->forceRevisionDate( $rpage, '20120101000000' );
// conflicting edit to redirect
$rpage->doEditContent( new WikitextContent( "#REDIRECT [[$name]]\n\n[[Category:Test]]" ),
- "testing 2", EDIT_UPDATE, $page->getLatest(), self::$users['uploader']->user );
+ "testing 2", EDIT_UPDATE, $page->getLatest(), self::$users['uploader']->getUser() );
$this->forceRevisionDate( $rpage, '20120101020202' );
// try to save edit, following the redirect but without creating a section
@@ -352,7 +330,7 @@ class ApiEditPageTest extends ApiTestCase {
'text' => 'nix bar!',
'basetimestamp' => $baseTime,
'redirect' => true,
- ), null, self::$users['sysop']->user );
+ ), null, self::$users['sysop']->getUser() );
$this->fail( 'redirect-appendonly error expected' );
} catch ( UsageException $ex ) {
@@ -372,13 +350,13 @@ class ApiEditPageTest extends ApiTestCase {
// base edit
$page->doEditContent( new WikitextContent( "Foo" ),
- "testing 1", EDIT_NEW, false, self::$users['sysop']->user );
+ "testing 1", EDIT_NEW, false, self::$users['sysop']->getUser() );
$this->forceRevisionDate( $page, '20120101000000' );
$baseTime = $page->getRevision()->getTimestamp();
// conflicting edit
$page->doEditContent( new WikitextContent( "Foo bar" ),
- "testing 2", EDIT_UPDATE, $page->getLatest(), self::$users['uploader']->user );
+ "testing 2", EDIT_UPDATE, $page->getLatest(), self::$users['uploader']->getUser() );
$this->forceRevisionDate( $page, '20120101020202' );
// try to save edit, expect conflict
@@ -388,7 +366,7 @@ class ApiEditPageTest extends ApiTestCase {
'title' => $name,
'text' => 'nix bar!',
'basetimestamp' => $baseTime,
- ), null, self::$users['sysop']->user );
+ ), null, self::$users['sysop']->getUser() );
$this->fail( 'edit conflict expected' );
} catch ( UsageException $ex ) {
@@ -411,13 +389,13 @@ class ApiEditPageTest extends ApiTestCase {
// base edit
$page->doEditContent( new WikitextContent( "Foo" ),
- "testing 1", EDIT_NEW, false, self::$users['sysop']->user );
+ "testing 1", EDIT_NEW, false, self::$users['sysop']->getUser() );
$this->forceRevisionDate( $page, '20120101000000' );
$baseTime = $page->getRevision()->getTimestamp();
// conflicting edit
$page->doEditContent( new WikitextContent( "Foo bar" ),
- "testing 2", EDIT_UPDATE, $page->getLatest(), self::$users['uploader']->user );
+ "testing 2", EDIT_UPDATE, $page->getLatest(), self::$users['uploader']->getUser() );
$this->forceRevisionDate( $page, '20120101020202' );
// try to save edit, expect no conflict
@@ -427,7 +405,7 @@ class ApiEditPageTest extends ApiTestCase {
'text' => 'nix bar!',
'basetimestamp' => $baseTime,
'section' => 'new',
- ), null, self::$users['sysop']->user );
+ ), null, self::$users['sysop']->getUser() );
$this->assertEquals( 'Success', $re['edit']['result'],
"no edit conflict expected here" );
@@ -454,17 +432,17 @@ class ApiEditPageTest extends ApiTestCase {
// base edit for content
$page->doEditContent( new WikitextContent( "Foo" ),
- "testing 1", EDIT_NEW, false, self::$users['sysop']->user );
+ "testing 1", EDIT_NEW, false, self::$users['sysop']->getUser() );
$this->forceRevisionDate( $page, '20120101000000' );
// base edit for redirect
$rpage->doEditContent( new WikitextContent( "#REDIRECT [[$name]]" ),
- "testing 1", EDIT_NEW, false, self::$users['sysop']->user );
+ "testing 1", EDIT_NEW, false, self::$users['sysop']->getUser() );
$this->forceRevisionDate( $rpage, '20120101000000' );
// new edit to content
$page->doEditContent( new WikitextContent( "Foo bar" ),
- "testing 2", EDIT_UPDATE, $page->getLatest(), self::$users['uploader']->user );
+ "testing 2", EDIT_UPDATE, $page->getLatest(), self::$users['uploader']->getUser() );
$this->forceRevisionDate( $rpage, '20120101020202' );
// try to save edit; should work, following the redirect.
@@ -474,7 +452,7 @@ class ApiEditPageTest extends ApiTestCase {
'text' => 'nix bar!',
'section' => 'new',
'redirect' => true,
- ), null, self::$users['sysop']->user );
+ ), null, self::$users['sysop']->getUser() );
$this->assertEquals( 'Success', $re['edit']['result'],
"no edit conflict expected here" );
@@ -493,4 +471,45 @@ class ApiEditPageTest extends ApiTestCase {
$page->clear();
}
+
+ public function testCheckDirectApiEditingDisallowed_forNonTextContent() {
+ $this->setExpectedException(
+ 'UsageException',
+ 'Direct editing via API is not supported for content model testing used by Dummy:ApiEditPageTest_nonTextPageEdit'
+ );
+
+ $this->doApiRequestWithToken( array(
+ 'action' => 'edit',
+ 'title' => 'Dummy:ApiEditPageTest_nonTextPageEdit',
+ 'text' => '{"animals":["kittens!"]}'
+ ) );
+ }
+
+ public function testSupportsDirectApiEditing_withContentHandlerOverride() {
+ $name = 'DummyNonText:ApiEditPageTest_testNonTextEdit';
+ $data = serialize( 'some bla bla text' );
+
+ $result = $this->doApiRequestWithToken( array(
+ 'action' => 'edit',
+ 'title' => $name,
+ 'text' => $data,
+ ) );
+
+ $apiResult = $result[0];
+
+ // Validate API result data
+ $this->assertArrayHasKey( 'edit', $apiResult );
+ $this->assertArrayHasKey( 'result', $apiResult['edit'] );
+ $this->assertEquals( 'Success', $apiResult['edit']['result'] );
+
+ $this->assertArrayHasKey( 'new', $apiResult['edit'] );
+ $this->assertArrayNotHasKey( 'nochange', $apiResult['edit'] );
+
+ $this->assertArrayHasKey( 'pageid', $apiResult['edit'] );
+
+ // validate resulting revision
+ $page = WikiPage::factory( Title::newFromText( $name ) );
+ $this->assertEquals( "testing-nontext", $page->getContentModel() );
+ $this->assertEquals( $data, $page->getContent()->serialize() );
+ }
}
diff --git a/tests/phpunit/includes/api/ApiLoginTest.php b/tests/phpunit/includes/api/ApiLoginTest.php
index 88a99e9b..7dfd14f3 100644
--- a/tests/phpunit/includes/api/ApiLoginTest.php
+++ b/tests/phpunit/includes/api/ApiLoginTest.php
@@ -23,7 +23,7 @@ class ApiLoginTest extends ApiTestCase {
global $wgServer;
$user = self::$users['sysop'];
- $user->user->logOut();
+ $user->getUser()->logOut();
if ( !isset( $wgServer ) ) {
$this->markTestIncomplete( 'This test needs $wgServer to be set in LocalSettings.php' );
@@ -68,7 +68,7 @@ class ApiLoginTest extends ApiTestCase {
}
$user = self::$users['sysop'];
- $user->user->logOut();
+ $user->getUser()->logOut();
$ret = $this->doApiRequest( array(
"action" => "login",
diff --git a/tests/phpunit/includes/api/ApiMainTest.php b/tests/phpunit/includes/api/ApiMainTest.php
index e8ef1804..94b741dc 100644
--- a/tests/phpunit/includes/api/ApiMainTest.php
+++ b/tests/phpunit/includes/api/ApiMainTest.php
@@ -71,7 +71,7 @@ class ApiMainTest extends ApiTestCase {
new FauxRequest( array( 'action' => 'query', 'meta' => 'siteinfo' ) )
);
$modules = $api->getModuleManager()->getNamesWithClasses();
- foreach( $modules as $name => $class ) {
+ foreach ( $modules as $name => $class ) {
$this->assertArrayHasKey(
$class,
$classes,
@@ -79,4 +79,173 @@ class ApiMainTest extends ApiTestCase {
);
}
}
+
+ /**
+ * Test HTTP precondition headers
+ *
+ * @covers ApiMain::checkConditionalRequestHeaders
+ * @dataProvider provideCheckConditionalRequestHeaders
+ * @param array $headers HTTP headers
+ * @param array $conditions Return data for ApiBase::getConditionalRequestData
+ * @param int $status Expected response status
+ * @param bool $post Request is a POST
+ */
+ public function testCheckConditionalRequestHeaders( $headers, $conditions, $status, $post = false ) {
+ $request = new FauxRequest( array( 'action' => 'query', 'meta' => 'siteinfo' ), $post );
+ $request->setHeaders( $headers );
+ $request->response()->statusHeader( 200 ); // Why doesn't it default?
+
+ $api = new ApiMain( $request );
+ $priv = TestingAccessWrapper::newFromObject( $api );
+ $priv->mInternalMode = false;
+
+ $module = $this->getMockBuilder( 'ApiBase' )
+ ->setConstructorArgs( array( $api, 'mock' ) )
+ ->setMethods( array( 'getConditionalRequestData' ) )
+ ->getMockForAbstractClass();
+ $module->expects( $this->any() )
+ ->method( 'getConditionalRequestData' )
+ ->will( $this->returnCallback( function ( $condition ) use ( $conditions ) {
+ return isset( $conditions[$condition] ) ? $conditions[$condition] : null;
+ } ) );
+
+ $ret = $priv->checkConditionalRequestHeaders( $module );
+
+ $this->assertSame( $status, $request->response()->getStatusCode() );
+ $this->assertSame( $status === 200, $ret );
+ }
+
+ public static function provideCheckConditionalRequestHeaders() {
+ $now = time();
+
+ return array(
+ // Non-existing from module is ignored
+ array( array( 'If-None-Match' => '"foo", "bar"' ), array(), 200 ),
+ array( array( 'If-Modified-Since' => 'Tue, 18 Aug 2015 00:00:00 GMT' ), array(), 200 ),
+
+ // No headers
+ array(
+ array(),
+ array(
+ 'etag' => '""',
+ 'last-modified' => '20150815000000',
+ ),
+ 200
+ ),
+
+ // Basic If-None-Match
+ array( array( 'If-None-Match' => '"foo", "bar"' ), array( 'etag' => '"bar"' ), 304 ),
+ array( array( 'If-None-Match' => '"foo", "bar"' ), array( 'etag' => '"baz"' ), 200 ),
+ array( array( 'If-None-Match' => '"foo"' ), array( 'etag' => 'W/"foo"' ), 304 ),
+ array( array( 'If-None-Match' => 'W/"foo"' ), array( 'etag' => '"foo"' ), 304 ),
+ array( array( 'If-None-Match' => 'W/"foo"' ), array( 'etag' => 'W/"foo"' ), 304 ),
+
+ // Pointless, but supported
+ array( array( 'If-None-Match' => '*' ), array(), 304 ),
+
+ // Basic If-Modified-Since
+ array( array( 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) ),
+ array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 304 ),
+ array( array( 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) ),
+ array( 'last-modified' => wfTimestamp( TS_MW, $now ) ), 304 ),
+ array( array( 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) ),
+ array( 'last-modified' => wfTimestamp( TS_MW, $now + 1 ) ), 200 ),
+
+ // If-Modified-Since ignored when If-None-Match is given too
+ array( array( 'If-None-Match' => '""', 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) ),
+ array( 'etag' => '"x"', 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 200 ),
+ array( array( 'If-None-Match' => '""', 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) ),
+ array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 304 ),
+
+ // Ignored for POST
+ array( array( 'If-None-Match' => '"foo", "bar"' ), array( 'etag' => '"bar"' ), 200, true ),
+ array( array( 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) ),
+ array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 200, true ),
+
+ // Other date formats allowed by the RFC
+ array( array( 'If-Modified-Since' => gmdate( 'l, d-M-y H:i:s', $now ) . ' GMT' ),
+ array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 304 ),
+ array( array( 'If-Modified-Since' => gmdate( 'D M j H:i:s Y', $now ) ),
+ array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 304 ),
+
+ // Old browser extension to HTTP/1.0
+ array( array( 'If-Modified-Since' => wfTimestamp( TS_RFC2822, $now ) . '; length=123' ),
+ array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 304 ),
+
+ // Invalid date formats should be ignored
+ array( array( 'If-Modified-Since' => gmdate( 'Y-m-d H:i:s', $now ) . ' GMT' ),
+ array( 'last-modified' => wfTimestamp( TS_MW, $now - 1 ) ), 200 ),
+ );
+ }
+
+ /**
+ * Test conditional headers output
+ * @dataProvider provideConditionalRequestHeadersOutput
+ * @param array $conditions Return data for ApiBase::getConditionalRequestData
+ * @param array $headers Expected output headers
+ * @param bool $isError $isError flag
+ * @param bool $post Request is a POST
+ */
+ public function testConditionalRequestHeadersOutput( $conditions, $headers, $isError = false, $post = false ) {
+ $request = new FauxRequest( array( 'action' => 'query', 'meta' => 'siteinfo' ), $post );
+ $response = $request->response();
+
+ $api = new ApiMain( $request );
+ $priv = TestingAccessWrapper::newFromObject( $api );
+ $priv->mInternalMode = false;
+
+ $module = $this->getMockBuilder( 'ApiBase' )
+ ->setConstructorArgs( array( $api, 'mock' ) )
+ ->setMethods( array( 'getConditionalRequestData' ) )
+ ->getMockForAbstractClass();
+ $module->expects( $this->any() )
+ ->method( 'getConditionalRequestData' )
+ ->will( $this->returnCallback( function ( $condition ) use ( $conditions ) {
+ return isset( $conditions[$condition] ) ? $conditions[$condition] : null;
+ } ) );
+ $priv->mModule = $module;
+
+ $priv->sendCacheHeaders( $isError );
+
+ foreach ( array( 'Last-Modified', 'ETag' ) as $header ) {
+ $this->assertEquals(
+ isset( $headers[$header] ) ? $headers[$header] : null,
+ $response->getHeader( $header ),
+ $header
+ );
+ }
+ }
+
+ public static function provideConditionalRequestHeadersOutput() {
+ return array(
+ array(
+ array(),
+ array()
+ ),
+ array(
+ array( 'etag' => '"foo"' ),
+ array( 'ETag' => '"foo"' )
+ ),
+ array(
+ array( 'last-modified' => '20150818000102' ),
+ array( 'Last-Modified' => 'Tue, 18 Aug 2015 00:01:02 GMT' )
+ ),
+ array(
+ array( 'etag' => '"foo"', 'last-modified' => '20150818000102' ),
+ array( 'ETag' => '"foo"', 'Last-Modified' => 'Tue, 18 Aug 2015 00:01:02 GMT' )
+ ),
+ array(
+ array( 'etag' => '"foo"', 'last-modified' => '20150818000102' ),
+ array(),
+ true,
+ ),
+ array(
+ array( 'etag' => '"foo"', 'last-modified' => '20150818000102' ),
+ array(),
+ false,
+ true,
+ ),
+ );
+ }
+
}
diff --git a/tests/phpunit/includes/api/ApiMessageTest.php b/tests/phpunit/includes/api/ApiMessageTest.php
index 6c3ce60d..08a984eb 100644
--- a/tests/phpunit/includes/api/ApiMessageTest.php
+++ b/tests/phpunit/includes/api/ApiMessageTest.php
@@ -14,9 +14,13 @@ class ApiMessageTest extends MediaWikiTestCase {
$msg = TestingAccessWrapper::newFromObject( $msg );
$msg2 = TestingAccessWrapper::newFromObject( $msg2 );
- foreach ( array( 'interface', 'useDatabase', 'title' ) as $key ) {
- $this->assertSame( $msg->$key, $msg2->$key, $key );
- }
+ $this->assertSame( $msg->interface, $msg2->interface, 'interface' );
+ $this->assertSame( $msg->useDatabase, $msg2->useDatabase, 'useDatabase' );
+ $this->assertSame(
+ $msg->title ? $msg->title->getFullText() : null,
+ $msg2->title ? $msg2->title->getFullText() : null,
+ 'title'
+ );
}
/**
@@ -30,6 +34,11 @@ class ApiMessageTest extends MediaWikiTestCase {
$this->assertEquals( 'code', $msg2->getApiCode() );
$this->assertEquals( array( 'data' ), $msg2->getApiData() );
+ $msg2 = unserialize( serialize( $msg2 ) );
+ $this->compareMessages( $msg, $msg2 );
+ $this->assertEquals( 'code', $msg2->getApiCode() );
+ $this->assertEquals( array( 'data' ), $msg2->getApiData() );
+
$msg = new Message( array( 'foo', 'bar' ), array( 'baz' ) );
$msg2 = new ApiMessage( array( array( 'foo', 'bar' ), 'baz' ), 'code', array( 'data' ) );
$this->compareMessages( $msg, $msg2 );
@@ -63,6 +72,11 @@ class ApiMessageTest extends MediaWikiTestCase {
$this->assertEquals( 'code', $msg2->getApiCode() );
$this->assertEquals( array( 'data' ), $msg2->getApiData() );
+ $msg2 = unserialize( serialize( $msg2 ) );
+ $this->compareMessages( $msg, $msg2 );
+ $this->assertEquals( 'code', $msg2->getApiCode() );
+ $this->assertEquals( array( 'data' ), $msg2->getApiData() );
+
$msg = new RawMessage( 'foo', array( 'baz' ) );
$msg2 = new ApiRawMessage( array( 'foo', 'baz' ), 'code', array( 'data' ) );
$this->compareMessages( $msg, $msg2 );
diff --git a/tests/phpunit/includes/api/ApiQueryAllPagesTest.php b/tests/phpunit/includes/api/ApiQueryAllPagesTest.php
index 124988f3..0ac00eea 100644
--- a/tests/phpunit/includes/api/ApiQueryAllPagesTest.php
+++ b/tests/phpunit/includes/api/ApiQueryAllPagesTest.php
@@ -13,9 +13,11 @@ class ApiQueryAllPagesTest extends ApiTestCase {
}
/**
- * @todo give this test a real name explaining what is being tested here
+ *Test bug 25702
+ *Prefixes of API search requests are not handled with case sensitivity and may result
+ *in wrong search results
*/
- public function testBug25702() {
+ public function testPrefixNormalizationSearchBug() {
$title = Title::newFromText( 'Category:Template:xyz' );
$page = WikiPage::factory( $title );
$page->doEdit( 'Some text', 'inserting content' );
diff --git a/tests/phpunit/includes/api/ApiResultTest.php b/tests/phpunit/includes/api/ApiResultTest.php
index f0d84552..2f31677e 100644
--- a/tests/phpunit/includes/api/ApiResultTest.php
+++ b/tests/phpunit/includes/api/ApiResultTest.php
@@ -181,6 +181,19 @@ class ApiResultTest extends MediaWikiTestCase {
);
}
+ ApiResult::setValue( $arr, null, NAN, ApiResult::NO_VALIDATE );
+
+ try {
+ ApiResult::setValue( $arr, null, NAN, ApiResult::NO_SIZE_CHECK );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( InvalidArgumentException $ex ) {
+ $this->assertSame(
+ 'Cannot add non-finite floats to ApiResult',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+
$arr = array();
$result2 = new ApiResult( 8388608 );
$result2->addValue( null, 'foo', 'bar' );
@@ -408,6 +421,19 @@ class ApiResultTest extends MediaWikiTestCase {
);
}
+ $result->addValue( null, null, NAN, ApiResult::NO_VALIDATE );
+
+ try {
+ $result->addValue( null, null, NAN, ApiResult::NO_SIZE_CHECK );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( InvalidArgumentException $ex ) {
+ $this->assertSame(
+ 'Cannot add non-finite floats to ApiResult',
+ $ex->getMessage(),
+ 'Expected exception'
+ );
+ }
+
$result->reset();
$result->addParsedLimit( 'foo', 12 );
$this->assertSame( array(
@@ -444,6 +470,12 @@ class ApiResultTest extends MediaWikiTestCase {
$result->removeValue( null, 'foo' );
$this->assertTrue( $result->addValue( null, 'foo', '1' ) );
+ $result = new ApiResult( 10 );
+ $obj = new ApiResultTestSerializableObject( 'ok' );
+ $obj->foobar = 'foobaz';
+ $this->assertTrue( $result->addValue( null, 'foo', $obj ) );
+ $this->assertSame( 2, $result->getSize() );
+
$result = new ApiResult( 8388608 );
$result2 = new ApiResult( 8388608 );
$result2->addValue( null, 'foo', 'bar' );
@@ -674,6 +706,10 @@ class ApiResultTest extends MediaWikiTestCase {
ApiResult::META_TYPE => 'BCkvp',
ApiResult::META_KVP_KEY_NAME => 'key',
),
+ 'kvpmerge' => array( 'x' => 'a', 'y' => array( 'b' ), 'z' => array( 'c' => 'd' ),
+ ApiResult::META_TYPE => 'kvp',
+ ApiResult::META_KVP_MERGE => true,
+ ),
'emptyDefault' => array( '_dummy' => 1 ),
'emptyAssoc' => array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ),
'_dummy' => 1,
@@ -858,6 +894,13 @@ class ApiResultTest extends MediaWikiTestCase {
ApiResult::META_TYPE => 'assoc',
ApiResult::META_KVP_KEY_NAME => 'key',
),
+ 'kvpmerge' => array(
+ 'x' => 'a',
+ 'y' => array( 'b', ApiResult::META_TYPE => 'array' ),
+ 'z' => array( 'c' => 'd', ApiResult::META_TYPE => 'assoc' ),
+ ApiResult::META_TYPE => 'assoc',
+ ApiResult::META_KVP_MERGE => true,
+ ),
'emptyDefault' => array( '_dummy' => 1, ApiResult::META_TYPE => 'array' ),
'emptyAssoc' => array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ),
'_dummy' => 1,
@@ -871,8 +914,12 @@ class ApiResultTest extends MediaWikiTestCase {
array( 'Types' => array( 'AssocAsObject' => true ) ),
(object)array(
'defaultArray' => array( 'b', 'c', 'a', ApiResult::META_TYPE => 'array' ),
- 'defaultAssoc' => (object)array( 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ),
- 'defaultAssoc2' => (object)array( 2 => 'a', 3 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ),
+ 'defaultAssoc' => (object)array( 'x' => 'a',
+ 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc'
+ ),
+ 'defaultAssoc2' => (object)array( 2 => 'a', 3 => 'b',
+ 0 => 'c', ApiResult::META_TYPE => 'assoc'
+ ),
'array' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ),
'BCarray' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ),
'BCassoc' => (object)array( 'a', 'b', 'c', ApiResult::META_TYPE => 'assoc' ),
@@ -885,6 +932,13 @@ class ApiResultTest extends MediaWikiTestCase {
ApiResult::META_TYPE => 'assoc',
ApiResult::META_KVP_KEY_NAME => 'key',
),
+ 'kvpmerge' => (object)array(
+ 'x' => 'a',
+ 'y' => array( 'b', ApiResult::META_TYPE => 'array' ),
+ 'z' => (object)array( 'c' => 'd', ApiResult::META_TYPE => 'assoc' ),
+ ApiResult::META_TYPE => 'assoc',
+ ApiResult::META_KVP_MERGE => true,
+ ),
'emptyDefault' => array( '_dummy' => 1, ApiResult::META_TYPE => 'array' ),
'emptyAssoc' => (object)array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ),
'_dummy' => 1,
@@ -916,6 +970,13 @@ class ApiResultTest extends MediaWikiTestCase {
ApiResult::META_TYPE => 'array',
ApiResult::META_KVP_KEY_NAME => 'key',
),
+ 'kvpmerge' => array(
+ $kvp( 'name', 'x', 'value', 'a' ),
+ $kvp( 'name', 'y', 'value', array( 'b', ApiResult::META_TYPE => 'array' ) ),
+ array( 'name' => 'z', 'c' => 'd', ApiResult::META_TYPE => 'assoc', ApiResult::META_PRESERVE_KEYS => array( 'name' ) ),
+ ApiResult::META_TYPE => 'array',
+ ApiResult::META_KVP_MERGE => true,
+ ),
'emptyDefault' => array( '_dummy' => 1, ApiResult::META_TYPE => 'array' ),
'emptyAssoc' => array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ),
'_dummy' => 1,
@@ -947,6 +1008,13 @@ class ApiResultTest extends MediaWikiTestCase {
ApiResult::META_TYPE => 'array',
ApiResult::META_KVP_KEY_NAME => 'key',
),
+ 'kvpmerge' => array(
+ $kvp( 'name', 'x', '*', 'a' ),
+ $kvp( 'name', 'y', '*', array( 'b', ApiResult::META_TYPE => 'array' ) ),
+ array( 'name' => 'z', 'c' => 'd', ApiResult::META_TYPE => 'assoc', ApiResult::META_PRESERVE_KEYS => array( 'name' ) ),
+ ApiResult::META_TYPE => 'array',
+ ApiResult::META_KVP_MERGE => true,
+ ),
'emptyDefault' => array( '_dummy' => 1, ApiResult::META_TYPE => 'array' ),
'emptyAssoc' => array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ),
'_dummy' => 1,
@@ -960,8 +1028,12 @@ class ApiResultTest extends MediaWikiTestCase {
array( 'Types' => array( 'ArmorKVP' => 'name', 'AssocAsObject' => true ) ),
(object)array(
'defaultArray' => array( 'b', 'c', 'a', ApiResult::META_TYPE => 'array' ),
- 'defaultAssoc' => (object)array( 'x' => 'a', 1 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ),
- 'defaultAssoc2' => (object)array( 2 => 'a', 3 => 'b', 0 => 'c', ApiResult::META_TYPE => 'assoc' ),
+ 'defaultAssoc' => (object)array( 'x' => 'a', 1 => 'b',
+ 0 => 'c', ApiResult::META_TYPE => 'assoc'
+ ),
+ 'defaultAssoc2' => (object)array( 2 => 'a', 3 => 'b',
+ 0 => 'c', ApiResult::META_TYPE => 'assoc'
+ ),
'array' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ),
'BCarray' => array( 'a', 'c', 'b', ApiResult::META_TYPE => 'array' ),
'BCassoc' => (object)array( 'a', 'b', 'c', ApiResult::META_TYPE => 'assoc' ),
@@ -978,6 +1050,13 @@ class ApiResultTest extends MediaWikiTestCase {
ApiResult::META_TYPE => 'array',
ApiResult::META_KVP_KEY_NAME => 'key',
),
+ 'kvpmerge' => array(
+ (object)$kvp( 'name', 'x', 'value', 'a' ),
+ (object)$kvp( 'name', 'y', 'value', array( 'b', ApiResult::META_TYPE => 'array' ) ),
+ (object)array( 'name' => 'z', 'c' => 'd', ApiResult::META_TYPE => 'assoc', ApiResult::META_PRESERVE_KEYS => array( 'name' ) ),
+ ApiResult::META_TYPE => 'array',
+ ApiResult::META_KVP_MERGE => true,
+ ),
'emptyDefault' => array( '_dummy' => 1, ApiResult::META_TYPE => 'array' ),
'emptyAssoc' => (object)array( '_dummy' => 1, ApiResult::META_TYPE => 'assoc' ),
'_dummy' => 1,
@@ -1017,6 +1096,11 @@ class ApiResultTest extends MediaWikiTestCase {
(object)array( 'key' => 'x', 'value' => 'a' ),
(object)array( 'key' => 'y', 'value' => 'b' ),
),
+ 'kvpmerge' => array(
+ (object)array( 'name' => 'x', 'value' => 'a' ),
+ (object)array( 'name' => 'y', 'value' => array( 'b' ) ),
+ (object)array( 'name' => 'z', 'c' => 'd' ),
+ ),
'emptyDefault' => array(),
'emptyAssoc' => (object)array(),
'_dummy' => 1,
@@ -1124,6 +1208,76 @@ class ApiResultTest extends MediaWikiTestCase {
$data[ApiResult::META_CONTENT] = 'bar';
}
+ /**
+ * @covers ApiResult
+ */
+ public function testAddMetadataToResultVars() {
+ $arr = array(
+ 'a' => "foo",
+ 'b' => false,
+ 'c' => 10,
+ 'sequential_numeric_keys' => array( 'a', 'b', 'c' ),
+ 'non_sequential_numeric_keys' => array( 'a', 'b', 4 => 'c' ),
+ 'string_keys' => array(
+ 'one' => 1,
+ 'two' => 2
+ ),
+ 'object_sequential_keys' => (object)array( 'a', 'b', 'c' ),
+ '_type' => "should be overwritten in result",
+ );
+ $this->assertSame( array(
+ ApiResult::META_TYPE => 'kvp',
+ ApiResult::META_KVP_KEY_NAME => 'key',
+ ApiResult::META_PRESERVE_KEYS => array(
+ 'a', 'b', 'c',
+ 'sequential_numeric_keys', 'non_sequential_numeric_keys',
+ 'string_keys', 'object_sequential_keys'
+ ),
+ ApiResult::META_BC_BOOLS => array( 'b' ),
+ ApiResult::META_INDEXED_TAG_NAME => 'var',
+ 'a' => "foo",
+ 'b' => false,
+ 'c' => 10,
+ 'sequential_numeric_keys' => array(
+ ApiResult::META_TYPE => 'array',
+ ApiResult::META_BC_BOOLS => array(),
+ ApiResult::META_INDEXED_TAG_NAME => 'value',
+ 0 => 'a',
+ 1 => 'b',
+ 2 => 'c',
+ ),
+ 'non_sequential_numeric_keys' => array(
+ ApiResult::META_TYPE => 'kvp',
+ ApiResult::META_KVP_KEY_NAME => 'key',
+ ApiResult::META_PRESERVE_KEYS => array( 0, 1, 4 ),
+ ApiResult::META_BC_BOOLS => array(),
+ ApiResult::META_INDEXED_TAG_NAME => 'var',
+ 0 => 'a',
+ 1 => 'b',
+ 4 => 'c',
+ ),
+ 'string_keys' => array(
+ ApiResult::META_TYPE => 'kvp',
+ ApiResult::META_KVP_KEY_NAME => 'key',
+ ApiResult::META_PRESERVE_KEYS => array( 'one', 'two' ),
+ ApiResult::META_BC_BOOLS => array(),
+ ApiResult::META_INDEXED_TAG_NAME => 'var',
+ 'one' => 1,
+ 'two' => 2,
+ ),
+ 'object_sequential_keys' => array(
+ ApiResult::META_TYPE => 'kvp',
+ ApiResult::META_KVP_KEY_NAME => 'key',
+ ApiResult::META_PRESERVE_KEYS => array( 0, 1, 2 ),
+ ApiResult::META_BC_BOOLS => array(),
+ ApiResult::META_INDEXED_TAG_NAME => 'var',
+ 0 => 'a',
+ 1 => 'b',
+ 2 => 'c',
+ ),
+ ), ApiResult::addMetadataToResultVars( $arr ) );
+ }
+
/**
* @covers ApiResult
*/
@@ -1133,7 +1287,8 @@ class ApiResultTest extends MediaWikiTestCase {
if ( preg_match( '/Use of ApiResult::\S+ was deprecated in MediaWiki \d+.\d+\./', $errstr ) ) {
return true;
}
- if ( preg_match( '/Use of ApiMain to ApiResult::__construct was deprecated in MediaWiki \d+.\d+\./', $errstr ) ) {
+ if ( preg_match( '/Use of ApiMain to ApiResult::__construct ' .
+ 'was deprecated in MediaWiki \d+.\d+\./', $errstr ) ) {
return true;
}
return false;
@@ -1166,17 +1321,6 @@ class ApiResultTest extends MediaWikiTestCase {
),
'*' => 'content',
), $result->getData() );
- $result->setRawMode();
- $this->assertSame( array(
- 'foo' => array(
- 'bar' => array(
- '*' => 'content',
- ),
- ),
- '*' => 'content',
- '_element' => 'itn',
- '_subelements' => array( 'sub' ),
- ), $result->getData() );
$arr = array();
ApiResult::setContent( $arr, 'value' );
@@ -1451,7 +1595,8 @@ class ApiResultTest extends MediaWikiTestCase {
$result = new ApiResult( 8388608 );
$result->setMainForContinuation( $main );
- $result->beginContinuation( '||mock2', array_slice( $allModules, 0, 2 ), array( 'mock1', 'mock2' ) );
+ $result->beginContinuation( '||mock2', array_slice( $allModules, 0, 2 ),
+ array( 'mock1', 'mock2' ) );
try {
$result->setContinueParam( $allModules[1], 'm2continue', 1 );
$this->fail( 'Expected exception not thrown' );
@@ -1467,7 +1612,8 @@ class ApiResultTest extends MediaWikiTestCase {
$this->fail( 'Expected exception not thrown' );
} catch ( UnexpectedValueException $ex ) {
$this->assertSame(
- 'Module \'mocklist\' called ApiContinuationManager::addContinueParam but was not passed to ApiContinuationManager::__construct',
+ 'Module \'mocklist\' called ApiContinuationManager::addContinueParam ' .
+ 'but was not passed to ApiContinuationManager::__construct',
$ex->getMessage(),
'Expected exception'
);
@@ -1495,13 +1641,14 @@ class ApiResultTest extends MediaWikiTestCase {
try {
$arr = array();
- ApiResult::setValue( $arr, 'foo', new ApiResultTestSerializableObject(
+ ApiResult::setValue( $arr, 'foo', new ApiResultTestSerializableObject(
new ApiResultTestStringifiableObject()
) );
$this->fail( 'Expected exception not thrown' );
} catch ( UnexpectedValueException $ex ) {
$this->assertSame(
- 'ApiResultTestSerializableObject::serializeForApiResult() returned an object of class ApiResultTestStringifiableObject',
+ 'ApiResultTestSerializableObject::serializeForApiResult() ' .
+ 'returned an object of class ApiResultTestStringifiableObject',
$ex->getMessage(),
'Expected exception'
);
@@ -1509,18 +1656,19 @@ class ApiResultTest extends MediaWikiTestCase {
try {
$arr = array();
- ApiResult::setValue( $arr, 'foo', new ApiResultTestSerializableObject( NAN ) );
+ ApiResult::setValue( $arr, 'foo', new ApiResultTestSerializableObject( NAN ) );
$this->fail( 'Expected exception not thrown' );
} catch ( UnexpectedValueException $ex ) {
$this->assertSame(
- 'ApiResultTestSerializableObject::serializeForApiResult() returned an invalid value: Cannot add non-finite floats to ApiResult',
+ 'ApiResultTestSerializableObject::serializeForApiResult() ' .
+ 'returned an invalid value: Cannot add non-finite floats to ApiResult',
$ex->getMessage(),
'Expected exception'
);
}
$arr = array();
- ApiResult::setValue( $arr, 'foo', new ApiResultTestSerializableObject(
+ ApiResult::setValue( $arr, 'foo', new ApiResultTestSerializableObject(
array(
'one' => new ApiResultTestStringifiableObject( '1' ),
'two' => new ApiResultTestSerializableObject( 2 ),
diff --git a/tests/phpunit/includes/api/ApiRevisionDeleteTest.php b/tests/phpunit/includes/api/ApiRevisionDeleteTest.php
index b03836eb..362d647f 100644
--- a/tests/phpunit/includes/api/ApiRevisionDeleteTest.php
+++ b/tests/phpunit/includes/api/ApiRevisionDeleteTest.php
@@ -25,7 +25,7 @@ class ApiRevisionDeleteTest extends ApiTestCase {
}
public function testHidingRevisions() {
- $user = self::$users['sysop']->user;
+ $user = self::$users['sysop']->getUser();
$revid = array_shift( $this->revs );
$out = $this->doApiRequest( array(
'action' => 'revisiondelete',
@@ -80,7 +80,7 @@ class ApiRevisionDeleteTest extends ApiTestCase {
}
public function testUnhidingOutput() {
- $user = self::$users['sysop']->user;
+ $user = self::$users['sysop']->getUser();
$revid = array_shift( $this->revs );
// Hide revisions
$this->doApiRequest( array(
diff --git a/tests/phpunit/includes/api/ApiTestCase.php b/tests/phpunit/includes/api/ApiTestCase.php
index da62bb0a..21345ac1 100644
--- a/tests/phpunit/includes/api/ApiTestCase.php
+++ b/tests/phpunit/includes/api/ApiTestCase.php
@@ -105,6 +105,7 @@ abstract class ApiTestCase extends MediaWikiLangTestCase {
$wgRequest = new FauxRequest( $params, true, $session );
RequestContext::getMain()->setRequest( $wgRequest );
+ RequestContext::getMain()->setUser( $wgUser );
// set up local environment
$context = $this->apiContext->newTestContext( $wgRequest, $wgUser );
diff --git a/tests/phpunit/includes/api/ApiUnblockTest.php b/tests/phpunit/includes/api/ApiUnblockTest.php
index 2c2370a8..a374f094 100644
--- a/tests/phpunit/includes/api/ApiUnblockTest.php
+++ b/tests/phpunit/includes/api/ApiUnblockTest.php
@@ -16,7 +16,7 @@ class ApiUnblockTest extends ApiTestCase {
/**
* @expectedException UsageException
*/
- public function testWithNoToken( ) {
+ public function testWithNoToken() {
$this->doApiRequest(
array(
'action' => 'unblock',
@@ -25,7 +25,7 @@ class ApiUnblockTest extends ApiTestCase {
),
null,
false,
- self::$users['sysop']->user
+ self::$users['sysop']->getUser()
);
}
}
diff --git a/tests/phpunit/includes/api/ApiUploadTest.php b/tests/phpunit/includes/api/ApiUploadTest.php
index f74fc354..c852d72b 100644
--- a/tests/phpunit/includes/api/ApiUploadTest.php
+++ b/tests/phpunit/includes/api/ApiUploadTest.php
@@ -80,7 +80,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
try {
$this->doApiRequestWithToken( array(
'action' => 'upload',
- ), $session, self::$users['uploader']->user );
+ ), $session, self::$users['uploader']->getUser() );
} catch ( UsageException $e ) {
$exception = true;
$this->assertEquals( "One of the parameters filekey, file, url, statuskey is required",
@@ -126,7 +126,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
$exception = false;
try {
list( $result, , ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->user );
+ self::$users['uploader']->getUser() );
} catch ( UsageException $e ) {
$exception = true;
}
@@ -165,7 +165,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
$exception = false;
try {
- $this->doApiRequestWithToken( $params, $session, self::$users['uploader']->user );
+ $this->doApiRequestWithToken( $params, $session, self::$users['uploader']->getUser() );
} catch ( UsageException $e ) {
$this->assertContains( 'The file you submitted was empty', $e->getMessage() );
$exception = true;
@@ -215,7 +215,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
$exception = false;
try {
list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->user );
+ self::$users['uploader']->getUser() );
} catch ( UsageException $e ) {
$exception = true;
}
@@ -232,7 +232,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
$exception = false;
try {
list( $result, , ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->user ); // FIXME: leaks a temporary file
+ self::$users['uploader']->getUser() ); // FIXME: leaks a temporary file
} catch ( UsageException $e ) {
$exception = true;
}
@@ -286,7 +286,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
$exception = false;
try {
list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->user );
+ self::$users['uploader']->getUser() );
} catch ( UsageException $e ) {
$exception = true;
}
@@ -311,7 +311,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
$exception = false;
try {
list( $result ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->user ); // FIXME: leaks a temporary file
+ self::$users['uploader']->getUser() ); // FIXME: leaks a temporary file
} catch ( UsageException $e ) {
$exception = true;
}
@@ -331,7 +331,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
*/
public function testUploadStash( $session ) {
$this->setMwGlobals( array(
- 'wgUser' => self::$users['uploader']->user, // @todo FIXME: still used somewhere
+ 'wgUser' => self::$users['uploader']->getUser(), // @todo FIXME: still used somewhere
) );
$extension = 'png';
@@ -368,7 +368,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
$exception = false;
try {
list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->user ); // FIXME: leaks a temporary file
+ self::$users['uploader']->getUser() ); // FIXME: leaks a temporary file
} catch ( UsageException $e ) {
$exception = true;
}
@@ -397,7 +397,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
$exception = false;
try {
list( $result ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->user );
+ self::$users['uploader']->getUser() );
} catch ( UsageException $e ) {
$exception = true;
}
@@ -415,7 +415,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
public function testUploadChunks( $session ) {
$this->setMwGlobals( array(
// @todo FIXME: still used somewhere
- 'wgUser' => self::$users['uploader']->user,
+ 'wgUser' => self::$users['uploader']->getUser(),
) );
$chunkSize = 1048576;
@@ -451,9 +451,9 @@ class ApiUploadTest extends ApiTestCaseUpload {
$chunkSessionKey = false;
$resultOffset = 0;
// Open the file:
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$handle = fopen( $filePath, "r" );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $handle === false ) {
$this->markTestIncomplete( "could not open file: $filePath" );
@@ -461,9 +461,9 @@ class ApiUploadTest extends ApiTestCaseUpload {
while ( !feof( $handle ) ) {
// Get the current chunk
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$chunkData = fread( $handle, $chunkSize );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
// Upload the current chunk into the $_FILE object:
$this->fakeUploadChunk( 'chunk', 'blob', $mimeType, $chunkData );
@@ -473,7 +473,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
// Upload fist chunk ( and get the session key )
try {
list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->user );
+ self::$users['uploader']->getUser() );
} catch ( UsageException $e ) {
$this->markTestIncomplete( $e->getMessage() );
}
@@ -501,7 +501,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
// Upload current chunk
try {
list( $result, , $session ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->user );
+ self::$users['uploader']->getUser() );
} catch ( UsageException $e ) {
$this->markTestIncomplete( $e->getMessage() );
}
@@ -541,7 +541,7 @@ class ApiUploadTest extends ApiTestCaseUpload {
$exception = false;
try {
list( $result ) = $this->doApiRequestWithToken( $params, $session,
- self::$users['uploader']->user );
+ self::$users['uploader']->getUser() );
} catch ( UsageException $e ) {
$exception = true;
}
diff --git a/tests/phpunit/includes/api/format/ApiFormatDumpTest.php b/tests/phpunit/includes/api/format/ApiFormatDumpTest.php
deleted file mode 100644
index c0f67f8d..00000000
--- a/tests/phpunit/includes/api/format/ApiFormatDumpTest.php
+++ /dev/null
@@ -1,63 +0,0 @@
- true ) ),
- );
- }
-
- $warning = "\n [\"warnings\"]=>\n array(1) {\n [\"dump\"]=>\n array(1) {\n [\"*\"]=>\n" .
- " string(64) \"format=dump has been deprecated. Please use format=json instead.\"\n" .
- " }\n }";
-
- return array(
- // Basic types
- array( array( null ), "array(2) {{$warning}\n [0]=>\n NULL\n}\n" ),
- array( array( true ), "array(2) {{$warning}\n [0]=>\n string(0) \"\"\n}\n" ),
- array( array( false ), "array(1) {{$warning}\n}\n" ),
- array( array( true, ApiResult::META_BC_BOOLS => array( 0 ) ),
- "array(2) {{$warning}\n [0]=>\n bool(true)\n}\n" ),
- array( array( false, ApiResult::META_BC_BOOLS => array( 0 ) ),
- "array(2) {{$warning}\n [0]=>\n bool(false)\n}\n" ),
- array( array( 42 ), "array(2) {{$warning}\n [0]=>\n int(42)\n}\n" ),
- array( array( 42.5 ), "array(2) {{$warning}\n [0]=>\n float(42.5)\n}\n" ),
- array( array( 1e42 ), "array(2) {{$warning}\n [0]=>\n float(1.0E+42)\n}\n" ),
- array( array( 'foo' ), "array(2) {{$warning}\n [0]=>\n string(3) \"foo\"\n}\n" ),
- array( array( 'fóo' ), "array(2) {{$warning}\n [0]=>\n string(4) \"fóo\"\n}\n" ),
-
- // Arrays
- array( array( array() ), "array(2) {{$warning}\n [0]=>\n array(0) {\n }\n}\n" ),
- array( array( array( 1 ) ), "array(2) {{$warning}\n [0]=>\n array(1) {\n [0]=>\n int(1)\n }\n}\n" ),
- array( array( array( 'x' => 1 ) ), "array(2) {{$warning}\n [0]=>\n array(1) {\n [\"x\"]=>\n int(1)\n }\n}\n" ),
- array( array( array( 2 => 1 ) ), "array(2) {{$warning}\n [0]=>\n array(1) {\n [2]=>\n int(1)\n }\n}\n" ),
- array( array( (object)array() ), "array(2) {{$warning}\n [0]=>\n array(0) {\n }\n}\n" ),
- array( array( array( 1, ApiResult::META_TYPE => 'assoc' ) ), "array(2) {{$warning}\n [0]=>\n array(1) {\n [0]=>\n int(1)\n }\n}\n" ),
- array( array( array( 'x' => 1, ApiResult::META_TYPE => 'array' ) ), "array(2) {{$warning}\n [0]=>\n array(1) {\n [0]=>\n int(1)\n }\n}\n" ),
- array( array( array( 'x' => 1, ApiResult::META_TYPE => 'kvp' ) ), "array(2) {{$warning}\n [0]=>\n array(1) {\n [\"x\"]=>\n int(1)\n }\n}\n" ),
- array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ) ),
- "array(2) {{$warning}\n [0]=>\n array(1) {\n [0]=>\n array(2) {\n [\"key\"]=>\n string(1) \"x\"\n [\"*\"]=>\n int(1)\n }\n }\n}\n" ),
- array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCarray' ) ), "array(2) {{$warning}\n [0]=>\n array(1) {\n [\"x\"]=>\n int(1)\n }\n}\n" ),
- array( array( array( 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ) ), "array(2) {{$warning}\n [0]=>\n array(2) {\n [0]=>\n string(1) \"a\"\n [1]=>\n string(1) \"b\"\n }\n}\n" ),
-
- // Content
- array( array( 'content' => 'foo', ApiResult::META_CONTENT => 'content' ),
- "array(2) {{$warning}\n [\"*\"]=>\n string(3) \"foo\"\n}\n" ),
-
- // BC Subelements
- array( array( 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => array( 'foo' ) ),
- "array(2) {{$warning}\n [\"foo\"]=>\n array(1) {\n [\"*\"]=>\n string(3) \"foo\"\n }\n}\n" ),
- );
- }
-
-}
diff --git a/tests/phpunit/includes/api/format/ApiFormatWddxTest.php b/tests/phpunit/includes/api/format/ApiFormatWddxTest.php
deleted file mode 100644
index 07111300..00000000
--- a/tests/phpunit/includes/api/format/ApiFormatWddxTest.php
+++ /dev/null
@@ -1,80 +0,0 @@
- true ) )
- );
- }
- return self::provideEncoding();
- }
-
- public static function provideEncoding() {
- $p = 'format=wddx has been deprecated. Please use format=json instead. ';
- $s = ' ';
-
- return array(
- // Basic types
- array( array( null ), "{$p} {$s}" ),
- array( array( true ), "{$p} {$s}" ),
- array( array( false ), "{$p}{$s}" ),
- array( array( true, ApiResult::META_BC_BOOLS => array( 0 ) ),
- "{$p} {$s}" ),
- array( array( false, ApiResult::META_BC_BOOLS => array( 0 ) ),
- "{$p} {$s}" ),
- array( array( 42 ), "{$p}42 {$s}" ),
- array( array( 42.5 ), "{$p}42.5 {$s}" ),
- array( array( 1e42 ), "{$p}1.0E+42 {$s}" ),
- array( array( 'foo' ), "{$p}foo {$s}" ),
- array( array( 'fóo' ), "{$p}fóo {$s}" ),
-
- // Arrays and objects
- array( array( array() ), "{$p} {$s}" ),
- array( array( array( 1 ) ), "{$p}1 {$s}" ),
- array( array( array( 'x' => 1 ) ), "{$p}1 {$s}" ),
- array( array( array( 2 => 1 ) ), "{$p}1 {$s}" ),
- array( array( (object)array() ), "{$p} {$s}" ),
- array( array( array( 1, ApiResult::META_TYPE => 'assoc' ) ), "{$p}1 {$s}" ),
- array( array( array( 'x' => 1, ApiResult::META_TYPE => 'array' ) ), "{$p}1 {$s}" ),
- array( array( array( 'x' => 1, ApiResult::META_TYPE => 'kvp' ) ), "{$p}1 {$s}" ),
- array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ) ),
- "{$p}x 1 {$s}" ),
- array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCarray' ) ), "{$p}1 {$s}" ),
- array( array( array( 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ) ), "{$p}a b {$s}" ),
-
- // Content
- array( array( 'content' => 'foo', ApiResult::META_CONTENT => 'content' ),
- "{$p}foo {$s}" ),
-
- // BC Subelements
- array( array( 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => array( 'foo' ) ),
- "{$p}foo {$s}" ),
- );
- }
-
- /**
- * @dataProvider provideEncoding
- */
- public function testSlowEncoding( array $data, $expect, array $params = array() ) {
- // Adjust expectation for differences between fast and slow printers.
- $expect = str_replace( '\'', '"', $expect );
- $expect = str_replace( '/>', ' />', $expect );
- $expect = '' . $expect;
-
- $this->assertSame( $expect, $this->encodeData( $params, $data, 'ApiFormatWddxTest_SlowWddx' ) );
- }
-}
-
-class ApiFormatWddxTest_SlowWddx extends ApiFormatWddx {
- public static function useSlowPrinter() {
- return true;
- }
-}
diff --git a/tests/phpunit/includes/api/query/ApiQueryContinueTestBase.php b/tests/phpunit/includes/api/query/ApiQueryContinueTestBase.php
index ce2f70de..db61bc80 100644
--- a/tests/phpunit/includes/api/query/ApiQueryContinueTestBase.php
+++ b/tests/phpunit/includes/api/query/ApiQueryContinueTestBase.php
@@ -57,10 +57,9 @@ abstract class ApiQueryContinueTestBase extends ApiQueryTestBase {
} else {
$params['action'] = 'query';
}
- if ( $useContinue && !isset( $params['continue'] ) ) {
+ // Silence warning
+ if ( !isset( $params['continue'] ) ) {
$params['continue'] = '';
- } else {
- $params['rawcontinue'] = '1';
}
$count = 0;
$result = array();
diff --git a/tests/phpunit/includes/api/query/ApiQueryTest.php b/tests/phpunit/includes/api/query/ApiQueryTest.php
index 5f061b50..61b992ba 100644
--- a/tests/phpunit/includes/api/query/ApiQueryTest.php
+++ b/tests/phpunit/includes/api/query/ApiQueryTest.php
@@ -131,7 +131,7 @@ class ApiQueryTest extends ApiTestCase {
);
$queryApi = new ApiQuery( $api, 'query' );
$modules = $queryApi->getModuleManager()->getNamesWithClasses();
- foreach( $modules as $name => $class ) {
+ foreach ( $modules as $name => $class ) {
$this->assertArrayHasKey(
$class,
$classes,
diff --git a/tests/phpunit/includes/api/query/ApiQueryTestBase.php b/tests/phpunit/includes/api/query/ApiQueryTestBase.php
index dabf72e0..d5fa4542 100644
--- a/tests/phpunit/includes/api/query/ApiQueryTestBase.php
+++ b/tests/phpunit/includes/api/query/ApiQueryTestBase.php
@@ -56,12 +56,12 @@ STR;
* @return array
*/
private function validateRequestExpectedPair( $v ) {
- $this->assertType( 'array', $v, self::PARAM_ASSERT );
+ $this->assertInternalType( 'array', $v, self::PARAM_ASSERT );
$this->assertEquals( 2, count( $v ), self::PARAM_ASSERT );
$this->assertArrayHasKey( 0, $v, self::PARAM_ASSERT );
$this->assertArrayHasKey( 1, $v, self::PARAM_ASSERT );
- $this->assertType( 'array', $v[0], self::PARAM_ASSERT );
- $this->assertType( 'array', $v[1], self::PARAM_ASSERT );
+ $this->assertInternalType( 'array', $v[0], self::PARAM_ASSERT );
+ $this->assertInternalType( 'array', $v[1], self::PARAM_ASSERT );
return $v;
}
@@ -87,6 +87,7 @@ STR;
/**
* Checks that the request's result matches the expected results.
+ * Assumes no rawcontinue and a complete batch.
* @param array $values Array is a two element array( request, expected_results )
* @param array $session
* @param bool $appendModule
@@ -99,8 +100,9 @@ STR;
if ( !array_key_exists( 'action', $req ) ) {
$req['action'] = 'query';
}
- if ( !array_key_exists( 'continue', $req ) ) {
- $req['rawcontinue'] = '1';
+ // Silence warning
+ if ( !isset( $params['continue'] ) ) {
+ $params['continue'] = '';
}
foreach ( $req as &$val ) {
if ( is_array( $val ) ) {
@@ -108,7 +110,7 @@ STR;
}
}
$result = $this->doApiRequest( $req, $session, $appendModule, $user );
- $this->assertResult( array( 'query' => $exp ), $result[0], $req );
+ $this->assertResult( array( 'batchcomplete' => true, 'query' => $exp ), $result[0], $req );
}
protected function assertResult( $exp, $result, $message = '' ) {
diff --git a/tests/phpunit/includes/cache/MessageCacheTest.php b/tests/phpunit/includes/cache/MessageCacheTest.php
index 442e9f9f..5302b363 100644
--- a/tests/phpunit/includes/cache/MessageCacheTest.php
+++ b/tests/phpunit/includes/cache/MessageCacheTest.php
@@ -52,7 +52,7 @@ class MessageCacheTest extends MediaWikiLangTestCase {
$this->makePage( 'MessageCacheTest-FullKeyTest', 'ru' );
// In content language -- get base if no derivative
- $this->makePage( 'FallbackLanguageTest-NoDervContLang', 'de', 'de/none', false );
+ $this->makePage( 'FallbackLanguageTest-NoDervContLang', 'de', 'de/none' );
}
/**
@@ -61,15 +61,14 @@ class MessageCacheTest extends MediaWikiLangTestCase {
* @param string $title Title of page to be created
* @param string $lang Language and content of the created page
* @param string|null $content Content of the created page, or null for a generic string
- * @param bool $createSubPage Set to false if a root page should be created
*/
- protected function makePage( $title, $lang, $content = null, $createSubPage = true ) {
+ protected function makePage( $title, $lang, $content = null ) {
global $wgContLang;
if ( $content === null ) {
$content = $lang;
}
- if ( $lang !== $wgContLang->getCode() || $createSubPage ) {
+ if ( $lang !== $wgContLang->getCode() ) {
$title = "$title/$lang";
}
@@ -125,4 +124,26 @@ class MessageCacheTest extends MediaWikiLangTestCase {
);
}
+ /**
+ * @dataProvider provideNormalizeKey
+ */
+ public function testNormalizeKey( $key, $expected ) {
+ $actual = MessageCache::normalizeKey( $key );
+ $this->assertEquals( $expected, $actual );
+ }
+
+ public function provideNormalizeKey() {
+ return array(
+ array( 'Foo', 'foo' ),
+ array( 'foo', 'foo' ),
+ array( 'fOo', 'fOo' ),
+ array( 'FOO', 'fOO' ),
+ array( 'Foo bar', 'foo_bar' ),
+ array( 'Ćab', 'ćab' ),
+ array( 'Ćab_e 3', 'ćab_e_3' ),
+ array( 'ĆAB', 'ćAB' ),
+ array( 'ćab', 'ćab' ),
+ array( 'ćaB', 'ćaB' ),
+ );
+ }
}
diff --git a/tests/phpunit/includes/changes/RecentChangeTest.php b/tests/phpunit/includes/changes/RecentChangeTest.php
index b3cb7b52..4d1a936e 100644
--- a/tests/phpunit/includes/changes/RecentChangeTest.php
+++ b/tests/phpunit/includes/changes/RecentChangeTest.php
@@ -10,8 +10,8 @@ class RecentChangeTest extends MediaWikiTestCase {
protected $user_comment;
protected $context;
- public function __construct() {
- parent::__construct();
+ public function setUp() {
+ parent::setUp();
$this->title = Title::newFromText( 'SomeTitle' );
$this->target = Title::newFromText( 'TestTarget' );
@@ -21,6 +21,26 @@ class RecentChangeTest extends MediaWikiTestCase {
$this->context = RequestContext::newExtraneousContext( $this->title );
}
+ /**
+ * @covers RecentChange::newFromRow
+ * @covers RecentChange::loadFromRow
+ */
+ public function testNewFromRow() {
+ $row = new stdClass();
+ $row->rc_foo = 'AAA';
+ $row->rc_timestamp = '20150921134808';
+ $row->rc_deleted = 'bar';
+
+ $rc = RecentChange::newFromRow( $row );
+
+ $expected = array(
+ 'rc_foo' => 'AAA',
+ 'rc_timestamp' => '20150921134808',
+ 'rc_deleted' => 'bar',
+ );
+ $this->assertEquals( $expected, $rc->getAttributes() );
+ }
+
/**
* The testIrcMsgForAction* tests are supposed to cover the hacky
* LogFormatter::getIRCActionText / bug 34508
@@ -46,6 +66,7 @@ class RecentChangeTest extends MediaWikiTestCase {
* - protect/protect
* - protect/modifyprotect
* - protect/unprotect
+ * - protect/move_prot
* - upload/upload
* - merge/merge
* - import/upload
@@ -59,289 +80,95 @@ class RecentChangeTest extends MediaWikiTestCase {
*/
/**
- * @covers LogFormatter::getIRCActionText
- */
- public function testIrcMsgForLogTypeBlock() {
- $sep = $this->context->msg( 'colon-separator' )->text();
-
- # block/block
- $this->assertIRCComment(
- $this->context->msg( 'blocklogentry', 'SomeTitle', 'duration', '(flags)' )->plain()
- . $sep . $this->user_comment,
- 'block', 'block',
- array(
- '5::duration' => 'duration',
- '6::flags' => 'flags',
- ),
- $this->user_comment
- );
- # block/unblock
- $this->assertIRCComment(
- $this->context->msg( 'unblocklogentry', 'SomeTitle' )->plain() . $sep . $this->user_comment,
- 'block', 'unblock',
- array(),
- $this->user_comment
- );
- # block/reblock
- $this->assertIRCComment(
- $this->context->msg( 'reblock-logentry', 'SomeTitle', 'duration', '(flags)' )->plain()
- . $sep . $this->user_comment,
- 'block', 'reblock',
- array(
- '5::duration' => 'duration',
- '6::flags' => 'flags',
- ),
- $this->user_comment
- );
- }
-
- /**
- * @covers LogFormatter::getIRCActionText
- */
- public function testIrcMsgForLogTypeDelete() {
- $sep = $this->context->msg( 'colon-separator' )->text();
-
- # delete/delete
- $this->assertIRCComment(
- $this->context->msg( 'deletedarticle', 'SomeTitle' )->plain() . $sep . $this->user_comment,
- 'delete', 'delete',
- array(),
- $this->user_comment
- );
-
- # delete/restore
- $this->assertIRCComment(
- $this->context->msg( 'undeletedarticle', 'SomeTitle' )->plain() . $sep . $this->user_comment,
- 'delete', 'restore',
- array(),
- $this->user_comment
- );
- }
-
- /**
- * @covers LogFormatter::getIRCActionText
- */
- public function testIrcMsgForLogTypeNewusers() {
- $this->assertIRCComment(
- 'New user account',
- 'newusers', 'newusers',
- array()
- );
- $this->assertIRCComment(
- 'New user account',
- 'newusers', 'create',
- array()
- );
- $this->assertIRCComment(
- 'created new account SomeTitle',
- 'newusers', 'create2',
- array()
- );
- $this->assertIRCComment(
- 'Account created automatically',
- 'newusers', 'autocreate',
- array()
- );
- }
-
- /**
- * @covers LogFormatter::getIRCActionText
- */
- public function testIrcMsgForLogTypeMove() {
- $move_params = array(
- '4::target' => $this->target->getPrefixedText(),
- '5::noredir' => 0,
- );
- $sep = $this->context->msg( 'colon-separator' )->text();
-
- # move/move
- $this->assertIRCComment(
- $this->context->msg( '1movedto2', 'SomeTitle', 'TestTarget' )
- ->plain() . $sep . $this->user_comment,
- 'move', 'move',
- $move_params,
- $this->user_comment
- );
-
- # move/move_redir
- $this->assertIRCComment(
- $this->context->msg( '1movedto2_redir', 'SomeTitle', 'TestTarget' )
- ->plain() . $sep . $this->user_comment,
- 'move', 'move_redir',
- $move_params,
- $this->user_comment
- );
- }
-
- /**
- * @covers LogFormatter::getIRCActionText
+ * @covers RecentChange::parseParams
*/
- public function testIrcMsgForLogTypePatrol() {
- # patrol/patrol
- $this->assertIRCComment(
- $this->context->msg( 'patrol-log-line', 'revision 777', '[[SomeTitle]]', '' )->plain(),
- 'patrol', 'patrol',
- array(
- '4::curid' => '777',
- '5::previd' => '666',
- '6::auto' => 0,
+ public function testParseParams() {
+ $params = array(
+ 'root' => array(
+ 'A' => 1,
+ 'B' => 'two'
)
);
- }
- /**
- * @covers LogFormatter::getIRCActionText
- */
- public function testIrcMsgForLogTypeProtect() {
- $protectParams = array(
- '[edit=sysop] (indefinite) [move=sysop] (indefinite)'
+ $this->assertParseParams(
+ $params,
+ 'a:1:{s:4:"root";a:2:{s:1:"A";i:1;s:1:"B";s:3:"two";}}'
);
- $sep = $this->context->msg( 'colon-separator' )->text();
- # protect/protect
- $this->assertIRCComment(
- $this->context->msg( 'protectedarticle', 'SomeTitle ' . $protectParams[0] )
- ->plain() . $sep . $this->user_comment,
- 'protect', 'protect',
- $protectParams,
- $this->user_comment
+ $this->assertParseParams(
+ null,
+ null
);
- # protect/unprotect
- $this->assertIRCComment(
- $this->context->msg( 'unprotectedarticle', 'SomeTitle' )->plain() . $sep . $this->user_comment,
- 'protect', 'unprotect',
- array(),
- $this->user_comment
+ $this->assertParseParams(
+ null,
+ serialize( false )
);
- # protect/modify
- $this->assertIRCComment(
- $this->context->msg( 'modifiedarticleprotection', 'SomeTitle ' . $protectParams[0] )
- ->plain() . $sep . $this->user_comment,
- 'protect', 'modify',
- $protectParams,
- $this->user_comment
+ $this->assertParseParams(
+ null,
+ 'not-an-array'
);
}
/**
- * @covers LogFormatter::getIRCActionText
+ * @param array $expectedParseParams
+ * @param string|null $rawRcParams
*/
- public function testIrcMsgForLogTypeUpload() {
- $sep = $this->context->msg( 'colon-separator' )->text();
+ protected function assertParseParams( $expectedParseParams, $rawRcParams ) {
+ $rc = new RecentChange;
+ $rc->setAttribs( array( 'rc_params' => $rawRcParams ) );
- # upload/upload
- $this->assertIRCComment(
- $this->context->msg( 'uploadedimage', 'SomeTitle' )->plain() . $sep . $this->user_comment,
- 'upload', 'upload',
- array(),
- $this->user_comment
- );
+ $actualParseParams = $rc->parseParams();
- # upload/overwrite
- $this->assertIRCComment(
- $this->context->msg( 'overwroteimage', 'SomeTitle' )->plain() . $sep . $this->user_comment,
- 'upload', 'overwrite',
- array(),
- $this->user_comment
- );
+ $this->assertEquals( $expectedParseParams, $actualParseParams );
}
/**
- * @covers LogFormatter::getIRCActionText
+ * 50 mins and 100 mins are used here as the tests never take that long!
+ * @return array
*/
- public function testIrcMsgForLogTypeMerge() {
- $sep = $this->context->msg( 'colon-separator' )->text();
-
- # merge/merge
- $this->assertIRCComment(
- $this->context->msg( 'pagemerge-logentry', 'SomeTitle', 'Dest', 'timestamp' )->plain()
- . $sep . $this->user_comment,
- 'merge', 'merge',
- array(
- '4::dest' => 'Dest',
- '5::mergepoint' => 'timestamp',
- ),
- $this->user_comment
+ public function provideIsInRCLifespan() {
+ return array(
+ array( 6000, time() - 3000, 0, true ),
+ array( 3000, time() - 6000, 0, false ),
+ array( 6000, time() - 3000, 6000, true ),
+ array( 3000, time() - 6000, 6000, true ),
);
}
/**
- * @covers LogFormatter::getIRCActionText
+ * @covers RecentChange::isInRCLifespan
+ * @dataProvider provideIsInRCLifespan
*/
- public function testIrcMsgForLogTypeImport() {
- $sep = $this->context->msg( 'colon-separator' )->text();
-
- # import/upload
- $this->assertIRCComment(
- $this->context->msg( 'import-logentry-upload', 'SomeTitle' )->plain() . $sep . $this->user_comment,
- 'import', 'upload',
- array(),
- $this->user_comment
- );
+ public function testIsInRCLifespan( $maxAge, $timestamp, $tolerance, $expected ) {
+ $this->setMwGlobals( 'wgRCMaxAge', $maxAge );
+ $this->assertEquals( $expected, RecentChange::isInRCLifespan( $timestamp, $tolerance ) );
+ }
- # import/interwiki
- $this->assertIRCComment(
- $this->context->msg( 'import-logentry-interwiki', 'SomeTitle' )->plain() . $sep . $this->user_comment,
- 'import', 'interwiki',
- array(),
- $this->user_comment
+ public function provideRCTypes() {
+ return array(
+ array( RC_EDIT, 'edit' ),
+ array( RC_NEW, 'new' ),
+ array( RC_LOG, 'log' ),
+ array( RC_EXTERNAL, 'external' ),
);
}
/**
- * @todo Emulate these edits somehow and extract
- * raw edit summary from RecentChange object
- * --
+ * @dataProvider provideRCTypes
+ * @covers RecentChange::parseFromRCType
*/
- /*
- public function testIrcMsgForBlankingAES() {
- // $this->context->msg( 'autosumm-blank', .. );
- }
-
- public function testIrcMsgForReplaceAES() {
- // $this->context->msg( 'autosumm-replace', .. );
- }
-
- public function testIrcMsgForRollbackAES() {
- // $this->context->msg( 'revertpage', .. );
+ public function testParseFromRCType( $rcType, $type ) {
+ $this->assertEquals( $type, RecentChange::parseFromRCType( $rcType ) );
}
- public function testIrcMsgForUndoAES() {
- // $this->context->msg( 'undo-summary', .. );
- }
- */
-
/**
- * @param string $expected Expected IRC text without colors codes
- * @param string $type Log type (move, delete, suppress, patrol ...)
- * @param string $action A log type action
- * @param array $params
- * @param string $comment (optional) A comment for the log action
- * @param string $msg (optional) A message for PHPUnit :-)
+ * @dataProvider provideRCTypes
+ * @covers RecentChange::parseToRCType
*/
- protected function assertIRCComment( $expected, $type, $action, $params,
- $comment = null, $msg = ''
- ) {
- $logEntry = new ManualLogEntry( $type, $action );
- $logEntry->setPerformer( $this->user );
- $logEntry->setTarget( $this->title );
- if ( $comment !== null ) {
- $logEntry->setComment( $comment );
- }
- $logEntry->setParameters( $params );
-
- $formatter = LogFormatter::newFromEntry( $logEntry );
- $formatter->setContext( $this->context );
-
- // Apply the same transformation as done in IRCColourfulRCFeedFormatter::getLine for rc_comment
- $ircRcComment = IRCColourfulRCFeedFormatter::cleanupForIRC( $formatter->getIRCActionComment() );
-
- $this->assertEquals(
- $expected,
- $ircRcComment,
- $msg
- );
+ public function testParseToRCType( $rcType, $type ) {
+ $this->assertEquals( $rcType, RecentChange::parseToRCType( $type ) );
}
+
}
diff --git a/tests/phpunit/includes/config/HashConfigTest.php b/tests/phpunit/includes/config/HashConfigTest.php
index 06973b09..4aa3e30c 100644
--- a/tests/phpunit/includes/config/HashConfigTest.php
+++ b/tests/phpunit/includes/config/HashConfigTest.php
@@ -30,7 +30,7 @@ class HashConfigTest extends MediaWikiTestCase {
public function testGet() {
$conf = new HashConfig( array(
'one' => '1',
- ));
+ ) );
$this->assertEquals( '1', $conf->get( 'one' ) );
$this->setExpectedException( 'ConfigException', 'HashConfig::get: undefined option' );
$conf->get( 'two' );
diff --git a/tests/phpunit/includes/content/ContentHandlerTest.php b/tests/phpunit/includes/content/ContentHandlerTest.php
index 988a59ee..8178c12e 100644
--- a/tests/phpunit/includes/content/ContentHandlerTest.php
+++ b/tests/phpunit/includes/content/ContentHandlerTest.php
@@ -22,6 +22,7 @@ class ContentHandlerTest extends MediaWikiTestCase {
'wgContentHandlers' => array(
CONTENT_MODEL_WIKITEXT => 'WikitextContentHandler',
CONTENT_MODEL_JAVASCRIPT => 'JavaScriptContentHandler',
+ CONTENT_MODEL_JSON => 'JsonContentHandler',
CONTENT_MODEL_CSS => 'CssContentHandler',
CONTENT_MODEL_TEXT => 'TextContentHandler',
'testing' => 'DummyContentHandlerForTesting',
@@ -51,19 +52,27 @@ class ContentHandlerTest extends MediaWikiTestCase {
return array(
array( 'Help:Foo', CONTENT_MODEL_WIKITEXT ),
array( 'Help:Foo.js', CONTENT_MODEL_WIKITEXT ),
+ array( 'Help:Foo.css', CONTENT_MODEL_WIKITEXT ),
+ array( 'Help:Foo.json', CONTENT_MODEL_WIKITEXT ),
array( 'Help:Foo/bar.js', CONTENT_MODEL_WIKITEXT ),
array( 'User:Foo', CONTENT_MODEL_WIKITEXT ),
array( 'User:Foo.js', CONTENT_MODEL_WIKITEXT ),
+ array( 'User:Foo.css', CONTENT_MODEL_WIKITEXT ),
+ array( 'User:Foo.json', CONTENT_MODEL_WIKITEXT ),
array( 'User:Foo/bar.js', CONTENT_MODEL_JAVASCRIPT ),
array( 'User:Foo/bar.css', CONTENT_MODEL_CSS ),
+ array( 'User:Foo/bar.json', CONTENT_MODEL_JSON ),
+ array( 'User:Foo/bar.json.nope', CONTENT_MODEL_WIKITEXT ),
array( 'User talk:Foo/bar.css', CONTENT_MODEL_WIKITEXT ),
array( 'User:Foo/bar.js.xxx', CONTENT_MODEL_WIKITEXT ),
array( 'User:Foo/bar.xxx', CONTENT_MODEL_WIKITEXT ),
array( 'MediaWiki:Foo.js', CONTENT_MODEL_JAVASCRIPT ),
- array( 'MediaWiki:Foo.css', CONTENT_MODEL_CSS ),
array( 'MediaWiki:Foo.JS', CONTENT_MODEL_WIKITEXT ),
- array( 'MediaWiki:Foo.CSS', CONTENT_MODEL_WIKITEXT ),
+ array( 'MediaWiki:Foo.css', CONTENT_MODEL_CSS ),
array( 'MediaWiki:Foo.css.xxx', CONTENT_MODEL_WIKITEXT ),
+ array( 'MediaWiki:Foo.CSS', CONTENT_MODEL_WIKITEXT ),
+ array( 'MediaWiki:Foo.json', CONTENT_MODEL_JSON ),
+ array( 'MediaWiki:Foo.JSON', CONTENT_MODEL_WIKITEXT ),
);
}
@@ -338,6 +347,11 @@ class ContentHandlerTest extends MediaWikiTestCase {
}
*/
+ public function testSupportsDirectEditing() {
+ $handler = new DummyContentHandlerForTesting( CONTENT_MODEL_JSON );
+ $this->assertFalse( $handler->supportsDirectEditing(), 'direct editing is not supported' );
+ }
+
/**
* @covers ContentHandler::runLegacyHooks
*/
@@ -365,164 +379,3 @@ class ContentHandlerTest extends MediaWikiTestCase {
return true;
}
}
-
-class DummyContentHandlerForTesting extends ContentHandler {
-
- public function __construct( $dataModel ) {
- parent::__construct( $dataModel, array( "testing" ) );
- }
-
- /**
- * @see ContentHandler::serializeContent
- *
- * @param Content $content
- * @param string $format
- *
- * @return string
- */
- public function serializeContent( Content $content, $format = null ) {
- return $content->serialize();
- }
-
- /**
- * @see ContentHandler::unserializeContent
- *
- * @param string $blob
- * @param string $format Unused.
- *
- * @return Content
- */
- public function unserializeContent( $blob, $format = null ) {
- $d = unserialize( $blob );
-
- return new DummyContentForTesting( $d );
- }
-
- /**
- * Creates an empty Content object of the type supported by this ContentHandler.
- *
- */
- public function makeEmptyContent() {
- return new DummyContentForTesting( '' );
- }
-}
-
-class DummyContentForTesting extends AbstractContent {
-
- public function __construct( $data ) {
- parent::__construct( "testing" );
-
- $this->data = $data;
- }
-
- public function serialize( $format = null ) {
- return serialize( $this->data );
- }
-
- /**
- * @return string A string representing the content in a way useful for
- * building a full text search index. If no useful representation exists,
- * this method returns an empty string.
- */
- public function getTextForSearchIndex() {
- return '';
- }
-
- /**
- * @return string|bool The wikitext to include when another page includes this content,
- * or false if the content is not includable in a wikitext page.
- */
- public function getWikitextForTransclusion() {
- return false;
- }
-
- /**
- * Returns a textual representation of the content suitable for use in edit
- * summaries and log messages.
- *
- * @param int $maxlength Maximum length of the summary text.
- * @return string The summary text.
- */
- public function getTextForSummary( $maxlength = 250 ) {
- return '';
- }
-
- /**
- * Returns native represenation of the data. Interpretation depends on the data model used,
- * as given by getDataModel().
- *
- * @return mixed The native representation of the content. Could be a string, a nested array
- * structure, an object, a binary blob... anything, really.
- */
- public function getNativeData() {
- return $this->data;
- }
-
- /**
- * returns the content's nominal size in bogo-bytes.
- *
- * @return int
- */
- public function getSize() {
- return strlen( $this->data );
- }
-
- /**
- * Return a copy of this Content object. The following must be true for the object returned
- * if $copy = $original->copy()
- *
- * * get_class($original) === get_class($copy)
- * * $original->getModel() === $copy->getModel()
- * * $original->equals( $copy )
- *
- * If and only if the Content object is imutable, the copy() method can and should
- * return $this. That is, $copy === $original may be true, but only for imutable content
- * objects.
- *
- * @return Content A copy of this object
- */
- public function copy() {
- return $this;
- }
-
- /**
- * Returns true if this content is countable as a "real" wiki page, provided
- * that it's also in a countable location (e.g. a current revision in the main namespace).
- *
- * @param bool $hasLinks If it is known whether this content contains links,
- * provide this information here, to avoid redundant parsing to find out.
- * @return bool
- */
- public function isCountable( $hasLinks = null ) {
- return false;
- }
-
- /**
- * @param Title $title
- * @param int $revId Unused.
- * @param null|ParserOptions $options
- * @param bool $generateHtml Whether to generate Html (default: true). If false, the result
- * of calling getText() on the ParserOutput object returned by this method is undefined.
- *
- * @return ParserOutput
- */
- public function getParserOutput( Title $title, $revId = null,
- ParserOptions $options = null, $generateHtml = true
- ) {
- return new ParserOutput( $this->getNativeData() );
- }
-
- /**
- * @see AbstractContent::fillParserOutput()
- *
- * @param Title $title Context title for parsing
- * @param int|null $revId Revision ID (for {{REVISIONID}})
- * @param ParserOptions $options Parser options
- * @param bool $generateHtml Whether or not to generate HTML
- * @param ParserOutput &$output The output object to fill (reference).
- */
- protected function fillParserOutput( Title $title, $revId,
- ParserOptions $options, $generateHtml, ParserOutput &$output ) {
- $output = new ParserOutput( $this->getNativeData() );
- }
-}
diff --git a/tests/phpunit/includes/content/CssContentHandlerTest.php b/tests/phpunit/includes/content/CssContentHandlerTest.php
new file mode 100644
index 00000000..e1785a96
--- /dev/null
+++ b/tests/phpunit/includes/content/CssContentHandlerTest.php
@@ -0,0 +1,30 @@
+setMwGlobals( array(
+ 'wgServer' => '//example.org',
+ 'wgScript' => '/w/index.php',
+ ) );
+ $ch = new CssContentHandler();
+ $content = $ch->makeRedirectContent( Title::newFromText( $title ) );
+ $this->assertInstanceOf( 'CssContent', $content );
+ $this->assertEquals( $expected, $content->serialize( CONTENT_FORMAT_CSS ) );
+ }
+
+ /**
+ * Keep this in sync with CssContentTest::provideGetRedirectTarget()
+ */
+ public static function provideMakeRedirectContent() {
+ return array(
+ array( 'MediaWiki:MonoBook.css', "/* #REDIRECT */@import url(//example.org/w/index.php?title=MediaWiki:MonoBook.css&action=raw&ctype=text/css);" ),
+ array( 'User:FooBar/common.css', "/* #REDIRECT */@import url(//example.org/w/index.php?title=User:FooBar/common.css&action=raw&ctype=text/css);" ),
+ array( 'Gadget:FooBaz.css', "/* #REDIRECT */@import url(//example.org/w/index.php?title=Gadget:FooBaz.css&action=raw&ctype=text/css);" ),
+ );
+ }
+}
diff --git a/tests/phpunit/includes/content/CssContentTest.php b/tests/phpunit/includes/content/CssContentTest.php
index 40484d3a..c4d87c24 100644
--- a/tests/phpunit/includes/content/CssContentTest.php
+++ b/tests/phpunit/includes/content/CssContentTest.php
@@ -4,6 +4,8 @@
* @group ContentHandler
* @group Database
* ^--- needed, because we do need the database to test link updates
+ *
+ * @FIXME this should not extend JavaScriptContentTest.
*/
class CssContentTest extends JavaScriptContentTest {
@@ -68,7 +70,48 @@ class CssContentTest extends JavaScriptContentTest {
$this->assertEquals( CONTENT_MODEL_CSS, $content->getContentHandler()->getModelID() );
}
- public static function dataEquals() {
+ /**
+ * Redirects aren't supported
+ */
+ public static function provideUpdateRedirect() {
+ return array(
+ array(
+ '#REDIRECT [[Someplace]]',
+ '#REDIRECT [[Someplace]]',
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideGetRedirectTarget
+ */
+ public function testGetRedirectTarget( $title, $text ) {
+ $this->setMwGlobals( array(
+ 'wgServer' => '//example.org',
+ 'wgScriptPath' => '/w',
+ 'wgScript' => '/w/index.php',
+ ) );
+ $content = new CssContent( $text );
+ $target = $content->getRedirectTarget();
+ $this->assertEquals( $title, $target ? $target->getPrefixedText() : null );
+ }
+
+ /**
+ * Keep this in sync with CssContentHandlerTest::provideMakeRedirectContent()
+ */
+ public static function provideGetRedirectTarget() {
+ return array(
+ array( 'MediaWiki:MonoBook.css', "/* #REDIRECT */@import url(//example.org/w/index.php?title=MediaWiki:MonoBook.css&action=raw&ctype=text/css);" ),
+ array( 'User:FooBar/common.css', "/* #REDIRECT */@import url(//example.org/w/index.php?title=User:FooBar/common.css&action=raw&ctype=text/css);" ),
+ array( 'Gadget:FooBaz.css', "/* #REDIRECT */@import url(//example.org/w/index.php?title=Gadget:FooBaz.css&action=raw&ctype=text/css);" ),
+ # No #REDIRECT comment
+ array( null, "@import url(//example.org/w/index.php?title=Gadget:FooBaz.css&action=raw&ctype=text/css);" ),
+ # Wrong domain
+ array( null, "/* #REDIRECT */@import url(//example.com/w/index.php?title=Gadget:FooBaz.css&action=raw&ctype=text/css);" ),
+ );
+ }
+
+ public static function dataEquals() {
return array(
array( new CssContent( 'hallo' ), null, false ),
array( new CssContent( 'hallo' ), new CssContent( 'hallo' ), true ),
diff --git a/tests/phpunit/includes/content/JavaScriptContentHandlerTest.php b/tests/phpunit/includes/content/JavaScriptContentHandlerTest.php
new file mode 100644
index 00000000..0f41020f
--- /dev/null
+++ b/tests/phpunit/includes/content/JavaScriptContentHandlerTest.php
@@ -0,0 +1,30 @@
+setMwGlobals( array(
+ 'wgServer' => '//example.org',
+ 'wgScript' => '/w/index.php',
+ ) );
+ $ch = new JavaScriptContentHandler();
+ $content = $ch->makeRedirectContent( Title::newFromText( $title ) );
+ $this->assertInstanceOf( 'JavaScriptContent', $content );
+ $this->assertEquals( $expected, $content->serialize( CONTENT_FORMAT_JAVASCRIPT ) );
+ }
+
+ /**
+ * Keep this in sync with JavaScriptContentTest::provideGetRedirectTarget()
+ */
+ public static function provideMakeRedirectContent() {
+ return array(
+ array( 'MediaWiki:MonoBook.js', '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=MediaWiki:MonoBook.js\u0026action=raw\u0026ctype=text/javascript");' ),
+ array( 'User:FooBar/common.js', '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=User:FooBar/common.js\u0026action=raw\u0026ctype=text/javascript");' ),
+ array( 'Gadget:FooBaz.js', '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=Gadget:FooBaz.js\u0026action=raw\u0026ctype=text/javascript");' ),
+ );
+ }
+}
diff --git a/tests/phpunit/includes/content/JavaScriptContentTest.php b/tests/phpunit/includes/content/JavaScriptContentTest.php
index 7193ec9f..0ee27129 100644
--- a/tests/phpunit/includes/content/JavaScriptContentTest.php
+++ b/tests/phpunit/includes/content/JavaScriptContentTest.php
@@ -251,16 +251,31 @@ class JavaScriptContentTest extends TextContentTest {
/**
* @covers JavaScriptContent::updateRedirect
+ * @dataProvider provideUpdateRedirect
*/
- public function testUpdateRedirect() {
+ public function testUpdateRedirect( $oldText, $expectedText) {
+ $this->setMwGlobals( array(
+ 'wgServer' => '//example.org',
+ 'wgScriptPath' => '/w/index.php',
+ ) );
$target = Title::newFromText( "testUpdateRedirect_target" );
- $content = $this->newContent( "#REDIRECT [[Someplace]]" );
+ $content = new JavaScriptContent( $oldText );
$newContent = $content->updateRedirect( $target );
- $this->assertTrue(
- $content->equals( $newContent ),
- "content should be unchanged since it's not wikitext"
+ $this->assertEquals( $expectedText, $newContent->getNativeData() );
+ }
+
+ public static function provideUpdateRedirect() {
+ return array(
+ array(
+ '#REDIRECT [[Someplace]]',
+ '#REDIRECT [[Someplace]]',
+ ),
+ array(
+ '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=MediaWiki:MonoBook.js\u0026action=raw\u0026ctype=text/javascript");',
+ '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=TestUpdateRedirect_target\u0026action=raw\u0026ctype=text/javascript");'
+ )
);
}
@@ -290,4 +305,32 @@ class JavaScriptContentTest extends TextContentTest {
array( new JavaScriptContent( "hallo" ), new JavaScriptContent( "HALLO" ), false ),
);
}
+
+ /**
+ * @dataProvider provideGetRedirectTarget
+ */
+ public function testGetRedirectTarget( $title, $text ) {
+ $this->setMwGlobals( array(
+ 'wgServer' => '//example.org',
+ 'wgScriptPath' => '/w/index.php',
+ ) );
+ $content = new JavaScriptContent( $text );
+ $target = $content->getRedirectTarget();
+ $this->assertEquals( $title, $target ? $target->getPrefixedText() : null );
+ }
+
+ /**
+ * Keep this in sync with JavaScriptContentHandlerTest::provideMakeRedirectContent()
+ */
+ public static function provideGetRedirectTarget() {
+ return array(
+ array( 'MediaWiki:MonoBook.js', '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=MediaWiki:MonoBook.js\u0026action=raw\u0026ctype=text/javascript");' ),
+ array( 'User:FooBar/common.js', '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=User:FooBar/common.js\u0026action=raw\u0026ctype=text/javascript");' ),
+ array( 'Gadget:FooBaz.js', '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=Gadget:FooBaz.js\u0026action=raw\u0026ctype=text/javascript");' ),
+ // No #REDIRECT comment
+ array( null, 'mw.loader.load("//example.org/w/index.php?title=MediaWiki:NoRedirect.js\u0026action=raw\u0026ctype=text/javascript");' ),
+ // Different domain
+ array( null, '/* #REDIRECT */mw.loader.load("//example.com/w/index.php?title=MediaWiki:OtherWiki.js\u0026action=raw\u0026ctype=text/javascript");' ),
+ );
+ }
}
diff --git a/tests/phpunit/includes/content/JsonContentTest.php b/tests/phpunit/includes/content/JsonContentTest.php
index cccfe7b1..8a9d2ab0 100644
--- a/tests/phpunit/includes/content/JsonContentTest.php
+++ b/tests/phpunit/includes/content/JsonContentTest.php
@@ -138,7 +138,7 @@ class JsonContentTest extends MediaWikiLangTestCase {
'0 "bar"
'
),
array(
- (object)array( ''),
+ (object)array( '' ),
'0 "' .
'<script>alert("evil!")</script>"' .
'
',
diff --git a/tests/phpunit/includes/content/TextContentHandlerTest.php b/tests/phpunit/includes/content/TextContentHandlerTest.php
new file mode 100644
index 00000000..492fec6b
--- /dev/null
+++ b/tests/phpunit/includes/content/TextContentHandlerTest.php
@@ -0,0 +1,12 @@
+assertTrue( $handler->supportsDirectEditing(), 'direct editing is supported' );
+ }
+
+}
diff --git a/tests/phpunit/includes/content/TextContentTest.php b/tests/phpunit/includes/content/TextContentTest.php
index dd61f85b..fe263756 100644
--- a/tests/phpunit/includes/content/TextContentTest.php
+++ b/tests/phpunit/includes/content/TextContentTest.php
@@ -27,10 +27,16 @@ class TextContentTest extends MediaWikiLangTestCase {
CONTENT_MODEL_JAVASCRIPT,
),
'wgUseTidy' => false,
- 'wgAlwaysUseTidy' => false,
'wgCapitalLinks' => true,
'wgHooks' => array(), // bypass hook ContentGetParserOutput that force custom rendering
) );
+
+ MWTidy::destroySingleton();
+ }
+
+ protected function tearDown() {
+ MWTidy::destroySingleton();
+ parent::tearDown();
}
public function newContent( $text ) {
diff --git a/tests/phpunit/includes/content/WikitextContentHandlerTest.php b/tests/phpunit/includes/content/WikitextContentHandlerTest.php
index 38fb5733..361238b7 100644
--- a/tests/phpunit/includes/content/WikitextContentHandlerTest.php
+++ b/tests/phpunit/includes/content/WikitextContentHandlerTest.php
@@ -115,6 +115,11 @@ class WikitextContentHandlerTest extends MediaWikiLangTestCase {
$this->assertEquals( $supported, $this->handler->isSupportedFormat( $format ) );
}
+ public function testSupportsDirectEditing() {
+ $handler = new WikiTextContentHandler();
+ $this->assertTrue( $handler->supportsDirectEditing(), 'direct editing is supported' );
+ }
+
public static function dataMerge3() {
return array(
array(
diff --git a/tests/phpunit/includes/db/DatabaseMysqlBaseTest.php b/tests/phpunit/includes/db/DatabaseMysqlBaseTest.php
index b4292a60..42ea58e5 100644
--- a/tests/phpunit/includes/db/DatabaseMysqlBaseTest.php
+++ b/tests/phpunit/includes/db/DatabaseMysqlBaseTest.php
@@ -181,7 +181,7 @@ class DatabaseMysqlBaseTest extends MediaWikiTestCase {
array( 'Tables_in_' => 'view2' ),
array( 'Tables_in_' => 'myview' ),
false # no more rows
- ));
+ ) );
return $db;
}
/**
diff --git a/tests/phpunit/includes/db/DatabaseSqliteTest.php b/tests/phpunit/includes/db/DatabaseSqliteTest.php
index 645baf1f..3db9172a 100644
--- a/tests/phpunit/includes/db/DatabaseSqliteTest.php
+++ b/tests/phpunit/includes/db/DatabaseSqliteTest.php
@@ -1,12 +1,13 @@
markTestSkipped( 'No SQLite support detected' );
}
- $this->db = MockDatabaseSqlite::newInstance();
+ $this->db = DatabaseSqliteMock::newInstance();
if ( version_compare( $this->db->getServerVersion(), '3.6.0', '<' ) ) {
$this->markTestSkipped( "SQLite at least 3.6 required, {$this->db->getServerVersion()} found" );
}
@@ -188,18 +189,34 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
public function testDuplicateTableStructure() {
$db = DatabaseSqlite::newStandaloneInstance( ':memory:' );
$db->query( 'CREATE TABLE foo(foo, barfoo)' );
+ $db->query( 'CREATE INDEX index1 ON foo(foo)' );
+ $db->query( 'CREATE UNIQUE INDEX index2 ON foo(barfoo)' );
$db->duplicateTableStructure( 'foo', 'bar' );
$this->assertEquals( 'CREATE TABLE "bar"(foo, barfoo)',
$db->selectField( 'sqlite_master', 'sql', array( 'name' => 'bar' ) ),
'Normal table duplication'
);
+ $indexList = $db->query( 'PRAGMA INDEX_LIST("bar")' );
+ $index = $indexList->next();
+ $this->assertEquals( 'bar_index1', $index->name );
+ $this->assertEquals( '0', $index->unique );
+ $index = $indexList->next();
+ $this->assertEquals( 'bar_index2', $index->name );
+ $this->assertEquals( '1', $index->unique );
$db->duplicateTableStructure( 'foo', 'baz', true );
$this->assertEquals( 'CREATE TABLE "baz"(foo, barfoo)',
$db->selectField( 'sqlite_temp_master', 'sql', array( 'name' => 'baz' ) ),
'Creation of temporary duplicate'
);
+ $indexList = $db->query( 'PRAGMA INDEX_LIST("baz")' );
+ $index = $indexList->next();
+ $this->assertEquals( 'baz_index1', $index->name );
+ $this->assertEquals( '0', $index->unique );
+ $index = $indexList->next();
+ $this->assertEquals( 'baz_index2', $index->name );
+ $this->assertEquals( '1', $index->unique );
$this->assertEquals( 0,
$db->selectField( 'sqlite_master', 'COUNT(*)', array( 'name' => 'baz' ) ),
'Create a temporary duplicate only'
diff --git a/tests/phpunit/includes/db/ORMTableTest.php b/tests/phpunit/includes/db/ORMTableTest.php
index 338d931f..764560d5 100644
--- a/tests/phpunit/includes/db/ORMTableTest.php
+++ b/tests/phpunit/includes/db/ORMTableTest.php
@@ -68,25 +68,6 @@ class ORMTableTest extends MediaWikiTestCase {
$this->assertInstanceOf( $class, $class::singleton() );
$this->assertTrue( $class::singleton() === $class::singleton() );
}
-
- /**
- * @since 1.21
- */
- public function testIgnoreErrorsOverride() {
- $table = $this->getTable();
-
- $db = $table->getReadDbConnection();
- $db->ignoreErrors( true );
-
- try {
- $table->rawSelect( "this is invalid" );
- $this->fail( "An invalid query should trigger a DBQueryError even if ignoreErrors is enabled." );
- } catch ( DBQueryError $ex ) {
- $this->assertTrue( true, "just making phpunit happy" );
- }
-
- $db->ignoreErrors( false );
- }
}
/**
diff --git a/tests/phpunit/includes/debug/MWDebugTest.php b/tests/phpunit/includes/debug/MWDebugTest.php
index 1abb47e7..7280a97b 100644
--- a/tests/phpunit/includes/debug/MWDebugTest.php
+++ b/tests/phpunit/includes/debug/MWDebugTest.php
@@ -12,11 +12,11 @@ class MWDebugTest extends MediaWikiTestCase {
}
/** Clear log before each test */
MWDebug::clearLog();
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
}
protected function tearDown() {
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
parent::tearDown();
}
diff --git a/tests/phpunit/includes/debug/logger/LegacyLoggerTest.php b/tests/phpunit/includes/debug/logger/LegacyLoggerTest.php
new file mode 100644
index 00000000..1b3ce2ca
--- /dev/null
+++ b/tests/phpunit/includes/debug/logger/LegacyLoggerTest.php
@@ -0,0 +1,175 @@
+assertEquals(
+ $expect, LegacyLogger::interpolate( $message, $context ) );
+ }
+
+ public function provideInterpolate() {
+ $e = new \Exception( 'boom!' );
+ $d = new \DateTime();
+ return array(
+ array(
+ 'no-op',
+ array(),
+ 'no-op',
+ ),
+ array(
+ 'Hello {world}!',
+ array(
+ 'world' => 'World',
+ ),
+ 'Hello World!',
+ ),
+ array(
+ '{greeting} {user}',
+ array(
+ 'greeting' => 'Goodnight',
+ 'user' => 'Moon',
+ ),
+ 'Goodnight Moon',
+ ),
+ array(
+ 'Oops {key_not_set}',
+ array(),
+ 'Oops {key_not_set}',
+ ),
+ array(
+ '{ not interpolated }',
+ array(
+ 'not interpolated' => 'This should NOT show up in the message',
+ ),
+ '{ not interpolated }',
+ ),
+ array(
+ '{null}',
+ array(
+ 'null' => null,
+ ),
+ '[Null]',
+ ),
+ array(
+ '{bool}',
+ array(
+ 'bool' => true,
+ ),
+ 'true',
+ ),
+ array(
+ '{float}',
+ array(
+ 'float' => 1.23,
+ ),
+ '1.23',
+ ),
+ array(
+ '{array}',
+ array(
+ 'array' => array( 1, 2, 3 ),
+ ),
+ '[Array(3)]',
+ ),
+ array(
+ '{exception}',
+ array(
+ 'exception' => $e,
+ ),
+ '[Exception ' . get_class( $e ) . '( ' .
+ $e->getFile() . ':' . $e->getLine() . ') ' .
+ $e->getMessage() . ']',
+ ),
+ array(
+ '{datetime}',
+ array(
+ 'datetime' => $d,
+ ),
+ $d->format( 'c' ),
+ ),
+ array(
+ '{object}',
+ array(
+ 'object' => new \stdClass,
+ ),
+ '[Object stdClass]',
+ ),
+ );
+ }
+
+ /**
+ * @covers LegacyLogger::shouldEmit
+ * @dataProvider provideShouldEmit
+ */
+ public function testShouldEmit( $level, $config, $expected ) {
+ $this->setMwGlobals( 'wgDebugLogGroups', array( 'fakechannel' => $config ) );
+ $this->assertEquals(
+ $expected,
+ LegacyLogger::shouldEmit( 'fakechannel', 'some message', $level, array() )
+ );
+ }
+
+ public static function provideShouldEmit() {
+ $dest = array( 'destination' => 'foobar' );
+ $tests = array(
+ array(
+ LogLevel::DEBUG,
+ $dest,
+ true
+ ),
+ array(
+ LogLevel::WARNING,
+ $dest + array( 'level' => LogLevel::INFO ),
+ true,
+ ),
+ array(
+ LogLevel::INFO,
+ $dest + array( 'level' => LogLevel::CRITICAL ),
+ false,
+ ),
+ );
+
+ if ( class_exists( '\Monolog\Logger' ) ) {
+ $tests[] = array(
+ \Monolog\Logger::INFO,
+ $dest + array( 'level' => LogLevel::INFO ),
+ true,
+ );
+ $tests[] = array(
+ \Monolog\Logger::WARNING,
+ $dest + array( 'level' => LogLevel::EMERGENCY ),
+ false,
+ );
+ }
+
+ return $tests;
+ }
+
+}
diff --git a/tests/phpunit/includes/debug/logger/MonologSpiTest.php b/tests/phpunit/includes/debug/logger/MonologSpiTest.php
new file mode 100644
index 00000000..aa0a54ff
--- /dev/null
+++ b/tests/phpunit/includes/debug/logger/MonologSpiTest.php
@@ -0,0 +1,136 @@
+ array(
+ '@default' => array(
+ 'processors' => array( 'constructor' ),
+ 'handlers' => array( 'constructor' ),
+ ),
+ ),
+ 'processors' => array(
+ 'constructor' => array(
+ 'class' => 'constructor',
+ ),
+ ),
+ 'handlers' => array(
+ 'constructor' => array(
+ 'class' => 'constructor',
+ 'formatter' => 'constructor',
+ ),
+ ),
+ 'formatters' => array(
+ 'constructor' => array(
+ 'class' => 'constructor',
+ ),
+ ),
+ );
+
+ $fixture = new MonologSpi( $base );
+ $this->assertSame(
+ $base,
+ TestingAccessWrapper::newFromObject( $fixture )->config
+ );
+
+ $fixture->mergeConfig( array(
+ 'loggers' => array(
+ 'merged' => array(
+ 'processors' => array( 'merged' ),
+ 'handlers' => array( 'merged' ),
+ ),
+ ),
+ 'processors' => array(
+ 'merged' => array(
+ 'class' => 'merged',
+ ),
+ ),
+ 'magic' => array(
+ 'idkfa' => array( 'xyzzy' ),
+ ),
+ 'handlers' => array(
+ 'merged' => array(
+ 'class' => 'merged',
+ 'formatter' => 'merged',
+ ),
+ ),
+ 'formatters' => array(
+ 'merged' => array(
+ 'class' => 'merged',
+ ),
+ ),
+ ) );
+ $this->assertSame(
+ array(
+ 'loggers' => array(
+ '@default' => array(
+ 'processors' => array( 'constructor' ),
+ 'handlers' => array( 'constructor' ),
+ ),
+ 'merged' => array(
+ 'processors' => array( 'merged' ),
+ 'handlers' => array( 'merged' ),
+ ),
+ ),
+ 'processors' => array(
+ 'constructor' => array(
+ 'class' => 'constructor',
+ ),
+ 'merged' => array(
+ 'class' => 'merged',
+ ),
+ ),
+ 'handlers' => array(
+ 'constructor' => array(
+ 'class' => 'constructor',
+ 'formatter' => 'constructor',
+ ),
+ 'merged' => array(
+ 'class' => 'merged',
+ 'formatter' => 'merged',
+ ),
+ ),
+ 'formatters' => array(
+ 'constructor' => array(
+ 'class' => 'constructor',
+ ),
+ 'merged' => array(
+ 'class' => 'merged',
+ ),
+ ),
+ 'magic' => array(
+ 'idkfa' => array( 'xyzzy' ),
+ ),
+ ),
+ TestingAccessWrapper::newFromObject( $fixture )->config
+ );
+ }
+
+}
diff --git a/tests/phpunit/includes/debug/logger/monolog/AvroFormatterTest.php b/tests/phpunit/includes/debug/logger/monolog/AvroFormatterTest.php
new file mode 100644
index 00000000..44242ed2
--- /dev/null
+++ b/tests/phpunit/includes/debug/logger/monolog/AvroFormatterTest.php
@@ -0,0 +1,64 @@
+markTestSkipped( 'Avro is required for the AvroFormatterTest' );
+ }
+ parent::setUp();
+ }
+
+ public function testSchemaNotAvailable() {
+ $formatter = new AvroFormatter( array() );
+ $this->setExpectedException( 'PHPUnit_Framework_Error_Notice', "The schema for channel 'marty' is not available" );
+ $formatter->format( array( 'channel' => 'marty' ) );
+ }
+
+ public function testSchemaNotAvailableReturnValue() {
+ $formatter = new AvroFormatter( array() );
+ $noticeEnabled = PHPUnit_Framework_Error_Notice::$enabled;
+ // disable conversion of notices
+ PHPUnit_Framework_Error_Notice::$enabled = false;
+ // have to keep the user notice from being output
+ wfSuppressWarnings();
+ $res = $formatter->format( array( 'channel' => 'marty' ) );
+ wfRestoreWarnings();
+ PHPUnit_Framework_Error_Notice::$enabled = $noticeEnabled;
+ $this->assertNull( $res );
+ }
+
+ public function testDoesSomethingWhenSchemaAvailable() {
+ $formatter = new AvroFormatter( array( 'string' => array( 'type' => 'string' ) ) );
+ $res = $formatter->format( array(
+ 'channel' => 'string',
+ 'context' => 'better to be',
+ ) );
+ $this->assertNotNull( $res );
+ // basically just tell us if avro changes its string encoding
+ $this->assertEquals( base64_decode( 'GGJldHRlciB0byBiZQ==' ), $res );
+ }
+}
diff --git a/tests/phpunit/includes/debug/logger/monolog/KafkaHandlerTest.php b/tests/phpunit/includes/debug/logger/monolog/KafkaHandlerTest.php
new file mode 100644
index 00000000..090f439e
--- /dev/null
+++ b/tests/phpunit/includes/debug/logger/monolog/KafkaHandlerTest.php
@@ -0,0 +1,207 @@
+markTestSkipped( 'Monolog and Kafka are required for the KafkaHandlerTest' );
+ }
+
+ parent::setUp();
+ }
+
+ public function topicNamingProvider() {
+ return array(
+ array( array(), 'monolog_foo' ),
+ array( array( 'alias' => array( 'foo' => 'bar' ) ), 'bar' )
+ );
+ }
+
+ /**
+ * @dataProvider topicNamingProvider
+ */
+ public function testTopicNaming( $options, $expect ) {
+ $produce = $this->getMockBuilder( 'Kafka\Produce' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $produce->expects($this->any())
+ ->method('getAvailablePartitions')
+ ->will($this->returnValue( array( 'A' ) ) );
+ $produce->expects($this->once())
+ ->method( 'setMessages' )
+ ->with( $expect, $this->anything(), $this->anything() );
+
+ $handler = new KafkaHandler( $produce, $options );
+ $handler->handle( array(
+ 'channel' => 'foo',
+ 'level' => Logger::EMERGENCY,
+ 'extra' => array(),
+ ) );
+ }
+
+ public function swallowsExceptionsWhenRequested() {
+ return array(
+ // defaults to false
+ array( array(), true ),
+ // also try false explicitly
+ array( array( 'swallowExceptions' => false ), true ),
+ // turn it on
+ array( array( 'swallowExceptions' => true ), false ),
+ );
+ }
+
+ /**
+ * @dataProvider swallowsExceptionsWhenRequested
+ */
+ public function testGetAvailablePartitionsException( $options, $expectException ) {
+ $produce = $this->getMockBuilder( 'Kafka\Produce' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $produce->expects( $this->any() )
+ ->method( 'getAvailablePartitions' )
+ ->will( $this->throwException( new \Kafka\Exception ) );
+
+ if ( $expectException ) {
+ $this->setExpectedException( 'Kafka\Exception' );
+ }
+
+ $handler = new KafkaHandler( $produce, $options );
+ $handler->handle( array(
+ 'channel' => 'foo',
+ 'level' => Logger::EMERGENCY,
+ 'extra' => array(),
+ ) );
+
+ if ( !$expectException ) {
+ $this->assertTrue( true, 'no exception was thrown' );
+ }
+ }
+
+ /**
+ * @dataProvider swallowsExceptionsWhenRequested
+ */
+ public function testSendException( $options, $expectException ) {
+ $produce = $this->getMockBuilder( 'Kafka\Produce' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $produce->expects( $this->any() )
+ ->method( 'getAvailablePartitions' )
+ ->will( $this->returnValue( array( 'A' ) ) );
+ $produce->expects( $this->any() )
+ ->method( 'send' )
+ ->will( $this->throwException( new \Kafka\Exception ) );
+
+ if ( $expectException ) {
+ $this->setExpectedException( 'Kafka\Exception' );
+ }
+
+ $handler = new KafkaHandler( $produce, $options );
+ $handler->handle( array(
+ 'channel' => 'foo',
+ 'level' => Logger::EMERGENCY,
+ 'extra' => array(),
+ ) );
+
+ if ( !$expectException ) {
+ $this->assertTrue( true, 'no exception was thrown' );
+ }
+ }
+
+ public function testHandlesNullFormatterResult() {
+ $produce = $this->getMockBuilder( 'Kafka\Produce' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $produce->expects( $this->any() )
+ ->method( 'getAvailablePartitions' )
+ ->will( $this->returnValue( array( 'A' ) ) );
+ $mockMethod = $produce->expects( $this->exactly( 2 ) )
+ ->method( 'setMessages' );
+ // evil hax
+ \TestingAccessWrapper::newFromObject( $mockMethod )->matcher->parametersMatcher =
+ new \PHPUnit_Framework_MockObject_Matcher_ConsecutiveParameters( array(
+ array( $this->anything(), $this->anything(), array( 'words' ) ),
+ array( $this->anything(), $this->anything(), array( 'lines' ) )
+ ) );
+
+ $formatter = $this->getMock( 'Monolog\Formatter\FormatterInterface' );
+ $formatter->expects( $this->any() )
+ ->method( 'format' )
+ ->will( $this->onConsecutiveCalls( 'words', null, 'lines' ) );
+
+ $handler = new KafkaHandler( $produce, array() );
+ $handler->setFormatter( $formatter );
+ for ( $i = 0; $i < 3; ++$i ) {
+ $handler->handle( array(
+ 'channel' => 'foo',
+ 'level' => Logger::EMERGENCY,
+ 'extra' => array(),
+ ) );
+ }
+ }
+
+
+ public function testBatchHandlesNullFormatterResult() {
+ $produce = $this->getMockBuilder( 'Kafka\Produce' )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $produce->expects( $this->any() )
+ ->method( 'getAvailablePartitions' )
+ ->will( $this->returnValue( array( 'A' ) ) );
+ $produce->expects( $this->once() )
+ ->method( 'setMessages' )
+ ->with( $this->anything(), $this->anything(), array( 'words', 'lines' ) );
+
+ $formatter = $this->getMock( 'Monolog\Formatter\FormatterInterface' );
+ $formatter->expects( $this->any() )
+ ->method( 'format' )
+ ->will( $this->onConsecutiveCalls( 'words', null, 'lines' ) );
+
+ $handler = new KafkaHandler( $produce, array() );
+ $handler->setFormatter( $formatter );
+ $handler->handleBatch( array(
+ array(
+ 'channel' => 'foo',
+ 'level' => Logger::EMERGENCY,
+ 'extra' => array(),
+ ),
+ array(
+ 'channel' => 'foo',
+ 'level' => Logger::EMERGENCY,
+ 'extra' => array(),
+ ),
+ array(
+ 'channel' => 'foo',
+ 'level' => Logger::EMERGENCY,
+ 'extra' => array(),
+ ),
+ ) );
+ }
+}
diff --git a/tests/phpunit/includes/debug/logger/monolog/LineFormatterTest.php b/tests/phpunit/includes/debug/logger/monolog/LineFormatterTest.php
new file mode 100644
index 00000000..be23c4a2
--- /dev/null
+++ b/tests/phpunit/includes/debug/logger/monolog/LineFormatterTest.php
@@ -0,0 +1,75 @@
+markTestSkipped( 'This test requires monolog to be installed' );
+ }
+ parent::setUp();
+ }
+
+ /**
+ * @covers LineFormatter::normalizeException
+ */
+ public function testNormalizeExceptionNoTrace() {
+ $fixture = new LineFormatter();
+ $fixture->includeStacktraces( false );
+ $fixture = TestingAccessWrapper::newFromObject( $fixture );
+ $boom = new InvalidArgumentException( 'boom', 0,
+ new LengthException( 'too long', 0,
+ new LogicException( 'Spock wuz here' )
+ )
+ );
+ $out = $fixture->normalizeException( $boom );
+ $this->assertContains( "\n[Exception InvalidArgumentException]", $out );
+ $this->assertContains( "\nCaused by: [Exception LengthException]", $out );
+ $this->assertContains( "\nCaused by: [Exception LogicException]", $out );
+ $this->assertNotContains( "\n #0", $out );
+ }
+
+ /**
+ * @covers LineFormatter::normalizeException
+ */
+ public function testNormalizeExceptionTrace() {
+ $fixture = new LineFormatter();
+ $fixture->includeStacktraces( true );
+ $fixture = TestingAccessWrapper::newFromObject( $fixture );
+ $boom = new InvalidArgumentException( 'boom', 0,
+ new LengthException( 'too long', 0,
+ new LogicException( 'Spock wuz here' )
+ )
+ );
+ $out = $fixture->normalizeException( $boom );
+ $this->assertContains( "\n[Exception InvalidArgumentException]", $out );
+ $this->assertContains( "\nCaused by: [Exception LengthException]", $out );
+ $this->assertContains( "\nCaused by: [Exception LogicException]", $out );
+ $this->assertContains( "\n #0", $out );
+ }
+}
diff --git a/tests/phpunit/includes/debug/logging/LegacyLoggerTest.php b/tests/phpunit/includes/debug/logging/LegacyLoggerTest.php
deleted file mode 100644
index 415fa045..00000000
--- a/tests/phpunit/includes/debug/logging/LegacyLoggerTest.php
+++ /dev/null
@@ -1,122 +0,0 @@
-assertEquals(
- $expect, LegacyLogger::interpolate( $message, $context ) );
- }
-
- public function provideInterpolate() {
- return array(
- array(
- 'no-op',
- array(),
- 'no-op',
- ),
- array(
- 'Hello {world}!',
- array(
- 'world' => 'World',
- ),
- 'Hello World!',
- ),
- array(
- '{greeting} {user}',
- array(
- 'greeting' => 'Goodnight',
- 'user' => 'Moon',
- ),
- 'Goodnight Moon',
- ),
- array(
- 'Oops {key_not_set}',
- array(),
- 'Oops {key_not_set}',
- ),
- array(
- '{ not interpolated }',
- array(
- 'not interpolated' => 'This should NOT show up in the message',
- ),
- '{ not interpolated }',
- ),
- );
- }
-
- /**
- * @covers LegacyLogger::shouldEmit
- * @dataProvider provideShouldEmit
- */
- public function testShouldEmit( $level, $config, $expected ) {
- $this->setMwGlobals( 'wgDebugLogGroups', array( 'fakechannel' => $config ) );
- $this->assertEquals(
- $expected,
- LegacyLogger::shouldEmit( 'fakechannel', 'some message', $level, array() )
- );
- }
-
- public static function provideShouldEmit() {
- $dest = array( 'destination' => 'foobar' );
- $tests = array(
- array(
- LogLevel::DEBUG,
- $dest,
- true
- ),
- array(
- LogLevel::WARNING,
- $dest + array( 'level' => LogLevel::INFO ),
- true,
- ),
- array(
- LogLevel::INFO,
- $dest + array( 'level' => LogLevel::CRITICAL ),
- false,
- ),
- );
-
- if ( class_exists( '\Monolog\Logger' ) ) {
- $tests[] = array(
- \Monolog\Logger::INFO,
- $dest + array( 'level' => LogLevel::INFO ),
- true,
- );
- $tests[] = array(
- \Monolog\Logger::WARNING,
- $dest + array( 'level' => LogLevel::EMERGENCY ),
- false,
- );
- }
-
- return $tests;
- }
-
-}
diff --git a/tests/phpunit/includes/deferred/DeferredUpdatesTest.php b/tests/phpunit/includes/deferred/DeferredUpdatesTest.php
index 5348c854..df4213ab 100644
--- a/tests/phpunit/includes/deferred/DeferredUpdatesTest.php
+++ b/tests/phpunit/includes/deferred/DeferredUpdatesTest.php
@@ -1,8 +1,9 @@
setMwGlobals( 'wgCommandLineMode', false );
- public function testDoUpdates() {
$updates = array(
'1' => 'deferred update 1',
'2' => 'deferred update 2',
@@ -35,4 +36,38 @@ class DeferredUpdatesTest extends MediaWikiTestCase {
DeferredUpdates::doUpdates();
}
+ public function testDoUpdatesCLI() {
+ $this->setMwGlobals( 'wgCommandLineMode', true );
+
+ $updates = array(
+ '1' => 'deferred update 1',
+ '2' => 'deferred update 2',
+ '2-1' => 'deferred update 1 within deferred update 2',
+ '3' => 'deferred update 3',
+ );
+ DeferredUpdates::addCallableUpdate(
+ function () use ( $updates ) {
+ echo $updates['1'];
+ }
+ );
+ DeferredUpdates::addCallableUpdate(
+ function () use ( $updates ) {
+ echo $updates['2'];
+ DeferredUpdates::addCallableUpdate(
+ function () use ( $updates ) {
+ echo $updates['2-1'];
+ }
+ );
+ }
+ );
+ DeferredUpdates::addCallableUpdate(
+ function () use ( $updates ) {
+ echo $updates[3];
+ }
+ );
+
+ $this->expectOutputString( implode( '', $updates ) );
+
+ DeferredUpdates::doUpdates();
+ }
}
diff --git a/tests/phpunit/includes/diff/ArrayDiffFormatterTest.php b/tests/phpunit/includes/diff/ArrayDiffFormatterTest.php
index 3bea9b31..a546bec1 100644
--- a/tests/phpunit/includes/diff/ArrayDiffFormatterTest.php
+++ b/tests/phpunit/includes/diff/ArrayDiffFormatterTest.php
@@ -69,11 +69,11 @@ class ArrayDiffFormatterTest extends MediaWikiTestCase {
$otherTestCases = array();
$otherTestCases[] = array(
- $this->getMockDiff( array( $this->getMockDiffOp( 'add', array( ), array( 'a1' ) ) ) ),
+ $this->getMockDiff( array( $this->getMockDiffOp( 'add', array(), array( 'a1' ) ) ) ),
array( array( 'action' => 'add', 'new' => 'a1', 'newline' => 1 ) ),
);
$otherTestCases[] = array(
- $this->getMockDiff( array( $this->getMockDiffOp( 'add', array( ), array( 'a1', 'a2' ) ) ) ),
+ $this->getMockDiff( array( $this->getMockDiffOp( 'add', array(), array( 'a1', 'a2' ) ) ) ),
array(
array( 'action' => 'add', 'new' => 'a1', 'newline' => 1 ),
array( 'action' => 'add', 'new' => 'a2', 'newline' => 2 ),
diff --git a/tests/phpunit/includes/exception/HttpErrorTest.php b/tests/phpunit/includes/exception/HttpErrorTest.php
new file mode 100644
index 00000000..66fe90c9
--- /dev/null
+++ b/tests/phpunit/includes/exception/HttpErrorTest.php
@@ -0,0 +1,65 @@
+assertFalse( $httpError->isLoggable(), 'http error is not loggable' );
+ }
+
+ public function testGetStatusCode() {
+ $httpError = new HttpError( 500, 'server error!' );
+ $this->assertEquals( 500, $httpError->getStatusCode() );
+ }
+
+ /**
+ * @dataProvider getHtmlProvider
+ */
+ public function testGetHtml( array $expected, $content, $header ) {
+ $httpError = new HttpError( 500, $content, $header );
+ $errorHtml = $httpError->getHtml();
+
+ foreach ( $expected as $key => $html ) {
+ $this->assertContains( $html, $errorHtml, $key );
+ }
+ }
+
+ public function getHtmlProvider() {
+ return array(
+ array(
+ array(
+ 'head html' => 'Server Error 123 ',
+ 'body html' => 'Server Error 123 '
+ . 'a server error!
'
+ ),
+ 'a server error!',
+ 'Server Error 123'
+ ),
+ array(
+ array(
+ 'head html' => 'loginerror ',
+ 'body html' => 'loginerror '
+ . 'suspicious-userlogout
'
+ ),
+ new RawMessage( 'suspicious-userlogout' ),
+ new RawMessage( 'loginerror' )
+ ),
+ array(
+ array(
+ 'head html' => 'Internal Server Error ',
+ 'body html' => 'Internal Server Error '
+ . 'a server error!
'
+ ),
+ 'a server error!',
+ null
+ )
+ );
+ }
+
+
+}
diff --git a/tests/phpunit/includes/exception/MWExceptionTest.php b/tests/phpunit/includes/exception/MWExceptionTest.php
index ef0f2a9e..f11fda32 100644
--- a/tests/phpunit/includes/exception/MWExceptionTest.php
+++ b/tests/phpunit/includes/exception/MWExceptionTest.php
@@ -178,7 +178,7 @@ class MWExceptionTest extends MediaWikiTestCase {
$this->setMwGlobals( array( 'wgLogExceptionBacktrace' => true ) );
$json = json_decode(
- MWExceptionHandler::jsonSerializeException( new $exClass())
+ MWExceptionHandler::jsonSerializeException( new $exClass() )
);
$this->assertObjectHasAttribute( $key, $json,
"JSON serialized exception is missing key '$key'"
diff --git a/tests/phpunit/includes/filebackend/FileBackendTest.php b/tests/phpunit/includes/filebackend/FileBackendTest.php
index bfca75ad..2e4942f0 100644
--- a/tests/phpunit/includes/filebackend/FileBackendTest.php
+++ b/tests/phpunit/includes/filebackend/FileBackendTest.php
@@ -2376,7 +2376,7 @@ class FileBackendTest extends MediaWikiTestCase {
$status = Status::newGood();
$sl = $this->backend->getScopedFileLocks( $paths, LockManager::LOCK_EX, $status );
- $this->assertType( 'ScopedLock', $sl,
+ $this->assertInstanceOf( 'ScopedLock', $sl,
"Scoped locking of files succeeded ($backendName)." );
$this->assertEquals( array(), $status->errors,
"Scoped locking of files succeeded ($backendName)." );
@@ -2392,6 +2392,56 @@ class FileBackendTest extends MediaWikiTestCase {
"Scoped unlocking of files succeeded with OK status ($backendName)." );
}
+ public function testReadAffinity() {
+ $be = TestingAccessWrapper::newFromObject(
+ new FileBackendMultiWrite( array(
+ 'name' => 'localtesting',
+ 'wikiId' => wfWikiId() . mt_rand(),
+ 'backends' => array(
+ array( // backend 0
+ 'name' => 'multitesting0',
+ 'class' => 'MemoryFileBackend',
+ 'isMultiMaster' => false,
+ 'readAffinity' => true
+ ),
+ array( // backend 1
+ 'name' => 'multitesting1',
+ 'class' => 'MemoryFileBackend',
+ 'isMultiMaster' => true
+ )
+ )
+ ) )
+ );
+
+ $this->assertEquals(
+ 1,
+ $be->getReadIndexFromParams( array( 'latest' => 1 ) ),
+ 'Reads with "latest" flag use backend 1'
+ );
+ $this->assertEquals(
+ 0,
+ $be->getReadIndexFromParams( array( 'latest' => 0 ) ),
+ 'Reads without "latest" flag use backend 0'
+ );
+
+ $p = 'container/test-cont/file.txt';
+ $be->backends[0]->quickCreate( array(
+ 'dst' => "mwstore://multitesting0/$p", 'content' => 'cattitude' ) );
+ $be->backends[1]->quickCreate( array(
+ 'dst' => "mwstore://multitesting1/$p", 'content' => 'princess of power' ) );
+
+ $this->assertEquals(
+ 'cattitude',
+ $be->getFileContents( array( 'src' => "mwstore://localtesting/$p" ) ),
+ "Non-latest read came from backend 0"
+ );
+ $this->assertEquals(
+ 'princess of power',
+ $be->getFileContents( array( 'src' => "mwstore://localtesting/$p", 'latest' => 1 ) ),
+ "Latest read came from backend1"
+ );
+ }
+
// helper function
private function listToArray( $iter ) {
return is_array( $iter ) ? $iter : iterator_to_array( $iter );
diff --git a/tests/phpunit/includes/filebackend/SwiftFileBackendTest.php b/tests/phpunit/includes/filebackend/SwiftFileBackendTest.php
new file mode 100644
index 00000000..a618889c
--- /dev/null
+++ b/tests/phpunit/includes/filebackend/SwiftFileBackendTest.php
@@ -0,0 +1,148 @@
+backend = TestingAccessWrapper::newFromObject(
+ new SwiftFileBackend( array(
+ 'name' => 'local-swift-testing',
+ 'class' => 'SwiftFileBackend',
+ 'wikiId' => 'unit-testing',
+ 'lockManager' => LockManagerGroup::singleton()->get( 'fsLockManager' ),
+ 'swiftAuthUrl' => 'http://127.0.0.1:8080/auth', // unused
+ 'swiftUser' => 'test:tester',
+ 'swiftKey' => 'testing',
+ 'swiftTempUrlKey' => 'b3968d0207b54ece87cccc06515a89d4' // unused
+ ) )
+ );
+ }
+
+ /**
+ * @dataProvider provider_testSanitzeHdrs
+ * @covers SwiftFileBackend::sanitzeHdrs
+ * @covers SwiftFileBackend::getCustomHeaders
+ */
+ public function testSanitzeHdrs( $raw, $sanitized ) {
+ $hdrs = $this->backend->sanitizeHdrs( array( 'headers' => $raw ) );
+
+ $this->assertEquals( $hdrs, $sanitized, 'sanitizeHdrs() has expected result' );
+ }
+
+ public static function provider_testSanitzeHdrs() {
+ return array(
+ array(
+ array(
+ 'content-length' => 345,
+ 'content-type' => 'image+bitmap/jpeg',
+ 'content-disposition' => 'inline',
+ 'content-duration' => 35.6363,
+ 'content-Custom' => 'hello',
+ 'x-content-custom' => 'hello'
+ ),
+ array(
+ 'content-disposition' => 'inline',
+ 'content-duration' => 35.6363,
+ 'content-custom' => 'hello',
+ 'x-content-custom' => 'hello'
+ )
+ ),
+ array(
+ array(
+ 'content-length' => 345,
+ 'content-type' => 'image+bitmap/jpeg',
+ 'content-Disposition' => 'inline; filename=xxx; ' . str_repeat( 'o', 1024 ),
+ 'content-duration' => 35.6363,
+ 'content-custom' => 'hello',
+ 'x-content-custom' => 'hello'
+ ),
+ array(
+ 'content-disposition' => 'inline;filename=xxx',
+ 'content-duration' => 35.6363,
+ 'content-custom' => 'hello',
+ 'x-content-custom' => 'hello'
+ )
+ ),
+ array(
+ array(
+ 'content-length' => 345,
+ 'content-type' => 'image+bitmap/jpeg',
+ 'content-disposition' => 'filename='. str_repeat( 'o', 1024 ) . ';inline',
+ 'content-duration' => 35.6363,
+ 'content-custom' => 'hello',
+ 'x-content-custom' => 'hello'
+ ),
+ array(
+ 'content-disposition' => '',
+ 'content-duration' => 35.6363,
+ 'content-custom' => 'hello',
+ 'x-content-custom' => 'hello'
+ )
+ )
+ );
+ }
+
+ /**
+ * @dataProvider provider_testGetMetadataHeaders
+ * @covers SwiftFileBackend::getMetadataHeaders
+ */
+ public function testGetMetadataHeaders( $raw, $sanitized ) {
+ $hdrs = $this->backend->getMetadataHeaders( $raw );
+
+ $this->assertEquals( $hdrs, $sanitized, 'getMetadataHeaders() has expected result' );
+ }
+
+ public static function provider_testGetMetadataHeaders() {
+ return array(
+ array(
+ array(
+ 'content-length' => 345,
+ 'content-custom' => 'hello',
+ 'x-content-custom' => 'hello',
+ 'x-object-meta-custom' => 5,
+ 'x-object-meta-sha1Base36' => 'a3deadfg...',
+ ),
+ array(
+ 'x-object-meta-custom' => 5,
+ 'x-object-meta-sha1base36' => 'a3deadfg...',
+ )
+ )
+ );
+ }
+
+ /**
+ * @dataProvider provider_testGetMetadata
+ * @covers SwiftFileBackend::getMetadata
+ */
+ public function testGetMetadata( $raw, $sanitized ) {
+ $hdrs = $this->backend->getMetadata( $raw );
+
+ $this->assertEquals( $hdrs, $sanitized, 'getMetadata() has expected result' );
+ }
+
+ public static function provider_testGetMetadata() {
+ return array(
+ array(
+ array(
+ 'content-length' => 345,
+ 'content-custom' => 'hello',
+ 'x-content-custom' => 'hello',
+ 'x-object-meta-custom' => 5,
+ 'x-object-meta-sha1Base36' => 'a3deadfg...',
+ ),
+ array(
+ 'custom' => 5,
+ 'sha1base36' => 'a3deadfg...',
+ )
+ )
+ );
+ }
+}
\ No newline at end of file
diff --git a/tests/phpunit/includes/filerepo/FileBackendDBRepoWrapperTest.php b/tests/phpunit/includes/filerepo/FileBackendDBRepoWrapperTest.php
new file mode 100644
index 00000000..681e3681
--- /dev/null
+++ b/tests/phpunit/includes/filerepo/FileBackendDBRepoWrapperTest.php
@@ -0,0 +1,138 @@
+expects( $dbReadsExpected )
+ ->method( 'selectField' )
+ ->will( $this->returnValue( $dbReturnValue ) );
+
+ $newPaths = $wrapperMock->getBackendPaths( array( $originalPath ), $latest );
+
+ $this->assertEquals(
+ $expectedBackendPath,
+ $newPaths[0],
+ $message );
+ }
+
+ public function getBackendPathsProvider() {
+ $prefix = 'mwstore://' . $this->backendName . '/' . $this->repoName;
+ $mocksForCaching = $this->getMocks();
+
+ return array(
+ array(
+ $mocksForCaching,
+ false,
+ $this->once(),
+ '96246614d75ba1703bdfd5d7660bb57407aaf5d9',
+ $prefix . '-public/f/o/foobar.jpg',
+ $prefix . '-original/9/6/2/96246614d75ba1703bdfd5d7660bb57407aaf5d9',
+ 'Public path translated correctly',
+ ),
+ array(
+ $mocksForCaching,
+ false,
+ $this->never(),
+ '96246614d75ba1703bdfd5d7660bb57407aaf5d9',
+ $prefix . '-public/f/o/foobar.jpg',
+ $prefix . '-original/9/6/2/96246614d75ba1703bdfd5d7660bb57407aaf5d9',
+ 'LRU cache leveraged',
+ ),
+ array(
+ $this->getMocks(),
+ true,
+ $this->once(),
+ '96246614d75ba1703bdfd5d7660bb57407aaf5d9',
+ $prefix . '-public/f/o/foobar.jpg',
+ $prefix . '-original/9/6/2/96246614d75ba1703bdfd5d7660bb57407aaf5d9',
+ 'Latest obtained',
+ ),
+ array(
+ $this->getMocks(),
+ true,
+ $this->never(),
+ '96246614d75ba1703bdfd5d7660bb57407aaf5d9',
+ $prefix . '-deleted/f/o/foobar.jpg',
+ $prefix . '-original/f/o/o/foobar',
+ 'Deleted path translated correctly',
+ ),
+ array(
+ $this->getMocks(),
+ true,
+ $this->once(),
+ null,
+ $prefix . '-public/b/a/baz.jpg',
+ $prefix . '-public/b/a/baz.jpg',
+ 'Path left untouched if no sha1 can be found',
+ ),
+ );
+ }
+
+ /**
+ * @covers FileBackendDBRepoWrapper::getFileContentsMulti
+ */
+ public function testGetFileContentsMulti() {
+ list( $dbMock, $backendMock, $wrapperMock ) = $this->getMocks();
+
+ $sha1Path = 'mwstore://' . $this->backendName . '/' . $this->repoName
+ . '-original/9/6/2/96246614d75ba1703bdfd5d7660bb57407aaf5d9';
+ $filenamePath = 'mwstore://' . $this->backendName . '/' . $this->repoName
+ . '-public/f/o/foobar.jpg';
+
+ $dbMock->expects( $this->once() )
+ ->method( 'selectField' )
+ ->will( $this->returnValue( '96246614d75ba1703bdfd5d7660bb57407aaf5d9' ) );
+
+ $backendMock->expects( $this->once() )
+ ->method( 'getFileContentsMulti')
+ ->will( $this->returnValue( array( $sha1Path => 'foo' ) ) );
+
+ $result = $wrapperMock->getFileContentsMulti( array( 'srcs' => array( $filenamePath ) ) );
+
+ $this->assertEquals(
+ array( $filenamePath => 'foo' ),
+ $result,
+ 'File contents paths translated properly'
+ );
+ }
+
+ protected function getMocks() {
+ $dbMock = $this->getMockBuilder( 'DatabaseMysql' )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $backendMock = $this->getMock( 'FSFileBackend',
+ array(),
+ array( array(
+ 'name' => $this->backendName,
+ 'wikiId' => wfWikiId()
+ ) ) );
+
+ $wrapperMock = $this->getMock( 'FileBackendDBRepoWrapper',
+ array( 'getDB' ),
+ array( array(
+ 'backend' => $backendMock,
+ 'repoName' => $this->repoName,
+ 'dbHandleFactory' => null
+ ) ) );
+
+ $wrapperMock->expects( $this->any() )->method( 'getDB' )->will( $this->returnValue( $dbMock ) );
+
+ return array( $dbMock, $backendMock, $wrapperMock );
+ }
+}
diff --git a/tests/phpunit/includes/filerepo/MigrateFileRepoLayoutTest.php b/tests/phpunit/includes/filerepo/MigrateFileRepoLayoutTest.php
new file mode 100644
index 00000000..551d3a76
--- /dev/null
+++ b/tests/phpunit/includes/filerepo/MigrateFileRepoLayoutTest.php
@@ -0,0 +1,114 @@
+tmpPrefix = wfTempDir() . '/migratefilelayout-test-' . time() . '-' . mt_rand();
+
+ $backend = new FSFileBackend( array(
+ 'name' => 'local-migratefilerepolayouttest',
+ 'wikiId' => wfWikiID(),
+ 'containerPaths' => array(
+ 'migratefilerepolayouttest-original' => "{$this->tmpPrefix}-original",
+ 'migratefilerepolayouttest-public' => "{$this->tmpPrefix}-public",
+ 'migratefilerepolayouttest-thumb' => "{$this->tmpPrefix}-thumb",
+ 'migratefilerepolayouttest-temp' => "{$this->tmpPrefix}-temp",
+ 'migratefilerepolayouttest-deleted' => "{$this->tmpPrefix}-deleted",
+ )
+ ) );
+
+ $dbMock = $this->getMockBuilder( 'DatabaseMysql' )
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $imageRow = new stdClass;
+ $imageRow->img_name = $filename;
+ $imageRow->img_sha1 = sha1( $this->text );
+
+ $dbMock->expects( $this->any() )
+ ->method( 'select' )
+ ->will( $this->onConsecutiveCalls(
+ new FakeResultWrapper( array( $imageRow ) ), // image
+ new FakeResultWrapper( array() ), // image
+ new FakeResultWrapper( array() ) // filearchive
+ ) );
+
+ $repoMock = $this->getMock( 'LocalRepo',
+ array( 'getMasterDB' ),
+ array( array(
+ 'name' => 'migratefilerepolayouttest',
+ 'backend' => $backend
+ ) ) );
+
+ $repoMock->expects( $this->any() )->method( 'getMasterDB' )->will( $this->returnValue( $dbMock ) );
+
+ $this->migratorMock = $this->getMock( 'MigrateFileRepoLayout', array( 'getRepo' ) );
+ $this->migratorMock->expects( $this->any() )->method( 'getRepo' )->will( $this->returnValue( $repoMock ) );
+
+ $this->tmpFilepath = TempFSFile::factory( 'migratefilelayout-test-', 'png' )->getPath();
+
+ file_put_contents( $this->tmpFilepath, $this->text );
+
+ $hashPath = $repoMock->getHashPath( $filename );
+
+ $status = $repoMock->store( $this->tmpFilepath, 'public', $hashPath . $filename, FileRepo::OVERWRITE );
+ }
+
+ protected function deleteFilesRecursively( $directory ) {
+ foreach ( glob( $directory . '/*' ) as $file ) {
+ if ( is_dir( $file ) ) {
+ $this->deleteFilesRecursively( $file );
+ } else {
+ unlink( $file );
+ }
+ }
+
+ rmdir( $directory );
+ }
+
+ protected function tearDown() {
+ foreach ( glob( $this->tmpPrefix . '*' ) as $directory ) {
+ $this->deleteFilesRecursively( $directory );
+ }
+
+ unlink( $this->tmpFilepath );
+
+ parent::tearDown();
+ }
+
+ public function testMigration() {
+ $this->migratorMock->loadParamsAndArgs( null, array( 'oldlayout' => 'name', 'newlayout' => 'sha1' ) );
+
+ ob_start();
+
+ $this->migratorMock->execute();
+
+ ob_end_clean();
+
+ $sha1 = sha1( $this->text );
+
+ $expectedOriginalFilepath = $this->tmpPrefix
+ . '-original/'
+ . substr( $sha1, 0, 1 )
+ . '/'
+ . substr( $sha1, 1, 1 )
+ . '/'
+ . substr( $sha1, 2, 1 )
+ . '/'
+ . $sha1 ;
+
+ $this->assertEquals( file_get_contents( $expectedOriginalFilepath ), $this->text, 'New sha1 file should be exist and have the right contents' );
+
+ $expectedPublicFilepath = $this->tmpPrefix . '-public/f/f8/Foo.png';
+
+ $this->assertEquals( file_get_contents( $expectedPublicFilepath ), $this->text, 'Existing name file should still and have the right contents' );
+ }
+}
diff --git a/tests/phpunit/includes/htmlform/HTMLAutoCompleteSelectFieldTest.php b/tests/phpunit/includes/htmlform/HTMLAutoCompleteSelectFieldTest.php
index 2c7f50c9..3b5347cd 100644
--- a/tests/phpunit/includes/htmlform/HTMLAutoCompleteSelectFieldTest.php
+++ b/tests/phpunit/includes/htmlform/HTMLAutoCompleteSelectFieldTest.php
@@ -6,7 +6,7 @@
*/
class HtmlAutoCompleteSelectFieldTest extends MediaWikiTestCase {
- var $options = array(
+ public $options = array(
'Bulgaria' => 'BGR',
'Burkina Faso' => 'BFA',
'Burundi' => 'BDI',
diff --git a/tests/phpunit/includes/json/FormatJsonTest.php b/tests/phpunit/includes/json/FormatJsonTest.php
index f0ac6acc..8bca3331 100644
--- a/tests/phpunit/includes/json/FormatJsonTest.php
+++ b/tests/phpunit/includes/json/FormatJsonTest.php
@@ -159,12 +159,12 @@ class FormatJsonTest extends MediaWikiTestCase {
$this->assertJson( $json );
$st = FormatJson::parse( $json );
- $this->assertType( 'Status', $st );
+ $this->assertInstanceOf( 'Status', $st );
$this->assertTrue( $st->isGood() );
$this->assertEquals( $expected, $st->getValue() );
$st = FormatJson::parse( $json, FormatJson::FORCE_ASSOC );
- $this->assertType( 'Status', $st );
+ $this->assertInstanceOf( 'Status', $st );
$this->assertTrue( $st->isGood() );
$this->assertEquals( $value, $st->getValue() );
}
@@ -230,7 +230,7 @@ class FormatJsonTest extends MediaWikiTestCase {
}
$st = FormatJson::parse( $value, FormatJson::TRY_FIXING );
- $this->assertType( 'Status', $st );
+ $this->assertInstanceOf( 'Status', $st );
if ( $expected === false ) {
$this->assertFalse( $st->isOK(), 'Expected isOK() == false' );
} else {
@@ -256,7 +256,7 @@ class FormatJsonTest extends MediaWikiTestCase {
*/
public function testParseErrors( $value ) {
$st = FormatJson::parse( $value );
- $this->assertType( 'Status', $st );
+ $this->assertInstanceOf( 'Status', $st );
$this->assertFalse( $st->isOK() );
}
@@ -313,7 +313,7 @@ class FormatJsonTest extends MediaWikiTestCase {
*/
public function testParseStripComments( $json, $expect ) {
$st = FormatJson::parse( $json, FormatJson::STRIP_COMMENTS );
- $this->assertType( 'Status', $st );
+ $this->assertInstanceOf( 'Status', $st );
$this->assertTrue( $st->isGood() );
$this->assertEquals( $expect, $st->getValue() );
}
diff --git a/tests/phpunit/includes/libs/ArrayUtilsTest.php b/tests/phpunit/includes/libs/ArrayUtilsTest.php
index b5ea7b72..32b150c7 100644
--- a/tests/phpunit/includes/libs/ArrayUtilsTest.php
+++ b/tests/phpunit/includes/libs/ArrayUtilsTest.php
@@ -23,11 +23,11 @@ class ArrayUtilsTest extends PHPUnit_Framework_TestCase {
}
function provideFindLowerBound() {
- $self = $this;
- $indexValueCallback = function ( $size ) use ( $self ) {
- return function ( $val ) use ( $self, $size ) {
- $self->assertTrue( $val >= 0 );
- $self->assertTrue( $val < $size );
+ $that = $this;
+ $indexValueCallback = function ( $size ) use ( $that ) {
+ return function ( $val ) use ( $that, $size ) {
+ $that->assertTrue( $val >= 0 );
+ $that->assertTrue( $val < $size );
return $val;
};
};
@@ -212,7 +212,7 @@ class ArrayUtilsTest extends PHPUnit_Framework_TestCase {
array(),
array( 1 => 1 ),
array( 1 ),
- array( 1 => 1),
+ array( 1 => 1 ),
),
array(
array(),
diff --git a/tests/phpunit/includes/libs/CSSMinTest.php b/tests/phpunit/includes/libs/CSSMinTest.php
index 6142f967..7841f30f 100644
--- a/tests/phpunit/includes/libs/CSSMinTest.php
+++ b/tests/phpunit/includes/libs/CSSMinTest.php
@@ -102,12 +102,12 @@ class CSSMinTest extends MediaWikiTestCase {
array(
'Without trailing slash',
array( 'foo { prop: url(../bar.png); }', false, 'http://example.org/quux', false ),
- 'foo { prop: url(http://example.org/quux/../bar.png); }',
+ 'foo { prop: url(http://example.org/bar.png); }',
),
array(
'With trailing slash on remote (bug 27052)',
array( 'foo { prop: url(../bar.png); }', false, 'http://example.org/quux/', false ),
- 'foo { prop: url(http://example.org/quux/../bar.png); }',
+ 'foo { prop: url(http://example.org/bar.png); }',
),
array(
'Guard against stripping double slashes from query',
@@ -133,12 +133,7 @@ class CSSMinTest extends MediaWikiTestCase {
$remotePath = 'http://localhost/w/';
$realOutput = CSSMin::remap( $input, $localPath, $remotePath );
-
- $this->assertEquals(
- $expectedOutput,
- preg_replace( '/\d+-\d+-\d+T\d+:\d+:\d+Z/', 'timestamp', $realOutput ),
- "CSSMin::remap: $message"
- );
+ $this->assertEquals( $expectedOutput, $realOutput, "CSSMin::remap: $message" );
}
public static function provideIsRemoteUrl() {
@@ -197,7 +192,7 @@ class CSSMinTest extends MediaWikiTestCase {
array(
'Regular file',
'foo { background: url(red.gif); }',
- 'foo { background: url(http://localhost/w/red.gif?timestamp); }',
+ 'foo { background: url(http://localhost/w/red.gif?34ac6); }',
),
array(
'Regular file (missing)',
@@ -242,12 +237,12 @@ class CSSMinTest extends MediaWikiTestCase {
array(
'Embedded file',
'foo { /* @embed */ background: url(red.gif); }',
- "foo { background: url($red); background: url(http://localhost/w/red.gif?timestamp)!ie; }",
+ "foo { background: url($red); background: url(http://localhost/w/red.gif?34ac6)!ie; }",
),
array(
'Embedded file, other comments before the rule',
"foo { /* Bar. */ /* @embed */ background: url(red.gif); }",
- "foo { /* Bar. */ background: url($red); /* Bar. */ background: url(http://localhost/w/red.gif?timestamp)!ie; }",
+ "foo { /* Bar. */ background: url($red); /* Bar. */ background: url(http://localhost/w/red.gif?34ac6)!ie; }",
),
array(
'Can not re-embed data: URIs',
@@ -268,12 +263,12 @@ class CSSMinTest extends MediaWikiTestCase {
'Embedded file (inline @embed)',
'foo { background: /* @embed */ url(red.gif); }',
"foo { background: url($red); "
- . "background: url(http://localhost/w/red.gif?timestamp)!ie; }",
+ . "background: url(http://localhost/w/red.gif?34ac6)!ie; }",
),
array(
'Can not embed large files',
'foo { /* @embed */ background: url(large.png); }',
- "foo { background: url(http://localhost/w/large.png?timestamp); }",
+ "foo { background: url(http://localhost/w/large.png?e3d1f); }",
),
array(
'SVG files are embedded without base64 encoding and unnecessary IE 6 and 7 fallback',
@@ -283,55 +278,55 @@ class CSSMinTest extends MediaWikiTestCase {
array(
'Two regular files in one rule',
'foo { background: url(red.gif), url(green.gif); }',
- 'foo { background: url(http://localhost/w/red.gif?timestamp), '
- . 'url(http://localhost/w/green.gif?timestamp); }',
+ 'foo { background: url(http://localhost/w/red.gif?34ac6), '
+ . 'url(http://localhost/w/green.gif?13651); }',
),
array(
'Two embedded files in one rule',
'foo { /* @embed */ background: url(red.gif), url(green.gif); }',
"foo { background: url($red), url($green); "
- . "background: url(http://localhost/w/red.gif?timestamp), "
- . "url(http://localhost/w/green.gif?timestamp)!ie; }",
+ . "background: url(http://localhost/w/red.gif?34ac6), "
+ . "url(http://localhost/w/green.gif?13651)!ie; }",
),
array(
'Two embedded files in one rule (inline @embed)',
'foo { background: /* @embed */ url(red.gif), /* @embed */ url(green.gif); }',
"foo { background: url($red), url($green); "
- . "background: url(http://localhost/w/red.gif?timestamp), "
- . "url(http://localhost/w/green.gif?timestamp)!ie; }",
+ . "background: url(http://localhost/w/red.gif?34ac6), "
+ . "url(http://localhost/w/green.gif?13651)!ie; }",
),
array(
'Two embedded files in one rule (inline @embed), one too large',
'foo { background: /* @embed */ url(red.gif), /* @embed */ url(large.png); }',
- "foo { background: url($red), url(http://localhost/w/large.png?timestamp); "
- . "background: url(http://localhost/w/red.gif?timestamp), "
- . "url(http://localhost/w/large.png?timestamp)!ie; }",
+ "foo { background: url($red), url(http://localhost/w/large.png?e3d1f); "
+ . "background: url(http://localhost/w/red.gif?34ac6), "
+ . "url(http://localhost/w/large.png?e3d1f)!ie; }",
),
array(
'Practical example with some noise',
'foo { /* @embed */ background: #f9f9f9 url(red.gif) 0 0 no-repeat; }',
"foo { background: #f9f9f9 url($red) 0 0 no-repeat; "
- . "background: #f9f9f9 url(http://localhost/w/red.gif?timestamp) 0 0 no-repeat!ie; }",
+ . "background: #f9f9f9 url(http://localhost/w/red.gif?34ac6) 0 0 no-repeat!ie; }",
),
array(
'Does not mess with other properties',
'foo { color: red; background: url(red.gif); font-size: small; }',
- 'foo { color: red; background: url(http://localhost/w/red.gif?timestamp); font-size: small; }',
+ 'foo { color: red; background: url(http://localhost/w/red.gif?34ac6); font-size: small; }',
),
array(
'Spacing and miscellanea not changed (1)',
'foo { background: url(red.gif); }',
- 'foo { background: url(http://localhost/w/red.gif?timestamp); }',
+ 'foo { background: url(http://localhost/w/red.gif?34ac6); }',
),
array(
'Spacing and miscellanea not changed (2)',
'foo {background:url(red.gif)}',
- 'foo {background:url(http://localhost/w/red.gif?timestamp)}',
+ 'foo {background:url(http://localhost/w/red.gif?34ac6)}',
),
array(
'Spaces within url() parentheses are ignored',
'foo { background: url( red.gif ); }',
- 'foo { background: url(http://localhost/w/red.gif?timestamp); }',
+ 'foo { background: url(http://localhost/w/red.gif?34ac6); }',
),
array(
'@import rule to local file (should we remap this?)',
@@ -351,22 +346,22 @@ class CSSMinTest extends MediaWikiTestCase {
array(
'Simple case with comments after url',
'foo { prop: url(red.gif)/* some {funny;} comment */ ; }',
- 'foo { prop: url(http://localhost/w/red.gif?timestamp)/* some {funny;} comment */ ; }',
+ 'foo { prop: url(http://localhost/w/red.gif?34ac6)/* some {funny;} comment */ ; }',
),
array(
'Embedded file with comment before url',
'foo { /* @embed */ background: /* some {funny;} comment */ url(red.gif); }',
- "foo { background: /* some {funny;} comment */ url($red); background: /* some {funny;} comment */ url(http://localhost/w/red.gif?timestamp)!ie; }",
+ "foo { background: /* some {funny;} comment */ url($red); background: /* some {funny;} comment */ url(http://localhost/w/red.gif?34ac6)!ie; }",
),
array(
'Embedded file with comments inside and outside the rule',
'foo { /* @embed */ background: url(red.gif) /* some {foo;} comment */; /* some {bar;} comment */ }',
- "foo { background: url($red) /* some {foo;} comment */; background: url(http://localhost/w/red.gif?timestamp) /* some {foo;} comment */!ie; /* some {bar;} comment */ }",
+ "foo { background: url($red) /* some {foo;} comment */; background: url(http://localhost/w/red.gif?34ac6) /* some {foo;} comment */!ie; /* some {bar;} comment */ }",
),
array(
'Embedded file with comment outside the rule',
'foo { /* @embed */ background: url(red.gif); /* some {funny;} comment */ }',
- "foo { background: url($red); background: url(http://localhost/w/red.gif?timestamp)!ie; /* some {funny;} comment */ }",
+ "foo { background: url($red); background: url(http://localhost/w/red.gif?34ac6)!ie; /* some {funny;} comment */ }",
),
array(
'Rule with two urls, each with comments',
diff --git a/tests/phpunit/includes/libs/IEUrlExtensionTest.php b/tests/phpunit/includes/libs/IEUrlExtensionTest.php
index e96953ee..57668e50 100644
--- a/tests/phpunit/includes/libs/IEUrlExtensionTest.php
+++ b/tests/phpunit/includes/libs/IEUrlExtensionTest.php
@@ -170,4 +170,37 @@ class IEUrlExtensionTest extends PHPUnit_Framework_TestCase {
'Two dots'
);
}
+
+ /**
+ * @covers IEUrlExtension::findIE6Extension
+ */
+ public function testScriptQuery() {
+ $this->assertEquals(
+ 'php',
+ IEUrlExtension::findIE6Extension( 'example.php?foo=a&bar=b' ),
+ 'Script with query'
+ );
+ }
+
+ /**
+ * @covers IEUrlExtension::findIE6Extension
+ */
+ public function testEscapedScriptQuery() {
+ $this->assertEquals(
+ '',
+ IEUrlExtension::findIE6Extension( 'example%2Ephp?foo=a&bar=b' ),
+ 'Script with urlencoded dot and query'
+ );
+ }
+
+ /**
+ * @covers IEUrlExtension::findIE6Extension
+ */
+ public function testEscapedScriptQueryDot() {
+ $this->assertEquals(
+ 'y',
+ IEUrlExtension::findIE6Extension( 'example%2Ephp?foo=a.x&bar=b.y' ),
+ 'Script with urlencoded dot and query with dot'
+ );
+ }
}
diff --git a/tests/phpunit/includes/libs/IPSetTest.php b/tests/phpunit/includes/libs/IPSetTest.php
deleted file mode 100644
index 5bbacef4..00000000
--- a/tests/phpunit/includes/libs/IPSetTest.php
+++ /dev/null
@@ -1,252 +0,0 @@
- expected (boolean) result against the config dataset.
- */
- public static function provideIPSets() {
- return array(
- array(
- 'old_list_subset',
- array(
- '208.80.152.162',
- '10.64.0.123',
- '10.64.0.124',
- '10.64.0.125',
- '10.64.0.126',
- '10.64.0.127',
- '10.64.0.128',
- '10.64.0.129',
- '10.64.32.104',
- '10.64.32.105',
- '10.64.32.106',
- '10.64.32.107',
- '91.198.174.45',
- '91.198.174.46',
- '91.198.174.47',
- '91.198.174.57',
- '2620:0:862:1:A6BA:DBFF:FE30:CFB3',
- '91.198.174.58',
- '2620:0:862:1:A6BA:DBFF:FE38:FFDA',
- '208.80.152.16',
- '208.80.152.17',
- '208.80.152.18',
- '208.80.152.19',
- '91.198.174.102',
- '91.198.174.103',
- '91.198.174.104',
- '91.198.174.105',
- '91.198.174.106',
- '91.198.174.107',
- '91.198.174.81',
- '2620:0:862:1:26B6:FDFF:FEF5:B2D4',
- '91.198.174.82',
- '2620:0:862:1:26B6:FDFF:FEF5:ABB4',
- '10.20.0.113',
- '2620:0:862:102:26B6:FDFF:FEF5:AD9C',
- '10.20.0.114',
- '2620:0:862:102:26B6:FDFF:FEF5:7C38',
- ),
- array(
- '0.0.0.0' => false,
- '255.255.255.255' => false,
- '10.64.0.122' => false,
- '10.64.0.123' => true,
- '10.64.0.124' => true,
- '10.64.0.129' => true,
- '10.64.0.130' => false,
- '91.198.174.81' => true,
- '91.198.174.80' => false,
- '0::0' => false,
- 'ffff:ffff:ffff:ffff:FFFF:FFFF:FFFF:FFFF' => false,
- '2001:db8::1234' => false,
- '2620:0:862:1:26b6:fdff:fef5:abb3' => false,
- '2620:0:862:1:26b6:fdff:fef5:abb4' => true,
- '2620:0:862:1:26b6:fdff:fef5:abb5' => false,
- ),
- ),
- array(
- 'new_cidr_set',
- array(
- '208.80.154.0/26',
- '2620:0:861:1::/64',
- '208.80.154.128/26',
- '2620:0:861:2::/64',
- '208.80.154.64/26',
- '2620:0:861:3::/64',
- '208.80.155.96/27',
- '2620:0:861:4::/64',
- '10.64.0.0/22',
- '2620:0:861:101::/64',
- '10.64.16.0/22',
- '2620:0:861:102::/64',
- '10.64.32.0/22',
- '2620:0:861:103::/64',
- '10.64.48.0/22',
- '2620:0:861:107::/64',
- '91.198.174.0/25',
- '2620:0:862:1::/64',
- '10.20.0.0/24',
- '2620:0:862:102::/64',
- '10.128.0.0/24',
- '2620:0:863:101::/64',
- '10.2.4.26',
- ),
- array(
- '0.0.0.0' => false,
- '255.255.255.255' => false,
- '10.2.4.25' => false,
- '10.2.4.26' => true,
- '10.2.4.27' => false,
- '10.20.0.255' => true,
- '10.128.0.0' => true,
- '10.64.17.55' => true,
- '10.64.20.0' => false,
- '10.64.27.207' => false,
- '10.64.31.255' => false,
- '0::0' => false,
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' => false,
- '2001:DB8::1' => false,
- '2620:0:861:106::45' => false,
- '2620:0:862:103::' => false,
- '2620:0:862:102:10:20:0:113' => true,
- ),
- ),
- array(
- 'empty_set',
- array(),
- array(
- '0.0.0.0' => false,
- '255.255.255.255' => false,
- '10.2.4.25' => false,
- '10.2.4.26' => false,
- '10.2.4.27' => false,
- '10.20.0.255' => false,
- '10.128.0.0' => false,
- '10.64.17.55' => false,
- '10.64.20.0' => false,
- '10.64.27.207' => false,
- '10.64.31.255' => false,
- '0::0' => false,
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' => false,
- '2001:DB8::1' => false,
- '2620:0:861:106::45' => false,
- '2620:0:862:103::' => false,
- '2620:0:862:102:10:20:0:113' => false,
- ),
- ),
- array(
- 'edge_cases',
- array(
- '0.0.0.0',
- '255.255.255.255',
- '::',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
- '10.10.10.10/25', // host bits intentional
- ),
- array(
- '0.0.0.0' => true,
- '255.255.255.255' => true,
- '10.2.4.25' => false,
- '10.2.4.26' => false,
- '10.2.4.27' => false,
- '10.20.0.255' => false,
- '10.128.0.0' => false,
- '10.64.17.55' => false,
- '10.64.20.0' => false,
- '10.64.27.207' => false,
- '10.64.31.255' => false,
- '0::0' => true,
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' => true,
- '2001:DB8::1' => false,
- '2620:0:861:106::45' => false,
- '2620:0:862:103::' => false,
- '2620:0:862:102:10:20:0:113' => false,
- '10.10.9.255' => false,
- '10.10.10.0' => true,
- '10.10.10.1' => true,
- '10.10.10.10' => true,
- '10.10.10.126' => true,
- '10.10.10.127' => true,
- '10.10.10.128' => false,
- '10.10.10.177' => false,
- '10.10.10.255' => false,
- '10.10.11.0' => false,
- ),
- ),
- array(
- 'exercise_optimizer',
- array(
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fffe:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fffd:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fffc:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fffb:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fffa:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fff9:8000/113',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fff9:0/113',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fff8:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fff7:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fff6:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fff5:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fff4:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fff3:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fff2:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fff1:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:fff0:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffef:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffee:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffec:0/111',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffeb:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffea:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffe9:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffe8:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffe7:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffe6:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffe5:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffe4:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffe3:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffe2:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffe1:0/112',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffe0:0/110',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffc0:0/107',
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffa0:0/107',
- ),
- array(
- '0.0.0.0' => false,
- '255.255.255.255' => false,
- '::' => false,
- 'ffff:ffff:ffff:ffff:ffff:ffff:ff9f:ffff' => false,
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffa0:0' => true,
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffc0:1234' => true,
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffed:ffff' => true,
- 'ffff:ffff:ffff:ffff:ffff:ffff:fff4:4444' => true,
- 'ffff:ffff:ffff:ffff:ffff:ffff:fff9:8080' => true,
- 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' => true,
- ),
- ),
- );
- }
-
- /**
- * Validates IPSet loading and matching code
- *
- * @covers IPSet
- * @dataProvider provideIPSets
- */
- public function testIPSet( $desc, array $cfg, array $tests ) {
- $ipset = new IPSet( $cfg );
- foreach ( $tests as $ip => $expected ) {
- $result = $ipset->match( $ip );
- $this->assertEquals( $expected, $result, "Incorrect match() result for $ip in dataset $desc" );
- }
- }
-}
diff --git a/tests/phpunit/includes/libs/JavaScriptMinifierTest.php b/tests/phpunit/includes/libs/JavaScriptMinifierTest.php
index 149a28c1..d23534ed 100644
--- a/tests/phpunit/includes/libs/JavaScriptMinifierTest.php
+++ b/tests/phpunit/includes/libs/JavaScriptMinifierTest.php
@@ -140,6 +140,13 @@ class JavaScriptMinifierTest extends PHPUnit_Framework_TestCase {
array( "5..toString();", "5..toString();" ),
array( "5...toString();", false ),
array( "5.\n.toString();", '5..toString();' ),
+
+ // Boolean minification (!0 / !1)
+ array( "var a = { b: true };", "var a={b:!0};" ),
+ array( "var a = { true: 12 };", "var a={true:12};", false ),
+ array( "a.true = 12;", "a.true=12;", false ),
+ array( "a.foo = true;", "a.foo=!0;" ),
+ array( "a.foo = false;", "a.foo=!1;" ),
);
}
@@ -147,15 +154,17 @@ class JavaScriptMinifierTest extends PHPUnit_Framework_TestCase {
* @dataProvider provideCases
* @covers JavaScriptMinifier::minify
*/
- public function testJavaScriptMinifierOutput( $code, $expectedOutput ) {
+ public function testJavaScriptMinifierOutput( $code, $expectedOutput, $expectedValid = true ) {
$minified = JavaScriptMinifier::minify( $code );
// JSMin+'s parser will throw an exception if output is not valid JS.
// suppression of warnings needed for stupid crap
- wfSuppressWarnings();
- $parser = new JSParser();
- wfRestoreWarnings();
- $parser->parse( $minified, 'minify-test.js', 1 );
+ if ( $expectedValid ) {
+ MediaWiki\suppressWarnings();
+ $parser = new JSParser();
+ MediaWiki\restoreWarnings();
+ $parser->parse( $minified, 'minify-test.js', 1 );
+ }
$this->assertEquals(
$expectedOutput,
diff --git a/tests/phpunit/includes/libs/ObjectFactoryTest.php b/tests/phpunit/includes/libs/ObjectFactoryTest.php
index 92207325..aea037e0 100644
--- a/tests/phpunit/includes/libs/ObjectFactoryTest.php
+++ b/tests/phpunit/includes/libs/ObjectFactoryTest.php
@@ -26,11 +26,20 @@ class ObjectFactoryTest extends PHPUnit_Framework_TestCase {
public function testClosureExpansionDisabled() {
$obj = ObjectFactory::getObjectFromSpec( array(
'class' => 'ObjectFactoryTest_Fixture',
- 'args' => array( function (){ return 'unwrapped'; }, ),
+ 'args' => array( function() {
+ return 'unwrapped';
+ }, ),
+ 'calls' => array(
+ 'setter' => array( function() {
+ return 'unwrapped';
+ }, ),
+ ),
'closure_expansion' => false,
) );
$this->assertInstanceOf( 'Closure', $obj->args[0] );
$this->assertSame( 'unwrapped', $obj->args[0]() );
+ $this->assertInstanceOf( 'Closure', $obj->setterArgs[0] );
+ $this->assertSame( 'unwrapped', $obj->setterArgs[0]() );
}
/**
@@ -39,22 +48,46 @@ class ObjectFactoryTest extends PHPUnit_Framework_TestCase {
public function testClosureExpansionEnabled() {
$obj = ObjectFactory::getObjectFromSpec( array(
'class' => 'ObjectFactoryTest_Fixture',
- 'args' => array( function (){ return 'unwrapped'; }, ),
+ 'args' => array( function() {
+ return 'unwrapped';
+ }, ),
+ 'calls' => array(
+ 'setter' => array( function() {
+ return 'unwrapped';
+ }, ),
+ ),
'closure_expansion' => true,
) );
$this->assertInternalType( 'string', $obj->args[0] );
$this->assertSame( 'unwrapped', $obj->args[0] );
+ $this->assertInternalType( 'string', $obj->setterArgs[0] );
+ $this->assertSame( 'unwrapped', $obj->setterArgs[0] );
$obj = ObjectFactory::getObjectFromSpec( array(
'class' => 'ObjectFactoryTest_Fixture',
- 'args' => array( function (){ return 'unwrapped'; }, ),
+ 'args' => array( function() {
+ return 'unwrapped';
+ }, ),
+ 'calls' => array(
+ 'setter' => array( function() {
+ return 'unwrapped';
+ }, ),
+ ),
) );
$this->assertInternalType( 'string', $obj->args[0] );
$this->assertSame( 'unwrapped', $obj->args[0] );
+ $this->assertInternalType( 'string', $obj->setterArgs[0] );
+ $this->assertSame( 'unwrapped', $obj->setterArgs[0] );
}
}
class ObjectFactoryTest_Fixture {
public $args;
- public function __construct( /*...*/ ) { $this->args = func_get_args(); }
+ public $setterArgs;
+ public function __construct( /*...*/ ) {
+ $this->args = func_get_args();
+ }
+ public function setter( /*...*/ ) {
+ $this->setterArgs = func_get_args();
+ }
}
diff --git a/tests/phpunit/includes/libs/ProcessCacheLRUTest.php b/tests/phpunit/includes/libs/ProcessCacheLRUTest.php
index 43001979..cec662a9 100644
--- a/tests/phpunit/includes/libs/ProcessCacheLRUTest.php
+++ b/tests/phpunit/includes/libs/ProcessCacheLRUTest.php
@@ -70,7 +70,7 @@ class ProcessCacheLRUTest extends PHPUnit_Framework_TestCase {
/**
* @dataProvider provideInvalidConstructorArg
- * @expectedException UnexpectedValueException
+ * @expectedException Wikimedia\Assert\ParameterAssertionException
* @covers ProcessCacheLRU::__construct
*/
public function testConstructorGivenInvalidValue( $maxSize ) {
diff --git a/tests/phpunit/includes/libs/SamplingStatsdClientTest.php b/tests/phpunit/includes/libs/SamplingStatsdClientTest.php
new file mode 100644
index 00000000..be6732d5
--- /dev/null
+++ b/tests/phpunit/includes/libs/SamplingStatsdClientTest.php
@@ -0,0 +1,43 @@
+getMock( 'Liuggio\StatsdClient\Sender\SenderInterface' );
+ $sender->expects( $this->any() )->method( 'open' )->will( $this->returnValue( true ) );
+ if ( $expectWrite ) {
+ $sender->expects( $this->once() )->method( 'write' )
+ ->with( $this->anything(), $this->equalTo( $data ) );
+ } else {
+ $sender->expects( $this->never() )->method( 'write' );
+ }
+ mt_srand( $seed );
+ $client = new SamplingStatsdClient( $sender );
+ $client->send( $data, $sampleRate );
+ }
+
+ public function samplingDataProvider() {
+ $unsampled = new StatsdData();
+ $unsampled->setKey( 'foo' );
+ $unsampled->setValue( 1 );
+
+ $sampled = new StatsdData();
+ $sampled->setKey( 'foo' );
+ $sampled->setValue( 1 );
+ $sampled->setSampleRate( '0.1' );
+
+ return array(
+ // $data, $sampleRate, $seed, $expectWrite
+ array( $unsampled, 1, 0 /*0.44*/, $unsampled ),
+ array( $sampled, 1, 0 /*0.44*/, null ),
+ array( $sampled, 1, 4 /*0.03*/, $sampled ),
+ array( $unsampled, 0.1, 4 /*0.03*/, $sampled ),
+ array( $sampled, 0.5, 0 /*0.44*/, null ),
+ array( $sampled, 0.5, 4 /*0.03*/, $sampled ),
+ );
+ }
+}
diff --git a/tests/phpunit/includes/libs/XhprofTest.php b/tests/phpunit/includes/libs/XhprofTest.php
index 2440fc08..77b188cf 100644
--- a/tests/phpunit/includes/libs/XhprofTest.php
+++ b/tests/phpunit/includes/libs/XhprofTest.php
@@ -255,43 +255,43 @@ class XhprofTest extends PHPUnit_Framework_TestCase {
*/
protected function getXhprofFixture( array $opts = array() ) {
$xhprof = new Xhprof( $opts );
- $xhprof->loadRawData( array (
- 'foo==>bar' => array (
+ $xhprof->loadRawData( array(
+ 'foo==>bar' => array(
'ct' => 2,
'wt' => 57,
'cpu' => 92,
'mu' => 1896,
'pmu' => 0,
),
- 'foo==>strlen' => array (
+ 'foo==>strlen' => array(
'ct' => 2,
'wt' => 21,
'cpu' => 141,
'mu' => 752,
'pmu' => 0,
),
- 'bar==>bar@1' => array (
+ 'bar==>bar@1' => array(
'ct' => 1,
'wt' => 18,
'cpu' => 19,
'mu' => 752,
'pmu' => 0,
),
- 'main()==>foo' => array (
+ 'main()==>foo' => array(
'ct' => 1,
'wt' => 304,
'cpu' => 307,
'mu' => 4008,
'pmu' => 0,
),
- 'main()==>xhprof_disable' => array (
+ 'main()==>xhprof_disable' => array(
'ct' => 1,
'wt' => 8,
'cpu' => 10,
'mu' => 768,
'pmu' => 392,
),
- 'main()' => array (
+ 'main()' => array(
'ct' => 1,
'wt' => 353,
'cpu' => 351,
@@ -311,7 +311,7 @@ class XhprofTest extends PHPUnit_Framework_TestCase {
*/
protected function assertArrayStructure( $struct, $actual, $label = null ) {
$this->assertInternalType( 'array', $actual, $label );
- $this->assertCount( count($struct), $actual, $label );
+ $this->assertCount( count( $struct ), $actual, $label );
foreach ( $struct as $key => $type ) {
$this->assertArrayHasKey( $key, $actual );
$this->assertInternalType( $type, $actual[$key] );
diff --git a/tests/phpunit/includes/libs/composer/ComposerLockTest.php b/tests/phpunit/includes/libs/composer/ComposerLockTest.php
index b5fd5f6e..cac3b101 100644
--- a/tests/phpunit/includes/libs/composer/ComposerLockTest.php
+++ b/tests/phpunit/includes/libs/composer/ComposerLockTest.php
@@ -27,34 +27,95 @@ class ComposerLockTest extends MediaWikiTestCase {
'wikimedia/cdb' => array(
'version' => '1.0.1',
'type' => 'library',
+ 'licenses' => array( 'GPL-2.0' ),
+ 'authors' => array(
+ array(
+ 'name' => 'Tim Starling',
+ 'email' => 'tstarling@wikimedia.org',
+ ),
+ array(
+ 'name' => 'Chad Horohoe',
+ 'email' => 'chad@wikimedia.org',
+ ),
+ ),
+ 'description' => 'Constant Database (CDB) wrapper library for PHP. Provides pure-PHP fallback when dba_* functions are absent.',
),
'cssjanus/cssjanus' => array(
'version' => '1.1.1',
'type' => 'library',
+ 'licenses' => array( 'Apache-2.0' ),
+ 'authors' => array(),
+ 'description' => 'Convert CSS stylesheets between left-to-right and right-to-left.',
),
'leafo/lessphp' => array(
'version' => '0.5.0',
'type' => 'library',
+ 'licenses' => array( 'MIT', 'GPL-3.0' ),
+ 'authors' => array(
+ array(
+ 'name' => 'Leaf Corcoran',
+ 'email' => 'leafot@gmail.com',
+ 'homepage' => 'http://leafo.net',
+ ),
+ ),
+ 'description' => 'lessphp is a compiler for LESS written in PHP.',
),
'psr/log' => array(
'version' => '1.0.0',
'type' => 'library',
+ 'licenses' => array( 'MIT' ),
+ 'authors' => array(
+ array(
+ 'name' => 'PHP-FIG',
+ 'homepage' => 'http://www.php-fig.org/',
+ ),
+ ),
+ 'description' => 'Common interface for logging libraries',
),
'oojs/oojs-ui' => array(
'version' => '0.6.0',
'type' => 'library',
+ 'licenses' => array( 'MIT' ),
+ 'authors' => array(),
+ 'description' => '',
),
'composer/installers' => array(
'version' => '1.0.19',
'type' => 'composer-installer',
+ 'licenses' => array( 'MIT' ),
+ 'authors' => array(
+ array(
+ 'name' => 'Kyle Robinson Young',
+ 'email' => 'kyle@dontkry.com',
+ 'homepage' => 'https://github.com/shama',
+ ),
+ ),
+ 'description' => 'A multi-framework Composer library installer',
),
'mediawiki/translate' => array(
'version' => '2014.12',
'type' => 'mediawiki-extension',
+ 'licenses' => array( 'GPL-2.0+' ),
+ 'authors' => array(
+ array(
+ 'name' => 'Niklas Laxström',
+ 'email' => 'niklas.laxstrom@gmail.com',
+ 'role' => 'Lead nitpicker',
+ ),
+ array(
+ 'name' => 'Siebrand Mazeland',
+ 'email' => 's.mazeland@xs4all.nl',
+ 'role' => 'Developer',
+ ),
+ ),
+ 'description' => 'The only standard solution to translate any kind of text with an avant-garde web interface within MediaWiki, including your documentation and software',
),
'mediawiki/universal-language-selector' => array(
'version' => '2014.12',
'type' => 'mediawiki-extension',
+ 'licenses' => array( 'GPL-2.0+', 'MIT' ),
+ 'authors' => array(),
+ 'description' => 'The primary aim is to allow users to select a language and configure its support in an easy way. Main features are language selection, input methods and web fonts.',
),
), $lock->getInstalledDependencies(), false, true );
}
diff --git a/tests/phpunit/includes/logging/BlockLogFormatterTest.php b/tests/phpunit/includes/logging/BlockLogFormatterTest.php
new file mode 100644
index 00000000..c7dc641d
--- /dev/null
+++ b/tests/phpunit/includes/logging/BlockLogFormatterTest.php
@@ -0,0 +1,372 @@
+ 'block',
+ 'action' => 'block',
+ 'comment' => 'Block comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Logtestuser',
+ 'params' => array(
+ '5::duration' => 'infinite',
+ '6::flags' => 'anononly',
+ ),
+ ),
+ array(
+ 'text' => 'Sysop blocked Logtestuser with an expiry time of indefinite (anonymous users only)',
+ 'api' => array(
+ 'duration' => 'infinite',
+ 'flags' => array( 'anononly' ),
+ ),
+ ),
+ ),
+
+ // Old legacy log
+ array(
+ array(
+ 'type' => 'block',
+ 'action' => 'block',
+ 'comment' => 'Block comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Logtestuser',
+ 'params' => array(
+ 'infinite',
+ 'anononly',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'Sysop blocked Logtestuser with an expiry time of indefinite (anonymous users only)',
+ 'api' => array(
+ 'duration' => 'infinite',
+ 'flags' => array( 'anononly' ),
+ ),
+ ),
+ ),
+
+ // Old legacy log without flag
+ array(
+ array(
+ 'type' => 'block',
+ 'action' => 'block',
+ 'comment' => 'Block comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Logtestuser',
+ 'params' => array(
+ 'infinite',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'Sysop blocked Logtestuser with an expiry time of indefinite',
+ 'api' => array(
+ 'duration' => 'infinite',
+ 'flags' => array(),
+ ),
+ ),
+ ),
+
+ // Very old legacy log without duration
+ array(
+ array(
+ 'type' => 'block',
+ 'action' => 'block',
+ 'comment' => 'Block comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Logtestuser',
+ 'params' => array(),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'Sysop blocked Logtestuser with an expiry time of indefinite',
+ 'api' => array(
+ 'duration' => 'infinite',
+ 'flags' => array(),
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideBlockLogDatabaseRows
+ */
+ public function testBlockLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideReblockLogDatabaseRows() {
+ return array(
+ // Current log format
+ array(
+ array(
+ 'type' => 'block',
+ 'action' => 'reblock',
+ 'comment' => 'Block comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Logtestuser',
+ 'params' => array(
+ '5::duration' => 'infinite',
+ '6::flags' => 'anononly',
+ ),
+ ),
+ array(
+ 'text' => 'Sysop changed block settings for Logtestuser with an expiry time of'
+ . ' indefinite (anonymous users only)',
+ 'api' => array(
+ 'duration' => 'infinite',
+ 'flags' => array( 'anononly' ),
+ ),
+ ),
+ ),
+
+ // Old log
+ array(
+ array(
+ 'type' => 'block',
+ 'action' => 'reblock',
+ 'comment' => 'Block comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Logtestuser',
+ 'params' => array(
+ 'infinite',
+ 'anononly',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'Sysop changed block settings for Logtestuser with an expiry time of'
+ . ' indefinite (anonymous users only)',
+ 'api' => array(
+ 'duration' => 'infinite',
+ 'flags' => array( 'anononly' ),
+ ),
+ ),
+ ),
+
+ // Older log without flag
+ array(
+ array(
+ 'type' => 'block',
+ 'action' => 'reblock',
+ 'comment' => 'Block comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Logtestuser',
+ 'params' => array(
+ 'infinite',
+ )
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'Sysop changed block settings for Logtestuser with an expiry time of indefinite',
+ 'api' => array(
+ 'duration' => 'infinite',
+ 'flags' => array(),
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideReblockLogDatabaseRows
+ */
+ public function testReblockLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideUnblockLogDatabaseRows() {
+ return array(
+ // Current log format
+ array(
+ array(
+ 'type' => 'block',
+ 'action' => 'unblock',
+ 'comment' => 'Block comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Logtestuser',
+ 'params' => array(),
+ ),
+ array(
+ 'text' => 'Sysop unblocked Logtestuser',
+ 'api' => array(),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideUnblockLogDatabaseRows
+ */
+ public function testUnblockLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideSuppressBlockLogDatabaseRows() {
+ return array(
+ // Current log format
+ array(
+ array(
+ 'type' => 'suppress',
+ 'action' => 'block',
+ 'comment' => 'Block comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Logtestuser',
+ 'params' => array(
+ '5::duration' => 'infinite',
+ '6::flags' => 'anononly',
+ ),
+ ),
+ array(
+ 'text' => 'Sysop blocked Logtestuser with an expiry time of indefinite (anonymous users only)',
+ 'api' => array(
+ 'duration' => 'infinite',
+ 'flags' => array( 'anononly' ),
+ ),
+ ),
+ ),
+
+ // legacy log
+ array(
+ array(
+ 'type' => 'suppress',
+ 'action' => 'block',
+ 'comment' => 'Block comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Logtestuser',
+ 'params' => array(
+ 'infinite',
+ 'anononly',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'Sysop blocked Logtestuser with an expiry time of indefinite (anonymous users only)',
+ 'api' => array(
+ 'duration' => 'infinite',
+ 'flags' => array( 'anononly' ),
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideSuppressBlockLogDatabaseRows
+ */
+ public function testSuppressBlockLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideSuppressReblockLogDatabaseRows() {
+ return array(
+ // Current log format
+ array(
+ array(
+ 'type' => 'suppress',
+ 'action' => 'reblock',
+ 'comment' => 'Block comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Logtestuser',
+ 'params' => array(
+ '5::duration' => 'infinite',
+ '6::flags' => 'anononly',
+ ),
+ ),
+ array(
+ 'text' => 'Sysop changed block settings for Logtestuser with an expiry time of'
+ . ' indefinite (anonymous users only)',
+ 'api' => array(
+ 'duration' => 'infinite',
+ 'flags' => array( 'anononly' ),
+ ),
+ ),
+ ),
+
+ // Legacy format
+ array(
+ array(
+ 'type' => 'suppress',
+ 'action' => 'reblock',
+ 'comment' => 'Block comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Logtestuser',
+ 'params' => array(
+ 'infinite',
+ 'anononly',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'Sysop changed block settings for Logtestuser with an expiry time of'
+ . ' indefinite (anonymous users only)',
+ 'api' => array(
+ 'duration' => 'infinite',
+ 'flags' => array( 'anononly' ),
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideSuppressReblockLogDatabaseRows
+ */
+ public function testSuppressReblockLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+}
diff --git a/tests/phpunit/includes/logging/DeleteLogFormatterTest.php b/tests/phpunit/includes/logging/DeleteLogFormatterTest.php
new file mode 100644
index 00000000..28e7efaf
--- /dev/null
+++ b/tests/phpunit/includes/logging/DeleteLogFormatterTest.php
@@ -0,0 +1,527 @@
+ 'delete',
+ 'action' => 'delete',
+ 'comment' => 'delete comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(),
+ ),
+ array(
+ 'text' => 'User deleted page Page',
+ 'api' => array(),
+ ),
+ ),
+
+ // Legacy format
+ array(
+ array(
+ 'type' => 'delete',
+ 'action' => 'delete',
+ 'comment' => 'delete comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User deleted page Page',
+ 'api' => array(),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideDeleteLogDatabaseRows
+ */
+ public function testDeleteLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideRestoreLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'delete',
+ 'action' => 'restore',
+ 'comment' => 'delete comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(),
+ ),
+ array(
+ 'text' => 'User restored page Page',
+ 'api' => array(),
+ ),
+ ),
+
+ // Legacy format
+ array(
+ array(
+ 'type' => 'delete',
+ 'action' => 'restore',
+ 'comment' => 'delete comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User restored page Page',
+ 'api' => array(),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideRestoreLogDatabaseRows
+ */
+ public function testRestoreLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideRevisionLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'delete',
+ 'action' => 'revision',
+ 'comment' => 'delete comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(
+ '4::type' => 'archive',
+ '5::ids' => array( '1', '3', '4' ),
+ '6::ofield' => '1',
+ '7::nfield' => '2',
+ ),
+ ),
+ array(
+ 'text' => 'User changed visibility of 3 revisions on page Page: edit summary '
+ . 'hidden and content unhidden',
+ 'api' => array(
+ 'type' => 'archive',
+ 'ids' => array( '1', '3', '4' ),
+ 'old' => array(
+ 'bitmask' => 1,
+ 'content' => true,
+ 'comment' => false,
+ 'user' => false,
+ 'restricted' => false,
+ ),
+ 'new' => array(
+ 'bitmask' => 2,
+ 'content' => false,
+ 'comment' => true,
+ 'user' => false,
+ 'restricted' => false,
+ ),
+ ),
+ ),
+ ),
+
+ // Legacy format
+ array(
+ array(
+ 'type' => 'delete',
+ 'action' => 'revision',
+ 'comment' => 'delete comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(
+ 'archive',
+ '1,3,4',
+ 'ofield=1',
+ 'nfield=2',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User changed visibility of 3 revisions on page Page: edit summary '
+ . 'hidden and content unhidden',
+ 'api' => array(
+ 'type' => 'archive',
+ 'ids' => array( '1', '3', '4' ),
+ 'old' => array(
+ 'bitmask' => 1,
+ 'content' => true,
+ 'comment' => false,
+ 'user' => false,
+ 'restricted' => false,
+ ),
+ 'new' => array(
+ 'bitmask' => 2,
+ 'content' => false,
+ 'comment' => true,
+ 'user' => false,
+ 'restricted' => false,
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideRevisionLogDatabaseRows
+ */
+ public function testRevisionLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideEventLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'delete',
+ 'action' => 'event',
+ 'comment' => 'delete comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(
+ '4::ids' => array( '1', '3', '4' ),
+ '5::ofield' => '1',
+ '6::nfield' => '2',
+ ),
+ ),
+ array(
+ 'text' => 'User changed visibility of 3 log events on Page: edit summary hidden '
+ . 'and content unhidden',
+ 'api' => array(
+ 'type' => 'logging',
+ 'ids' => array( '1', '3', '4' ),
+ 'old' => array(
+ 'bitmask' => 1,
+ 'content' => true,
+ 'comment' => false,
+ 'user' => false,
+ 'restricted' => false,
+ ),
+ 'new' => array(
+ 'bitmask' => 2,
+ 'content' => false,
+ 'comment' => true,
+ 'user' => false,
+ 'restricted' => false,
+ ),
+ ),
+ ),
+ ),
+
+ // Legacy format
+ array(
+ array(
+ 'type' => 'delete',
+ 'action' => 'event',
+ 'comment' => 'delete comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(
+ '1,3,4',
+ 'ofield=1',
+ 'nfield=2',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User changed visibility of 3 log events on Page: edit summary hidden '
+ . 'and content unhidden',
+ 'api' => array(
+ 'type' => 'logging',
+ 'ids' => array( '1', '3', '4' ),
+ 'old' => array(
+ 'bitmask' => 1,
+ 'content' => true,
+ 'comment' => false,
+ 'user' => false,
+ 'restricted' => false,
+ ),
+ 'new' => array(
+ 'bitmask' => 2,
+ 'content' => false,
+ 'comment' => true,
+ 'user' => false,
+ 'restricted' => false,
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideEventLogDatabaseRows
+ */
+ public function testEventLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideSuppressRevisionLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'suppress',
+ 'action' => 'revision',
+ 'comment' => 'Suppress comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(
+ '4::type' => 'archive',
+ '5::ids' => array( '1', '3', '4' ),
+ '6::ofield' => '1',
+ '7::nfield' => '10',
+ ),
+ ),
+ array(
+ 'text' => 'User secretly changed visibility of 3 revisions on page Page: edit '
+ . 'summary hidden, content unhidden and applied restrictions to administrators',
+ 'api' => array(
+ 'type' => 'archive',
+ 'ids' => array( '1', '3', '4' ),
+ 'old' => array(
+ 'bitmask' => 1,
+ 'content' => true,
+ 'comment' => false,
+ 'user' => false,
+ 'restricted' => false,
+ ),
+ 'new' => array(
+ 'bitmask' => 10,
+ 'content' => false,
+ 'comment' => true,
+ 'user' => false,
+ 'restricted' => true,
+ ),
+ ),
+ ),
+ ),
+
+ // Legacy format
+ array(
+ array(
+ 'type' => 'suppress',
+ 'action' => 'revision',
+ 'comment' => 'Suppress comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(
+ 'archive',
+ '1,3,4',
+ 'ofield=1',
+ 'nfield=10',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User secretly changed visibility of 3 revisions on page Page: edit '
+ . 'summary hidden, content unhidden and applied restrictions to administrators',
+ 'api' => array(
+ 'type' => 'archive',
+ 'ids' => array( '1', '3', '4' ),
+ 'old' => array(
+ 'bitmask' => 1,
+ 'content' => true,
+ 'comment' => false,
+ 'user' => false,
+ 'restricted' => false,
+ ),
+ 'new' => array(
+ 'bitmask' => 10,
+ 'content' => false,
+ 'comment' => true,
+ 'user' => false,
+ 'restricted' => true,
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideSuppressRevisionLogDatabaseRows
+ */
+ public function testSuppressRevisionLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideSuppressEventLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'suppress',
+ 'action' => 'event',
+ 'comment' => 'Suppress comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(
+ '4::ids' => array( '1', '3', '4' ),
+ '5::ofield' => '1',
+ '6::nfield' => '10',
+ ),
+ ),
+ array(
+ 'text' => 'User secretly changed visibility of 3 log events on Page: edit '
+ . 'summary hidden, content unhidden and applied restrictions to administrators',
+ 'api' => array(
+ 'type' => 'logging',
+ 'ids' => array( '1', '3', '4' ),
+ 'old' => array(
+ 'bitmask' => 1,
+ 'content' => true,
+ 'comment' => false,
+ 'user' => false,
+ 'restricted' => false,
+ ),
+ 'new' => array(
+ 'bitmask' => 10,
+ 'content' => false,
+ 'comment' => true,
+ 'user' => false,
+ 'restricted' => true,
+ ),
+ ),
+ ),
+ ),
+
+ // Legacy format
+ array(
+ array(
+ 'type' => 'suppress',
+ 'action' => 'event',
+ 'comment' => 'Suppress comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(
+ '1,3,4',
+ 'ofield=1',
+ 'nfield=10',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User secretly changed visibility of 3 log events on Page: edit '
+ . 'summary hidden, content unhidden and applied restrictions to administrators',
+ 'api' => array(
+ 'type' => 'logging',
+ 'ids' => array( '1', '3', '4' ),
+ 'old' => array(
+ 'bitmask' => 1,
+ 'content' => true,
+ 'comment' => false,
+ 'user' => false,
+ 'restricted' => false,
+ ),
+ 'new' => array(
+ 'bitmask' => 10,
+ 'content' => false,
+ 'comment' => true,
+ 'user' => false,
+ 'restricted' => true,
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideSuppressEventLogDatabaseRows
+ */
+ public function testSuppressEventLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideSuppressDeleteLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'suppress',
+ 'action' => 'delete',
+ 'comment' => 'delete comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(),
+ ),
+ array(
+ 'text' => 'User suppressed page Page',
+ 'api' => array(),
+ ),
+ ),
+
+ // Legacy format
+ array(
+ array(
+ 'type' => 'suppress',
+ 'action' => 'delete',
+ 'comment' => 'delete comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User suppressed page Page',
+ 'api' => array(),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideSuppressDeleteLogDatabaseRows
+ */
+ public function testSuppressDeleteLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+}
diff --git a/tests/phpunit/includes/logging/LogFormatterTest.php b/tests/phpunit/includes/logging/LogFormatterTest.php
index 515990e6..844c9afb 100644
--- a/tests/phpunit/includes/logging/LogFormatterTest.php
+++ b/tests/phpunit/includes/logging/LogFormatterTest.php
@@ -1,4 +1,5 @@
recache( $wgLang->getCode() );
$this->user = User::newFromName( 'Testuser' );
- $this->title = Title::newMainPage();
+ $this->title = Title::newFromText( 'SomeTitle' );
+ $this->target = Title::newFromText( 'TestTarget' );
$this->context = new RequestContext();
$this->context->setUser( $this->user );
$this->context->setTitle( $this->title );
$this->context->setLanguage( $wgLang );
+
+ $this->user_comment = '';
}
protected function tearDown() {
@@ -292,4 +306,309 @@ class LogFormatterTest extends MediaWikiLangTestCase {
array( '4:user-link:key', 'foo', array( 'key' => 'Foo' ) ),
);
}
+
+ /**
+ * @covers LogFormatter::getIRCActionComment
+ * @covers LogFormatter::getIRCActionText
+ */
+ public function testIrcMsgForLogTypeBlock() {
+ $sep = $this->context->msg( 'colon-separator' )->text();
+
+ # block/block
+ $this->assertIRCComment(
+ $this->context->msg( 'blocklogentry', 'SomeTitle', 'duration', '(flags)' )->plain()
+ . $sep . $this->user_comment,
+ 'block', 'block',
+ array(
+ '5::duration' => 'duration',
+ '6::flags' => 'flags',
+ ),
+ $this->user_comment
+ );
+ # block/block - legacy
+ $this->assertIRCComment(
+ $this->context->msg( 'blocklogentry', 'SomeTitle', 'duration', '(flags)' )->plain()
+ . $sep . $this->user_comment,
+ 'block', 'block',
+ array(
+ 'duration',
+ 'flags',
+ ),
+ $this->user_comment,
+ '',
+ true
+ );
+ # block/unblock
+ $this->assertIRCComment(
+ $this->context->msg( 'unblocklogentry', 'SomeTitle' )->plain() . $sep . $this->user_comment,
+ 'block', 'unblock',
+ array(),
+ $this->user_comment
+ );
+ # block/reblock
+ $this->assertIRCComment(
+ $this->context->msg( 'reblock-logentry', 'SomeTitle', 'duration', '(flags)' )->plain()
+ . $sep . $this->user_comment,
+ 'block', 'reblock',
+ array(
+ '5::duration' => 'duration',
+ '6::flags' => 'flags',
+ ),
+ $this->user_comment
+ );
+ }
+
+ /**
+ * @covers LogFormatter::getIRCActionComment
+ * @covers LogFormatter::getIRCActionText
+ */
+ public function testIrcMsgForLogTypeDelete() {
+ $sep = $this->context->msg( 'colon-separator' )->text();
+
+ # delete/delete
+ $this->assertIRCComment(
+ $this->context->msg( 'deletedarticle', 'SomeTitle' )->plain() . $sep . $this->user_comment,
+ 'delete', 'delete',
+ array(),
+ $this->user_comment
+ );
+
+ # delete/restore
+ $this->assertIRCComment(
+ $this->context->msg( 'undeletedarticle', 'SomeTitle' )->plain() . $sep . $this->user_comment,
+ 'delete', 'restore',
+ array(),
+ $this->user_comment
+ );
+ }
+
+ /**
+ * @covers LogFormatter::getIRCActionComment
+ * @covers LogFormatter::getIRCActionText
+ */
+ public function testIrcMsgForLogTypeNewusers() {
+ $this->assertIRCComment(
+ 'New user account',
+ 'newusers', 'newusers',
+ array()
+ );
+ $this->assertIRCComment(
+ 'New user account',
+ 'newusers', 'create',
+ array()
+ );
+ $this->assertIRCComment(
+ 'created new account SomeTitle',
+ 'newusers', 'create2',
+ array()
+ );
+ $this->assertIRCComment(
+ 'Account created automatically',
+ 'newusers', 'autocreate',
+ array()
+ );
+ }
+
+ /**
+ * @covers LogFormatter::getIRCActionComment
+ * @covers LogFormatter::getIRCActionText
+ */
+ public function testIrcMsgForLogTypeMove() {
+ $move_params = array(
+ '4::target' => $this->target->getPrefixedText(),
+ '5::noredir' => 0,
+ );
+ $sep = $this->context->msg( 'colon-separator' )->text();
+
+ # move/move
+ $this->assertIRCComment(
+ $this->context->msg( '1movedto2', 'SomeTitle', 'TestTarget' )
+ ->plain() . $sep . $this->user_comment,
+ 'move', 'move',
+ $move_params,
+ $this->user_comment
+ );
+
+ # move/move_redir
+ $this->assertIRCComment(
+ $this->context->msg( '1movedto2_redir', 'SomeTitle', 'TestTarget' )
+ ->plain() . $sep . $this->user_comment,
+ 'move', 'move_redir',
+ $move_params,
+ $this->user_comment
+ );
+ }
+
+ /**
+ * @covers LogFormatter::getIRCActionComment
+ * @covers LogFormatter::getIRCActionText
+ */
+ public function testIrcMsgForLogTypePatrol() {
+ # patrol/patrol
+ $this->assertIRCComment(
+ $this->context->msg( 'patrol-log-line', 'revision 777', '[[SomeTitle]]', '' )->plain(),
+ 'patrol', 'patrol',
+ array(
+ '4::curid' => '777',
+ '5::previd' => '666',
+ '6::auto' => 0,
+ )
+ );
+ }
+
+ /**
+ * @covers LogFormatter::getIRCActionComment
+ * @covers LogFormatter::getIRCActionText
+ */
+ public function testIrcMsgForLogTypeProtect() {
+ $protectParams = array(
+ '[edit=sysop] (indefinite) [move=sysop] (indefinite)'
+ );
+ $sep = $this->context->msg( 'colon-separator' )->text();
+
+ # protect/protect
+ $this->assertIRCComment(
+ $this->context->msg( 'protectedarticle', 'SomeTitle ' . $protectParams[0] )
+ ->plain() . $sep . $this->user_comment,
+ 'protect', 'protect',
+ $protectParams,
+ $this->user_comment
+ );
+
+ # protect/unprotect
+ $this->assertIRCComment(
+ $this->context->msg( 'unprotectedarticle', 'SomeTitle' )->plain() . $sep . $this->user_comment,
+ 'protect', 'unprotect',
+ array(),
+ $this->user_comment
+ );
+
+ # protect/modify
+ $this->assertIRCComment(
+ $this->context->msg( 'modifiedarticleprotection', 'SomeTitle ' . $protectParams[0] )
+ ->plain() . $sep . $this->user_comment,
+ 'protect', 'modify',
+ $protectParams,
+ $this->user_comment
+ );
+
+ # protect/move_prot
+ $this->assertIRCComment(
+ $this->context->msg( 'movedarticleprotection', 'SomeTitle', 'OldTitle' )
+ ->plain() . $sep . $this->user_comment,
+ 'protect', 'move_prot',
+ array(
+ '4::oldtitle' => 'OldTitle'
+ ),
+ $this->user_comment
+ );
+ }
+
+ /**
+ * @covers LogFormatter::getIRCActionComment
+ * @covers LogFormatter::getIRCActionText
+ */
+ public function testIrcMsgForLogTypeUpload() {
+ $sep = $this->context->msg( 'colon-separator' )->text();
+
+ # upload/upload
+ $this->assertIRCComment(
+ $this->context->msg( 'uploadedimage', 'SomeTitle' )->plain() . $sep . $this->user_comment,
+ 'upload', 'upload',
+ array(),
+ $this->user_comment
+ );
+
+ # upload/overwrite
+ $this->assertIRCComment(
+ $this->context->msg( 'overwroteimage', 'SomeTitle' )->plain() . $sep . $this->user_comment,
+ 'upload', 'overwrite',
+ array(),
+ $this->user_comment
+ );
+ }
+
+ /**
+ * @covers LogFormatter::getIRCActionComment
+ * @covers LogFormatter::getIRCActionText
+ */
+ public function testIrcMsgForLogTypeMerge() {
+ $sep = $this->context->msg( 'colon-separator' )->text();
+
+ # merge/merge
+ $this->assertIRCComment(
+ $this->context->msg( 'pagemerge-logentry', 'SomeTitle', 'Dest', 'timestamp' )->plain()
+ . $sep . $this->user_comment,
+ 'merge', 'merge',
+ array(
+ '4::dest' => 'Dest',
+ '5::mergepoint' => 'timestamp',
+ ),
+ $this->user_comment
+ );
+ }
+
+ /**
+ * @covers LogFormatter::getIRCActionComment
+ * @covers LogFormatter::getIRCActionText
+ */
+ public function testIrcMsgForLogTypeImport() {
+ $sep = $this->context->msg( 'colon-separator' )->text();
+
+ # import/upload
+ $msg = $this->context->msg( 'import-logentry-upload', 'SomeTitle' )->plain() .
+ $sep .
+ $this->user_comment;
+ $this->assertIRCComment(
+ $msg,
+ 'import', 'upload',
+ array(),
+ $this->user_comment
+ );
+
+ # import/interwiki
+ $msg = $this->context->msg( 'import-logentry-interwiki', 'SomeTitle' )->plain() .
+ $sep .
+ $this->user_comment;
+ $this->assertIRCComment(
+ $msg,
+ 'import', 'interwiki',
+ array(),
+ $this->user_comment
+ );
+ }
+
+ /**
+ * @param string $expected Expected IRC text without colors codes
+ * @param string $type Log type (move, delete, suppress, patrol ...)
+ * @param string $action A log type action
+ * @param array $params
+ * @param string $comment (optional) A comment for the log action
+ * @param string $msg (optional) A message for PHPUnit :-)
+ */
+ protected function assertIRCComment( $expected, $type, $action, $params,
+ $comment = null, $msg = '', $legacy = false
+ ) {
+ $logEntry = new ManualLogEntry( $type, $action );
+ $logEntry->setPerformer( $this->user );
+ $logEntry->setTarget( $this->title );
+ if ( $comment !== null ) {
+ $logEntry->setComment( $comment );
+ }
+ $logEntry->setParameters( $params );
+ $logEntry->setLegacy( $legacy );
+
+ $formatter = LogFormatter::newFromEntry( $logEntry );
+ $formatter->setContext( $this->context );
+
+ // Apply the same transformation as done in IRCColourfulRCFeedFormatter::getLine for rc_comment
+ $ircRcComment = IRCColourfulRCFeedFormatter::cleanupForIRC( $formatter->getIRCActionComment() );
+
+ $this->assertEquals(
+ $expected,
+ $ircRcComment,
+ $msg
+ );
+ }
+
}
diff --git a/tests/phpunit/includes/logging/LogFormatterTestCase.php b/tests/phpunit/includes/logging/LogFormatterTestCase.php
new file mode 100644
index 00000000..e88452b7
--- /dev/null
+++ b/tests/phpunit/includes/logging/LogFormatterTestCase.php
@@ -0,0 +1,65 @@
+expandDatabaseRow( $row, $this->isLegacy( $extra ) );
+
+ $formatter = LogFormatter::newFromRow( $row );
+
+ $this->assertEquals(
+ $extra['text'],
+ self::removeSomeHtml( $formatter->getActionText() ),
+ 'Action text is equal to expected text'
+ );
+
+ $this->assertSame( // ensure types and array key order
+ $extra['api'],
+ self::removeApiMetaData( $formatter->formatParametersForApi() ),
+ 'Api log params is equal to expected array'
+ );
+ }
+
+ protected function isLegacy( $extra ) {
+ return isset( $extra['legacy'] ) && $extra['legacy'];
+ }
+
+ protected function expandDatabaseRow( $data, $legacy ) {
+ return array(
+ // no log_id because no insert in database
+ 'log_type' => $data['type'],
+ 'log_action' => $data['action'],
+ 'log_timestamp' => isset( $data['timestamp'] ) ? $data['timestamp'] : wfTimestampNow(),
+ 'log_user' => isset( $data['user'] ) ? $data['user'] : 0,
+ 'log_user_text' => isset( $data['user_text'] ) ? $data['user_text'] : 'User',
+ 'log_namespace' => isset( $data['namespace'] ) ? $data['namespace'] : NS_MAIN,
+ 'log_title' => isset( $data['title'] ) ? $data['title'] : 'Main_Page',
+ 'log_page' => isset( $data['page'] ) ? $data['page'] : 0,
+ 'log_comment' => isset( $data['comment'] ) ? $data['comment'] : '',
+ 'log_params' => $legacy
+ ? LogPage::makeParamBlob( $data['params'] )
+ : LogEntryBase::makeParamBlob( $data['params'] ),
+ 'log_deleted' => isset( $data['deleted'] ) ? $data['deleted'] : 0,
+ );
+ }
+
+ private static function removeSomeHtml( $html ) {
+ $html = str_replace( '"', '"', $html );
+ return trim( preg_replace( '/<(a|span)[^>]*>([^<]*)<\/\1>/', '$2', $html ) );
+ }
+
+ private static function removeApiMetaData( $val ) {
+ if ( is_array( $val ) ) {
+ unset( $val['_element'] );
+ unset( $val['_type'] );
+ foreach ( $val as $key => $value ) {
+ $val[$key] = self::removeApiMetaData( $value );
+ }
+ }
+ return $val;
+ }
+}
diff --git a/tests/phpunit/includes/logging/MergeLogFormatterTest.php b/tests/phpunit/includes/logging/MergeLogFormatterTest.php
new file mode 100644
index 00000000..2ff0ddf5
--- /dev/null
+++ b/tests/phpunit/includes/logging/MergeLogFormatterTest.php
@@ -0,0 +1,67 @@
+ 'merge',
+ 'action' => 'merge',
+ 'comment' => 'Merge comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'OldPage',
+ 'params' => array(
+ '4::dest' => 'NewPage',
+ '5::mergepoint' => '20140804160710',
+ ),
+ ),
+ array(
+ 'text' => 'User merged OldPage into NewPage (revisions up to 16:07, 4 August 2014)',
+ 'api' => array(
+ 'dest_ns' => 0,
+ 'dest_title' => 'NewPage',
+ 'mergepoint' => '2014-08-04T16:07:10Z',
+ ),
+ ),
+ ),
+
+ // Legacy format
+ array(
+ array(
+ 'type' => 'merge',
+ 'action' => 'merge',
+ 'comment' => 'merge comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'OldPage',
+ 'params' => array(
+ 'NewPage',
+ '20140804160710',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User merged OldPage into NewPage (revisions up to 16:07, 4 August 2014)',
+ 'api' => array(
+ 'dest_ns' => 0,
+ 'dest_title' => 'NewPage',
+ 'mergepoint' => '2014-08-04T16:07:10Z',
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideMergeLogDatabaseRows
+ */
+ public function testMergeLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+}
diff --git a/tests/phpunit/includes/logging/MoveLogFormatterTest.php b/tests/phpunit/includes/logging/MoveLogFormatterTest.php
new file mode 100644
index 00000000..fdc4b7e1
--- /dev/null
+++ b/tests/phpunit/includes/logging/MoveLogFormatterTest.php
@@ -0,0 +1,270 @@
+ 'move',
+ 'action' => 'move',
+ 'comment' => 'move comment with redirect',
+ 'namespace' => NS_MAIN,
+ 'title' => 'OldPage',
+ 'params' => array(
+ '4::target' => 'NewPage',
+ '5::noredir' => '0',
+ ),
+ ),
+ array(
+ 'text' => 'User moved page OldPage to NewPage',
+ 'api' => array(
+ 'target_ns' => 0,
+ 'target_title' => 'NewPage',
+ 'suppressredirect' => false,
+ ),
+ ),
+ ),
+
+ // Current format - without redirect
+ array(
+ array(
+ 'type' => 'move',
+ 'action' => 'move',
+ 'comment' => 'move comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'OldPage',
+ 'params' => array(
+ '4::target' => 'NewPage',
+ '5::noredir' => '1',
+ ),
+ ),
+ array(
+ 'text' => 'User moved page OldPage to NewPage without leaving a redirect',
+ 'api' => array(
+ 'target_ns' => 0,
+ 'target_title' => 'NewPage',
+ 'suppressredirect' => true,
+ ),
+ ),
+ ),
+
+ // legacy format - with redirect
+ array(
+ array(
+ 'type' => 'move',
+ 'action' => 'move',
+ 'comment' => 'move comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'OldPage',
+ 'params' => array(
+ 'NewPage',
+ '',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User moved page OldPage to NewPage',
+ 'api' => array(
+ 'target_ns' => 0,
+ 'target_title' => 'NewPage',
+ 'suppressredirect' => false,
+ ),
+ ),
+ ),
+
+ // legacy format - without redirect
+ array(
+ array(
+ 'type' => 'move',
+ 'action' => 'move',
+ 'comment' => 'move comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'OldPage',
+ 'params' => array(
+ 'NewPage',
+ '1',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User moved page OldPage to NewPage without leaving a redirect',
+ 'api' => array(
+ 'target_ns' => 0,
+ 'target_title' => 'NewPage',
+ 'suppressredirect' => true,
+ ),
+ ),
+ ),
+
+ // old format without flag for redirect suppression
+ array(
+ array(
+ 'type' => 'move',
+ 'action' => 'move',
+ 'comment' => 'move comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'OldPage',
+ 'params' => array(
+ 'NewPage',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User moved page OldPage to NewPage',
+ 'api' => array(
+ 'target_ns' => 0,
+ 'target_title' => 'NewPage',
+ 'suppressredirect' => false,
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideMoveLogDatabaseRows
+ */
+ public function testMoveLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideMoveRedirLogDatabaseRows() {
+ return array(
+ // Current format - with redirect
+ array(
+ array(
+ 'type' => 'move',
+ 'action' => 'move_redir',
+ 'comment' => 'move comment with redirect',
+ 'namespace' => NS_MAIN,
+ 'title' => 'OldPage',
+ 'params' => array(
+ '4::target' => 'NewPage',
+ '5::noredir' => '0',
+ ),
+ ),
+ array(
+ 'text' => 'User moved page OldPage to NewPage over redirect',
+ 'api' => array(
+ 'target_ns' => 0,
+ 'target_title' => 'NewPage',
+ 'suppressredirect' => false,
+ ),
+ ),
+ ),
+
+ // Current format - without redirect
+ array(
+ array(
+ 'type' => 'move',
+ 'action' => 'move_redir',
+ 'comment' => 'move comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'OldPage',
+ 'params' => array(
+ '4::target' => 'NewPage',
+ '5::noredir' => '1',
+ ),
+ ),
+ array(
+ 'text' => 'User moved page OldPage to NewPage over a redirect without leaving a redirect',
+ 'api' => array(
+ 'target_ns' => 0,
+ 'target_title' => 'NewPage',
+ 'suppressredirect' => true,
+ ),
+ ),
+ ),
+
+ // legacy format - with redirect
+ array(
+ array(
+ 'type' => 'move',
+ 'action' => 'move_redir',
+ 'comment' => 'move comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'OldPage',
+ 'params' => array(
+ 'NewPage',
+ '',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User moved page OldPage to NewPage over redirect',
+ 'api' => array(
+ 'target_ns' => 0,
+ 'target_title' => 'NewPage',
+ 'suppressredirect' => false,
+ ),
+ ),
+ ),
+
+ // legacy format - without redirect
+ array(
+ array(
+ 'type' => 'move',
+ 'action' => 'move_redir',
+ 'comment' => 'move comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'OldPage',
+ 'params' => array(
+ 'NewPage',
+ '1',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User moved page OldPage to NewPage over a redirect without leaving a redirect',
+ 'api' => array(
+ 'target_ns' => 0,
+ 'target_title' => 'NewPage',
+ 'suppressredirect' => true,
+ ),
+ ),
+ ),
+
+ // old format without flag for redirect suppression
+ array(
+ array(
+ 'type' => 'move',
+ 'action' => 'move_redir',
+ 'comment' => 'move comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'OldPage',
+ 'params' => array(
+ 'NewPage',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User moved page OldPage to NewPage over redirect',
+ 'api' => array(
+ 'target_ns' => 0,
+ 'target_title' => 'NewPage',
+ 'suppressredirect' => false,
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideMoveRedirLogDatabaseRows
+ */
+ public function testMoveRedirLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+}
diff --git a/tests/phpunit/includes/logging/NewUsersLogFormatterTest.php b/tests/phpunit/includes/logging/NewUsersLogFormatterTest.php
new file mode 100644
index 00000000..5b03370d
--- /dev/null
+++ b/tests/phpunit/includes/logging/NewUsersLogFormatterTest.php
@@ -0,0 +1,207 @@
+mergeMwGlobalArrayValue( 'wgLogActionsHandlers', array(
+ 'newusers/newusers' => 'NewUsersLogFormatter',
+ 'newusers/create' => 'NewUsersLogFormatter',
+ 'newusers/create2' => 'NewUsersLogFormatter',
+ 'newusers/byemail' => 'NewUsersLogFormatter',
+ 'newusers/autocreate' => 'NewUsersLogFormatter',
+ ) );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideNewUsersLogDatabaseRows() {
+ return array(
+ // Only old logs
+ array(
+ array(
+ 'type' => 'newusers',
+ 'action' => 'newusers',
+ 'comment' => 'newusers comment',
+ 'user' => 0,
+ 'user_text' => 'New user',
+ 'namespace' => NS_USER,
+ 'title' => 'New user',
+ 'params' => array(),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User account New user was created',
+ 'api' => array(),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideNewUsersLogDatabaseRows
+ */
+ public function testNewUsersLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideCreateLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'newusers',
+ 'action' => 'create',
+ 'comment' => 'newusers comment',
+ 'user' => 0,
+ 'user_text' => 'New user',
+ 'namespace' => NS_USER,
+ 'title' => 'New user',
+ 'params' => array(
+ '4::userid' => 1,
+ ),
+ ),
+ array(
+ 'text' => 'User account New user was created',
+ 'api' => array(
+ 'userid' => 1,
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideCreateLogDatabaseRows
+ */
+ public function testCreateLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideCreate2LogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'newusers',
+ 'action' => 'create2',
+ 'comment' => 'newusers comment',
+ 'user' => 0,
+ 'user_text' => 'User',
+ 'namespace' => NS_USER,
+ 'title' => 'UTSysop',
+ 'params' => array(
+ '4::userid' => 1,
+ ),
+ ),
+ array(
+ 'text' => 'User account UTSysop was created by User',
+ 'api' => array(
+ 'userid' => 1,
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideCreate2LogDatabaseRows
+ */
+ public function testCreate2LogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideByemailLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'newusers',
+ 'action' => 'byemail',
+ 'comment' => 'newusers comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'UTSysop',
+ 'params' => array(
+ '4::userid' => 1,
+ ),
+ ),
+ array(
+ 'text' => 'User account UTSysop was created by Sysop and password was sent by email',
+ 'api' => array(
+ 'userid' => 1,
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideByemailLogDatabaseRows
+ */
+ public function testByemailLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideAutocreateLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'newusers',
+ 'action' => 'autocreate',
+ 'comment' => 'newusers comment',
+ 'user' => 0,
+ 'user_text' => 'New user',
+ 'namespace' => NS_USER,
+ 'title' => 'New user',
+ 'params' => array(
+ '4::userid' => 1,
+ ),
+ ),
+ array(
+ 'text' => 'User account New user was created automatically',
+ 'api' => array(
+ 'userid' => 1,
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideAutocreateLogDatabaseRows
+ */
+ public function testAutocreateLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+}
diff --git a/tests/phpunit/includes/logging/PageLangLogFormatterTest.php b/tests/phpunit/includes/logging/PageLangLogFormatterTest.php
new file mode 100644
index 00000000..226e492b
--- /dev/null
+++ b/tests/phpunit/includes/logging/PageLangLogFormatterTest.php
@@ -0,0 +1,53 @@
+setMwGlobals( 'wgHooks', array() );
+ // Register LogHandler, see $wgPageLanguageUseDB in Setup.php
+ $this->mergeMwGlobalArrayValue( 'wgLogActionsHandlers', array(
+ 'pagelang/pagelang' => 'PageLangLogFormatter',
+ ) );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function providePageLangLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'pagelang',
+ 'action' => 'pagelang',
+ 'comment' => 'page lang comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(
+ '4::oldlanguage' => 'en',
+ '5::newlanguage' => 'de[def]',
+ ),
+ ),
+ array(
+ 'text' => 'User changed page language for Page from English (en) to Deutsch (de) [default].',
+ 'api' => array(
+ 'oldlanguage' => 'en',
+ 'newlanguage' => 'de[def]'
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider providePageLangLogDatabaseRows
+ */
+ public function testPageLangLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+}
diff --git a/tests/phpunit/includes/logging/PatrolLogFormatterTest.php b/tests/phpunit/includes/logging/PatrolLogFormatterTest.php
new file mode 100644
index 00000000..6e1c5efc
--- /dev/null
+++ b/tests/phpunit/includes/logging/PatrolLogFormatterTest.php
@@ -0,0 +1,118 @@
+ 'patrol',
+ 'action' => 'patrol',
+ 'comment' => 'patrol comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(
+ '4::curid' => 2,
+ '5::previd' => 1,
+ '6::auto' => 0,
+ ),
+ ),
+ array(
+ 'text' => 'User marked revision 2 of page Page patrolled',
+ 'api' => array(
+ 'curid' => 2,
+ 'previd' => 1,
+ 'auto' => false,
+ ),
+ ),
+ ),
+
+ // Current format - autopatrol
+ array(
+ array(
+ 'type' => 'patrol',
+ 'action' => 'patrol',
+ 'comment' => 'patrol comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(
+ '4::curid' => 2,
+ '5::previd' => 1,
+ '6::auto' => 1,
+ ),
+ ),
+ array(
+ 'text' => 'User automatically marked revision 2 of page Page patrolled',
+ 'api' => array(
+ 'curid' => 2,
+ 'previd' => 1,
+ 'auto' => true,
+ ),
+ ),
+ ),
+
+ // Legacy format
+ array(
+ array(
+ 'type' => 'patrol',
+ 'action' => 'patrol',
+ 'comment' => 'patrol comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(
+ '2',
+ '1',
+ '0',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User marked revision 2 of page Page patrolled',
+ 'api' => array(
+ 'curid' => 2,
+ 'previd' => 1,
+ 'auto' => false,
+ ),
+ ),
+ ),
+
+ // Legacy format - autopatrol
+ array(
+ array(
+ 'type' => 'patrol',
+ 'action' => 'patrol',
+ 'comment' => 'patrol comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'Page',
+ 'params' => array(
+ '2',
+ '1',
+ '1',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User automatically marked revision 2 of page Page patrolled',
+ 'api' => array(
+ 'curid' => 2,
+ 'previd' => 1,
+ 'auto' => true,
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider providePatrolLogDatabaseRows
+ */
+ public function testPatrolLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+}
diff --git a/tests/phpunit/includes/logging/ProtectLogFormatterTest.php b/tests/phpunit/includes/logging/ProtectLogFormatterTest.php
new file mode 100644
index 00000000..611b2dfc
--- /dev/null
+++ b/tests/phpunit/includes/logging/ProtectLogFormatterTest.php
@@ -0,0 +1,63 @@
+ 'protect',
+ 'action' => 'move_prot',
+ 'comment' => 'Move comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'NewPage',
+ 'params' => array(
+ '4::oldtitle' => 'OldPage',
+ ),
+ ),
+ array(
+ 'text' => 'User moved protection settings from OldPage to NewPage',
+ 'api' => array(
+ 'oldtitle_ns' => 0,
+ 'oldtitle_title' => 'OldPage',
+ ),
+ ),
+ ),
+
+ // Legacy format
+ array(
+ array(
+ 'type' => 'protect',
+ 'action' => 'move_prot',
+ 'comment' => 'Move comment',
+ 'namespace' => NS_MAIN,
+ 'title' => 'NewPage',
+ 'params' => array(
+ 'OldPage',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'User moved protection settings from OldPage to NewPage',
+ 'api' => array(
+ 'oldtitle_ns' => 0,
+ 'oldtitle_title' => 'OldPage',
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideMoveProtLogDatabaseRows
+ */
+ public function testMoveProtLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+}
diff --git a/tests/phpunit/includes/logging/RightsLogFormatterTest.php b/tests/phpunit/includes/logging/RightsLogFormatterTest.php
new file mode 100644
index 00000000..e9577f11
--- /dev/null
+++ b/tests/phpunit/includes/logging/RightsLogFormatterTest.php
@@ -0,0 +1,157 @@
+ 'rights',
+ 'action' => 'rights',
+ 'comment' => 'rights comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'User',
+ 'params' => array(
+ '4::oldgroups' => array(),
+ '5::newgroups' => array( 'sysop', 'bureaucrat' ),
+ ),
+ ),
+ array(
+ 'text' => 'Sysop changed group membership for User:User from (none) to '
+ . 'administrator and bureaucrat',
+ 'api' => array(
+ 'oldgroups' => array(),
+ 'newgroups' => array( 'sysop', 'bureaucrat' ),
+ ),
+ ),
+ ),
+
+ // Legacy format
+ array(
+ array(
+ 'type' => 'rights',
+ 'action' => 'rights',
+ 'comment' => 'rights comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'User',
+ 'params' => array(
+ '',
+ 'sysop, bureaucrat',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'Sysop changed group membership for User:User from (none) to '
+ . 'administrator and bureaucrat',
+ 'api' => array(
+ 'oldgroups' => array(),
+ 'newgroups' => array( 'sysop', 'bureaucrat' ),
+ ),
+ ),
+ ),
+
+ // Really old entry
+ array(
+ array(
+ 'type' => 'rights',
+ 'action' => 'rights',
+ 'comment' => 'rights comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'User',
+ 'params' => array(),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'Sysop changed group membership for User:User',
+ 'api' => array(),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideRightsLogDatabaseRows
+ */
+ public function testRightsLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideAutopromoteLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'rights',
+ 'action' => 'autopromote',
+ 'comment' => 'rights comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Sysop',
+ 'params' => array(
+ '4::oldgroups' => array( 'sysop' ),
+ '5::newgroups' => array( 'sysop', 'bureaucrat' ),
+ ),
+ ),
+ array(
+ 'text' => 'Sysop was automatically promoted from administrator to '
+ . 'administrator and bureaucrat',
+ 'api' => array(
+ 'oldgroups' => array( 'sysop' ),
+ 'newgroups' => array( 'sysop', 'bureaucrat' ),
+ ),
+ ),
+ ),
+
+ // Legacy format
+ array(
+ array(
+ 'type' => 'rights',
+ 'action' => 'autopromote',
+ 'comment' => 'rights comment',
+ 'user' => 0,
+ 'user_text' => 'Sysop',
+ 'namespace' => NS_USER,
+ 'title' => 'Sysop',
+ 'params' => array(
+ 'sysop',
+ 'sysop, bureaucrat',
+ ),
+ ),
+ array(
+ 'legacy' => true,
+ 'text' => 'Sysop was automatically promoted from administrator to '
+ . 'administrator and bureaucrat',
+ 'api' => array(
+ 'oldgroups' => array( 'sysop' ),
+ 'newgroups' => array( 'sysop', 'bureaucrat' ),
+ ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideAutopromoteLogDatabaseRows
+ */
+ public function testAutopromoteLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+}
diff --git a/tests/phpunit/includes/logging/UploadLogFormatterTest.php b/tests/phpunit/includes/logging/UploadLogFormatterTest.php
new file mode 100644
index 00000000..12f51613
--- /dev/null
+++ b/tests/phpunit/includes/logging/UploadLogFormatterTest.php
@@ -0,0 +1,166 @@
+ 'upload',
+ 'action' => 'upload',
+ 'comment' => 'upload comment',
+ 'namespace' => NS_FILE,
+ 'title' => 'File.png',
+ 'params' => array(
+ 'img_sha1' => 'hash',
+ 'img_timestamp' => '20150101000000',
+ ),
+ ),
+ array(
+ 'text' => 'User uploaded File:File.png',
+ 'api' => array(
+ 'img_sha1' => 'hash',
+ 'img_timestamp' => '2015-01-01T00:00:00Z',
+ ),
+ ),
+ ),
+
+ // Old format without params
+ array(
+ array(
+ 'type' => 'upload',
+ 'action' => 'upload',
+ 'comment' => 'upload comment',
+ 'namespace' => NS_FILE,
+ 'title' => 'File.png',
+ 'params' => array(),
+ ),
+ array(
+ 'text' => 'User uploaded File:File.png',
+ 'api' => array(),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideUploadLogDatabaseRows
+ */
+ public function testUploadLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideOverwriteLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'upload',
+ 'action' => 'overwrite',
+ 'comment' => 'upload comment',
+ 'namespace' => NS_FILE,
+ 'title' => 'File.png',
+ 'params' => array(
+ 'img_sha1' => 'hash',
+ 'img_timestamp' => '20150101000000',
+ ),
+ ),
+ array(
+ 'text' => 'User uploaded a new version of File:File.png',
+ 'api' => array(
+ 'img_sha1' => 'hash',
+ 'img_timestamp' => '2015-01-01T00:00:00Z',
+ ),
+ ),
+ ),
+
+ // Old format without params
+ array(
+ array(
+ 'type' => 'upload',
+ 'action' => 'overwrite',
+ 'comment' => 'upload comment',
+ 'namespace' => NS_FILE,
+ 'title' => 'File.png',
+ 'params' => array(),
+ ),
+ array(
+ 'text' => 'User uploaded a new version of File:File.png',
+ 'api' => array(),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideOverwriteLogDatabaseRows
+ */
+ public function testOverwriteLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+
+ /**
+ * Provide different rows from the logging table to test
+ * for backward compatibility.
+ * Do not change the existing data, just add a new database row
+ */
+ public static function provideRevertLogDatabaseRows() {
+ return array(
+ // Current format
+ array(
+ array(
+ 'type' => 'upload',
+ 'action' => 'revert',
+ 'comment' => 'upload comment',
+ 'namespace' => NS_FILE,
+ 'title' => 'File.png',
+ 'params' => array(
+ 'img_sha1' => 'hash',
+ 'img_timestamp' => '20150101000000',
+ ),
+ ),
+ array(
+ 'text' => 'User uploaded File:File.png',
+ 'api' => array(
+ 'img_sha1' => 'hash',
+ 'img_timestamp' => '2015-01-01T00:00:00Z',
+ ),
+ ),
+ ),
+
+ // Old format without params
+ array(
+ array(
+ 'type' => 'upload',
+ 'action' => 'revert',
+ 'comment' => 'upload comment',
+ 'namespace' => NS_FILE,
+ 'title' => 'File.png',
+ 'params' => array(),
+ ),
+ array(
+ 'text' => 'User uploaded File:File.png',
+ 'api' => array(),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider provideRevertLogDatabaseRows
+ */
+ public function testRevertLogDatabaseRows( $row, $extra ) {
+ $this->doTestLogFormatter( $row, $extra );
+ }
+}
diff --git a/tests/phpunit/includes/media/ExifBitmapTest.php b/tests/phpunit/includes/media/ExifBitmapTest.php
index 41330f41..adbc9775 100644
--- a/tests/phpunit/includes/media/ExifBitmapTest.php
+++ b/tests/phpunit/includes/media/ExifBitmapTest.php
@@ -3,7 +3,7 @@
/**
* @group Media
*/
-class ExifBitmapTest extends MediaWikiTestCase {
+class ExifBitmapTest extends MediaWikiMediaTestCase {
/**
* @var ExifBitmapHandler
@@ -143,4 +143,41 @@ class ExifBitmapTest extends MediaWikiTestCase {
$res = $this->handler->convertMetadataVersion( $metadata, 1 );
$this->assertEquals( $expected, $res );
}
+
+ /**
+ * @dataProvider provideSwappingICCProfile
+ * @covers BitmapHandler::swapICCProfile
+ */
+ public function testSwappingICCProfile( $sourceFilename, $controlFilename, $newProfileFilename, $oldProfileName ) {
+ global $wgExiftool;
+
+ if ( !$wgExiftool || !is_file( $wgExiftool ) ) {
+ $this->markTestSkipped( "Exiftool not installed, cannot test ICC profile swapping" );
+ }
+
+ $this->setMwGlobals( 'wgUseTinyRGBForJPGThumbnails', true );
+
+ $sourceFilepath = $this->filePath . $sourceFilename;
+ $controlFilepath = $this->filePath . $controlFilename;
+ $profileFilepath = $this->filePath . $newProfileFilename;
+ $filepath = $this->getNewTempFile();
+
+ copy( $sourceFilepath, $filepath );
+
+ $file = $this->dataFile( $sourceFilename, 'image/jpeg' );
+ $this->handler->swapICCProfile( $filepath, $oldProfileName, $profileFilepath );
+
+ $this->assertEquals( sha1( file_get_contents( $filepath ) ), sha1( file_get_contents( $controlFilepath ) ) );
+ }
+
+ public function provideSwappingICCProfile() {
+ return array(
+ // File with sRGB should end up with TinyRGB
+ array( 'srgb.jpg', 'tinyrgb.jpg', 'tinyrgb.icc', 'IEC 61966-2.1 Default RGB colour space - sRGB' ),
+ // File with TinyRGB should be left unchanged
+ array( 'tinyrgb.jpg', 'tinyrgb.jpg', 'tinyrgb.icc', 'IEC 61966-2.1 Default RGB colour space - sRGB' ),
+ // File with no profile should be left unchanged
+ array( 'test.jpg', 'test.jpg', 'tinyrgb.icc', 'IEC 61966-2.1 Default RGB colour space - sRGB' )
+ );
+ }
}
diff --git a/tests/phpunit/includes/media/FormatMetadataTest.php b/tests/phpunit/includes/media/FormatMetadataTest.php
index 54758f94..b666c83c 100644
--- a/tests/phpunit/includes/media/FormatMetadataTest.php
+++ b/tests/phpunit/includes/media/FormatMetadataTest.php
@@ -36,39 +36,6 @@ class FormatMetadataTest extends MediaWikiMediaTestCase {
'File with invalid date metadata (bug 29471)' );
}
- /**
- * @param string $filename
- * @param int $expected Total image area
- * @dataProvider provideFlattenArray
- * @covers FormatMetadata::flattenArray
- */
- public function testFlattenArray( $vals, $type, $noHtml, $ctx, $expected ) {
- $actual = FormatMetadata::flattenArray( $vals, $type, $noHtml, $ctx );
- $this->assertEquals( $expected, $actual );
- }
-
- public static function provideFlattenArray() {
- return array(
- array(
- array( 1, 2, 3 ), 'ul', false, false,
- "",
- ),
- array(
- array( 1, 2, 3 ), 'ol', false, false,
- "1 \n2 \n3 ",
- ),
- array(
- array( 1, 2, 3 ), 'ul', true, false,
- "\n*1\n*2\n*3",
- ),
- array(
- array( 1, 2, 3 ), 'ol', true, false,
- "\n#1\n#2\n#3",
- ),
- // TODO: more test cases
- );
- }
-
/**
* @param mixed $input
* @param mixed $output
diff --git a/tests/phpunit/includes/media/WebPTest.php b/tests/phpunit/includes/media/WebPTest.php
new file mode 100644
index 00000000..d36710a3
--- /dev/null
+++ b/tests/phpunit/includes/media/WebPTest.php
@@ -0,0 +1,127 @@
+tempFileName = tempnam( wfTempDir(), 'WEBP' );
+ }
+ public function tearDown() {
+ parent::tearDown();
+ unlink( $this->tempFileName );
+ }
+ /**
+ * @dataProvider provideTestExtractMetaData
+ */
+ public function testExtractMetaData( $header, $expectedResult ) {
+ // Put header into file
+ file_put_contents( $this->tempFileName, $header );
+
+ $this->assertEquals( $expectedResult, WebPHandler::extractMetadata( $this->tempFileName ) );
+ }
+ public function provideTestExtractMetaData() {
+ return array(
+ // Files from https://developers.google.com/speed/webp/gallery2
+ array( "\x52\x49\x46\x46\x90\x68\x01\x00\x57\x45\x42\x50\x56\x50\x38\x4C\x83\x68\x01\x00\x2F\x8F\x01\x4B\x10\x8D\x38\x6C\xDB\x46\x92\xE0\xE0\x82\x7B\x6C",
+ array( 'compression' => 'lossless', 'width' => 400, 'height' => 301 ) ),
+ array( "\x52\x49\x46\x46\x64\x5B\x00\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\x8F\x01\x00\x2C\x01\x00\x41\x4C\x50\x48\xE5\x0E",
+ array( 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 400, 'height' => 301) ),
+ array( "\x52\x49\x46\x46\xA8\x72\x00\x00\x57\x45\x42\x50\x56\x50\x38\x4C\x9B\x72\x00\x00\x2F\x81\x81\x62\x10\x8D\x40\x8C\x24\x39\x6E\x73\x73\x38\x01\x96",
+ array( 'compression' => 'lossless', 'width' => 386, 'height' => 395 ) ),
+ array( "\x52\x49\x46\x46\xE0\x42\x00\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\x81\x01\x00\x8A\x01\x00\x41\x4C\x50\x48\x56\x10",
+ array( 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 386, 'height' => 395 ) ),
+ array( "\x52\x49\x46\x46\x70\x61\x02\x00\x57\x45\x42\x50\x56\x50\x38\x4C\x63\x61\x02\x00\x2F\x1F\xC3\x95\x10\x8D\xC8\x72\xDB\xC8\x92\x24\xD8\x91\xD9\x91",
+ array( 'compression' => 'lossless', 'width' => 800, 'height' => 600 ) ),
+ array( "\x52\x49\x46\x46\x1C\x1D\x01\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\x1F\x03\x00\x57\x02\x00\x41\x4C\x50\x48\x25\x8B",
+ array( 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 800, 'height' => 600 ) ),
+ array( "\x52\x49\x46\x46\xFA\xC5\x00\x00\x57\x45\x42\x50\x56\x50\x38\x4C\xEE\xC5\x00\x00\x2F\xA4\x81\x28\x10\x8D\x40\x68\x24\xC9\x91\xA4\xAE\xF3\x97\x75",
+ array( 'compression' => 'lossless', 'width' => 421, 'height' => 163 ) ),
+ array( "\x52\x49\x46\x46\xF6\x5D\x00\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\xA4\x01\x00\xA2\x00\x00\x41\x4C\x50\x48\x38\x1A",
+ array( 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 421, 'height' => 163 ) ),
+ array( "\x52\x49\x46\x46\xC4\x96\x01\x00\x57\x45\x42\x50\x56\x50\x38\x4C\xB8\x96\x01\x00\x2F\x2B\xC1\x4A\x10\x11\x87\x6D\xDB\x48\x12\xFC\x60\xB0\x83\x24",
+ array( 'compression' => 'lossless', 'width' => 300, 'height' => 300 ) ),
+ array( "\x52\x49\x46\x46\x0A\x11\x01\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\x2B\x01\x00\x2B\x01\x00\x41\x4C\x50\x48\x67\x6E",
+ array( 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 300, 'height' => 300 ) ),
+
+ // Lossy files from https://developers.google.com/speed/webp/gallery1
+ array( "\x52\x49\x46\x46\x68\x76\x00\x00\x57\x45\x42\x50\x56\x50\x38\x20\x5C\x76\x00\x00\xD2\xBE\x01\x9D\x01\x2A\x26\x02\x70\x01\x3E\xD5\x4E\x97\x43\xA2",
+ array( 'compression' => 'lossy', 'width' => 550, 'height' => 368 ) ),
+ array( "\x52\x49\x46\x46\xB0\xEC\x00\x00\x57\x45\x42\x50\x56\x50\x38\x20\xA4\xEC\x00\x00\xB2\x4B\x02\x9D\x01\x2A\x26\x02\x94\x01\x3E\xD1\x50\x96\x46\x26",
+ array( 'compression' => 'lossy', 'width' => 550, 'height' => 404 ) ),
+ array( "\x52\x49\x46\x46\x7A\x19\x03\x00\x57\x45\x42\x50\x56\x50\x38\x20\x6E\x19\x03\x00\xB2\xF8\x09\x9D\x01\x2A\x00\x05\xD0\x02\x3E\xAD\x46\x99\x4A\xA5",
+ array( 'compression' => 'lossy', 'width' => 1280, 'height' => 720 ) ),
+ array( "\x52\x49\x46\x46\x44\xB3\x02\x00\x57\x45\x42\x50\x56\x50\x38\x20\x38\xB3\x02\x00\x52\x57\x06\x9D\x01\x2A\x00\x04\x04\x03\x3E\xA5\x44\x96\x49\x26",
+ array( 'compression' => 'lossy', 'width' => 1024, 'height' => 772) ),
+ array( "\x52\x49\x46\x46\x02\x43\x01\x00\x57\x45\x42\x50\x56\x50\x38\x20\xF6\x42\x01\x00\x12\xC0\x05\x9D\x01\x2A\x00\x04\xF0\x02\x3E\x79\x34\x93\x47\xA4",
+ array( 'compression' => 'lossy', 'width' => 1024, 'height' => 752) ),
+
+ // Animated file from https://groups.google.com/a/chromium.org/d/topic/blink-dev/Y8tRC4mdQz8/discussion
+ array( "\x52\x49\x46\x46\xD0\x0B\x02\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x12\x00\x00\x00\x3F\x01\x00\x3F\x01\x00\x41\x4E",
+ array( 'compression' => 'unknown', 'animated' => true, 'transparency' => true, 'width' => 320, 'height' => 320 ) ),
+
+ // Error cases
+ array( '', false ),
+ array( ' ', false ),
+ array( 'RIFF ', false ),
+ array( 'RIFF1234WEBP ', false ),
+ array( 'RIFF1234WEBPVP8 ', false ),
+ array( 'RIFF1234WEBPVP8L ', false ),
+ );
+ }
+
+ /**
+ * @dataProvider provideTestWithFileExtractMetaData
+ */
+ public function testWithFileExtractMetaData( $filename, $expectedResult ) {
+ $this->assertEquals( $expectedResult, WebPHandler::extractMetadata( $filename ) );
+ }
+ public function provideTestWithFileExtractMetaData() {
+ return array(
+ array( __DIR__ . '/../../data/media/2_webp_ll.webp',
+ array( 'compression' => 'lossless', 'width' => 386, 'height' => 395 ) ),
+ array( __DIR__ . '/../../data/media/2_webp_a.webp',
+ array( 'compression' => 'lossy', 'animated' => false, 'transparency' => true, 'width' => 386, 'height' => 395 ) ),
+ );
+ }
+
+ /**
+ * @dataProvider provideTestGetImageSize
+ */
+ public function testGetImageSize( $path, $expectedResult ) {
+ $handler = new WebPHandler();
+ $this->assertEquals( $expectedResult, $handler->getImageSize( null, $path ) );
+ }
+ public function provideTestGetImageSize() {
+ return array(
+ // Public domain files from https://developers.google.com/speed/webp/gallery2
+ array( __DIR__ . '/../../data/media/2_webp_a.webp', array( 386, 395 ) ),
+ array( __DIR__ . '/../../data/media/2_webp_ll.webp', array( 386, 395 ) ),
+ array( __DIR__ . '/../../data/media/webp_animated.webp', array( 300, 225 ) ),
+
+ // Error cases
+ array( __FILE__, false ),
+ );
+ }
+
+ /**
+ * Tests the WebP MIME detection. This should really be a separate test, but sticking it
+ * here for now.
+ *
+ * @dataProvider provideTestGetMimeType
+ */
+ public function testGuessMimeType( $path ) {
+ $mime = MimeMagic::singleton();
+ $this->assertEquals( 'image/webp', $mime->guessMimeType( $path, false ) );
+ }
+ public function provideTestGetMimeType() {
+ return array(
+ // Public domain files from https://developers.google.com/speed/webp/gallery2
+ array( __DIR__ . '/../../data/media/2_webp_a.webp' ),
+ array( __DIR__ . '/../../data/media/2_webp_ll.webp' ),
+ array( __DIR__ . '/../../data/media/webp_animated.webp' ),
+ );
+ }
+}
+
+/* Python code to extract a header and convert to PHP format:
+ * print '"%s"' % ''.join( '\\x%02X' % ord(c) for c in urllib.urlopen(url).read(36) )
+ */
diff --git a/tests/phpunit/includes/media/XMPValidateTest.php b/tests/phpunit/includes/media/XMPValidateTest.php
index ebec8f6c..53671d42 100644
--- a/tests/phpunit/includes/media/XMPValidateTest.php
+++ b/tests/phpunit/includes/media/XMPValidateTest.php
@@ -1,5 +1,7 @@
validateDate( array(), $value, true );
$this->assertEquals( $expected, $value );
}
diff --git a/tests/phpunit/includes/objectcache/BagOStuffTest.php b/tests/phpunit/includes/objectcache/BagOStuffTest.php
index 4516bb4e..b6840062 100644
--- a/tests/phpunit/includes/objectcache/BagOStuffTest.php
+++ b/tests/phpunit/includes/objectcache/BagOStuffTest.php
@@ -1,8 +1,10 @@
+ * @group BagOStuff
*/
class BagOStuffTest extends MediaWikiTestCase {
+ /** @var BagOStuff */
private $cache;
protected function setUp() {
@@ -136,20 +138,48 @@ class BagOStuffTest extends MediaWikiTestCase {
public function testGetMulti() {
$value1 = array( 'this' => 'is', 'a' => 'test' );
$value2 = array( 'this' => 'is', 'another' => 'test' );
+ $value3 = array( 'testing a key that may be encoded when sent to cache backend' );
$key1 = wfMemcKey( 'test1' );
$key2 = wfMemcKey( 'test2' );
+ $key3 = wfMemcKey( 'will-%-encode' ); // internally, MemcachedBagOStuffs will encode to will-%25-encode
$this->cache->add( $key1, $value1 );
$this->cache->add( $key2, $value2 );
+ $this->cache->add( $key3, $value3 );
$this->assertEquals(
- $this->cache->getMulti( array( $key1, $key2 ) ),
- array( $key1 => $value1, $key2 => $value2 )
+ array( $key1 => $value1, $key2 => $value2, $key3 => $value3 ),
+ $this->cache->getMulti( array( $key1, $key2, $key3 ) )
);
// cleanup
$this->cache->delete( $key1 );
$this->cache->delete( $key2 );
+ $this->cache->delete( $key3 );
+ }
+
+ /**
+ * @covers BagOStuff::getScopedLock
+ */
+ public function testGetScopedLock() {
+ $key = wfMemcKey( 'test' );
+ $value1 = $this->cache->getScopedLock( $key, 0 );
+ $value2 = $this->cache->getScopedLock( $key, 0 );
+
+ $this->assertType( 'ScopedCallback', $value1, 'First call returned lock' );
+ $this->assertNull( $value2, 'Duplicate call returned no lock' );
+
+ unset( $value1 );
+
+ $value3 = $this->cache->getScopedLock( $key, 0 );
+ $this->assertType( 'ScopedCallback', $value3, 'Lock returned callback after release' );
+ unset( $value3 );
+
+ $value1 = $this->cache->getScopedLock( $key, 0, 5, 'reentry' );
+ $value2 = $this->cache->getScopedLock( $key, 0, 5, 'reentry' );
+
+ $this->assertType( 'ScopedCallback', $value1, 'First reentrant call returned lock' );
+ $this->assertType( 'ScopedCallback', $value1, 'Second reentrant call returned lock' );
}
}
diff --git a/tests/phpunit/includes/objectcache/MultiWriteBagOStuffTest.php b/tests/phpunit/includes/objectcache/MultiWriteBagOStuffTest.php
new file mode 100644
index 00000000..2b66181c
--- /dev/null
+++ b/tests/phpunit/includes/objectcache/MultiWriteBagOStuffTest.php
@@ -0,0 +1,55 @@
+cache1 = new HashBagOStuff();
+ $this->cache2 = new HashBagOStuff();
+ $this->cache = new MultiWriteBagOStuff( array(
+ 'caches' => array( $this->cache1, $this->cache2 ),
+ 'replication' => 'async'
+ ) );
+ }
+
+ public function testSetImmediate() {
+ $key = wfRandomString();
+ $value = wfRandomString();
+ $this->cache->set( $key, $value );
+
+ // Set in tier 1
+ $this->assertEquals( $value, $this->cache1->get( $key ), 'Written to tier 1' );
+ // Set in tier 2
+ $this->assertEquals( $value, $this->cache2->get( $key ), 'Written to tier 2' );
+ }
+
+ public function testSetDelayed() {
+ $key = wfRandomString();
+ $value = wfRandomString();
+
+ // XXX: DeferredUpdates bound to transactions in CLI mode
+ $dbw = wfGetDB( DB_MASTER );
+ $dbw->begin();
+ $this->cache->set( $key, $value );
+
+ // Set in tier 1
+ $this->assertEquals( $value, $this->cache1->get( $key ), 'Written to tier 1' );
+ // Not yet set in tier 2
+ $this->assertEquals( false, $this->cache2->get( $key ), 'Not written to tier 2' );
+
+ $dbw->commit();
+
+ // Set in tier 2
+ $this->assertEquals( $value, $this->cache2->get( $key ), 'Written to tier 2' );
+ }
+}
diff --git a/tests/phpunit/includes/objectcache/ReplicatedBagOStuffTest.php b/tests/phpunit/includes/objectcache/ReplicatedBagOStuffTest.php
new file mode 100644
index 00000000..a419f5b6
--- /dev/null
+++ b/tests/phpunit/includes/objectcache/ReplicatedBagOStuffTest.php
@@ -0,0 +1,62 @@
+writeCache = new HashBagOStuff();
+ $this->readCache = new HashBagOStuff();
+ $this->cache = new ReplicatedBagOStuff( array(
+ 'writeFactory' => $this->writeCache,
+ 'readFactory' => $this->readCache,
+ ) );
+ }
+
+ /**
+ * @covers ReplicatedBagOStuff::set
+ */
+ public function testSet() {
+ $key = wfRandomString();
+ $value = wfRandomString();
+ $this->cache->set( $key, $value );
+
+ // Write to master.
+ $this->assertEquals( $this->writeCache->get( $key ), $value );
+ // Don't write to slave. Replication is deferred to backend.
+ $this->assertEquals( $this->readCache->get( $key ), false );
+ }
+
+ /**
+ * @covers ReplicatedBagOStuff::get
+ */
+ public function testGet() {
+ $key = wfRandomString();
+
+ $write = wfRandomString();
+ $this->writeCache->set( $key, $write );
+ $read = wfRandomString();
+ $this->readCache->set( $key, $read );
+
+ // Read from slave.
+ $this->assertEquals( $this->cache->get( $key ), $read );
+ }
+
+ /**
+ * @covers ReplicatedBagOStuff::get
+ */
+ public function testGetAbsent() {
+ $key = wfRandomString();
+ $value = wfRandomString();
+ $this->writeCache->set( $key, $value );
+
+ // Don't read from master. No failover if value is absent.
+ $this->assertEquals( $this->cache->get( $key ), false );
+ }
+}
diff --git a/tests/phpunit/includes/objectcache/WANObjectCacheTest.php b/tests/phpunit/includes/objectcache/WANObjectCacheTest.php
new file mode 100644
index 00000000..40ae4613
--- /dev/null
+++ b/tests/phpunit/includes/objectcache/WANObjectCacheTest.php
@@ -0,0 +1,292 @@
+getCliArg( 'use-wanobjectcache' ) ) {
+ $name = $this->getCliArg( 'use-wanobjectcache' );
+
+ $this->cache = ObjectCache::getWANInstance( $name );
+ } else {
+ $this->cache = new WANObjectCache( array(
+ 'cache' => new HashBagOStuff(),
+ 'pool' => 'testcache-hash',
+ 'relayer' => new EventRelayerNull( array() )
+ ) );
+ }
+
+ $wanCache = TestingAccessWrapper::newFromObject( $this->cache );
+ $this->internalCache = $wanCache->cache;
+ }
+
+ /**
+ * @dataProvider provider_testSetAndGet
+ * @covers WANObjectCache::set()
+ * @covers WANObjectCache::get()
+ * @param mixed $value
+ * @param integer $ttl
+ */
+ public function testSetAndGet( $value, $ttl ) {
+ $key = wfRandomString();
+ $this->cache->set( $key, $value, $ttl );
+
+ $curTTL = null;
+ $this->assertEquals( $value, $this->cache->get( $key, $curTTL ) );
+ if ( is_infinite( $ttl ) || $ttl == 0 ) {
+ $this->assertTrue( is_infinite( $curTTL ), "Current TTL is infinite" );
+ } else {
+ $this->assertGreaterThan( 0, $curTTL, "Current TTL > 0" );
+ $this->assertLessThanOrEqual( $ttl, $curTTL, "Current TTL < nominal TTL" );
+ }
+ }
+
+ public static function provider_testSetAndGet() {
+ return array(
+ array( 14141, 3 ),
+ array( 3535.666, 3 ),
+ array( array(), 3 ),
+ array( null, 3 ),
+ array( '0', 3 ),
+ array( (object)array( 'meow' ), 3 ),
+ array( INF, 3 ),
+ array( '', 3 ),
+ array( 'pizzacat', INF ),
+ );
+ }
+
+ public function testGetNotExists() {
+ $key = wfRandomString();
+ $curTTL = null;
+ $value = $this->cache->get( $key, $curTTL );
+
+ $this->assertFalse( $value, "Non-existing key has false value" );
+ $this->assertNull( $curTTL, "Non-existing key has null current TTL" );
+ }
+
+ public function testSetOver() {
+ $key = wfRandomString();
+ for ( $i = 0; $i < 3; ++$i ) {
+ $value = wfRandomString();
+ $this->cache->set( $key, $value, 3 );
+
+ $this->assertEquals( $this->cache->get( $key ), $value );
+ }
+ }
+
+ /**
+ * @covers WANObjectCache::getWithSetCallback()
+ */
+ public function testGetWithSetCallback() {
+ $cache = $this->cache;
+
+ $key = wfRandomString();
+ $value = wfRandomString();
+ $cKey1 = wfRandomString();
+ $cKey2 = wfRandomString();
+
+ $wasSet = 0;
+ $func = function( $old, &$ttl ) use ( &$wasSet, $value ) {
+ ++$wasSet;
+ $ttl = 20; // override with another value
+ return $value;
+ };
+
+ $wasSet = 0;
+ $v = $cache->getWithSetCallback( $key, $func, 30, array(), array( 'lockTSE' => 5 ) );
+ $this->assertEquals( $v, $value );
+ $this->assertEquals( 1, $wasSet, "Value regenerated" );
+
+ $curTTL = null;
+ $v = $cache->get( $key, $curTTL );
+ $this->assertLessThanOrEqual( 20, $curTTL, 'Current TTL between 19-20 (overriden)' );
+ $this->assertGreaterThanOrEqual( 19, $curTTL, 'Current TTL between 19-20 (overriden)' );
+
+ $wasSet = 0;
+ $v = $cache->getWithSetCallback( $key, $func, 30, array(), array( 'lockTSE' => 5 ) );
+ $this->assertEquals( $v, $value );
+ $this->assertEquals( 0, $wasSet, "Value not regenerated" );
+
+ $priorTime = microtime( true );
+ usleep( 1 );
+ $wasSet = 0;
+ $v = $cache->getWithSetCallback( $key, $func, 30, array( $cKey1, $cKey2 ) );
+ $this->assertEquals( $v, $value );
+ $this->assertEquals( 1, $wasSet, "Value regenerated due to check keys" );
+ $t1 = $cache->getCheckKeyTime( $cKey1 );
+ $this->assertGreaterThanOrEqual( $priorTime, $t1, 'Check keys generated on miss' );
+ $t2 = $cache->getCheckKeyTime( $cKey2 );
+ $this->assertGreaterThanOrEqual( $priorTime, $t2, 'Check keys generated on miss' );
+
+ $priorTime = microtime( true );
+ $wasSet = 0;
+ $v = $cache->getWithSetCallback( $key, $func, 30, array( $cKey1, $cKey2 ) );
+ $this->assertEquals( $v, $value );
+ $this->assertEquals( 1, $wasSet, "Value regenerated due to still-recent check keys" );
+ $t1 = $cache->getCheckKeyTime( $cKey1 );
+ $this->assertLessThanOrEqual( $priorTime, $t1, 'Check keys did not change again' );
+ $t2 = $cache->getCheckKeyTime( $cKey2 );
+ $this->assertLessThanOrEqual( $priorTime, $t2, 'Check keys did not change again' );
+
+ $curTTL = null;
+ $v = $cache->get( $key, $curTTL, array( $cKey1, $cKey2 ) );
+ $this->assertEquals( $v, $value );
+ $this->assertLessThanOrEqual( 0, $curTTL, "Value has current TTL < 0 due to check keys" );
+ }
+
+ /**
+ * @covers WANObjectCache::getWithSetCallback()
+ */
+ public function testLockTSE() {
+ $cache = $this->cache;
+ $key = wfRandomString();
+ $value = wfRandomString();
+
+ $calls = 0;
+ $func = function() use ( &$calls, $value ) {
+ ++$calls;
+ return $value;
+ };
+
+ $cache->delete( $key );
+ $ret = $cache->getWithSetCallback( $key, 30, $func, array(), array( 'lockTSE' => 5 ) );
+ $this->assertEquals( $value, $ret );
+ $this->assertEquals( 1, $calls, 'Value was populated' );
+
+ // Acquire a lock to verify that getWithSetCallback uses lockTSE properly
+ $this->internalCache->lock( $key, 0 );
+ $ret = $cache->getWithSetCallback( $key, 30, $func, array(), array( 'lockTSE' => 5 ) );
+ $this->assertEquals( $value, $ret );
+ $this->assertEquals( 1, $calls, 'Callback was not used' );
+ }
+
+ /**
+ * @covers WANObjectCache::getMulti()
+ */
+ public function testGetMulti() {
+ $cache = $this->cache;
+
+ $value1 = array( 'this' => 'is', 'a' => 'test' );
+ $value2 = array( 'this' => 'is', 'another' => 'test' );
+
+ $key1 = wfRandomString();
+ $key2 = wfRandomString();
+ $key3 = wfRandomString();
+
+ $cache->set( $key1, $value1, 5 );
+ $cache->set( $key2, $value2, 10 );
+
+ $curTTLs = array();
+ $this->assertEquals(
+ array( $key1 => $value1, $key2 => $value2 ),
+ $cache->getMulti( array( $key1, $key2, $key3 ), $curTTLs )
+ );
+
+ $this->assertEquals( 2, count( $curTTLs ), "Two current TTLs in array" );
+ $this->assertGreaterThan( 0, $curTTLs[$key1], "Key 1 has current TTL > 0" );
+ $this->assertGreaterThan( 0, $curTTLs[$key2], "Key 2 has current TTL > 0" );
+
+ $cKey1 = wfRandomString();
+ $cKey2 = wfRandomString();
+ $curTTLs = array();
+ $this->assertEquals(
+ array( $key1 => $value1, $key2 => $value2 ),
+ $cache->getMulti( array( $key1, $key2, $key3 ), $curTTLs ),
+ 'Result array populated'
+ );
+
+ $priorTime = microtime( true );
+ usleep( 1 );
+ $curTTLs = array();
+ $this->assertEquals(
+ array( $key1 => $value1, $key2 => $value2 ),
+ $cache->getMulti( array( $key1, $key2, $key3 ), $curTTLs, array( $cKey1, $cKey2 ) ),
+ "Result array populated even with new check keys"
+ );
+ $t1 = $cache->getCheckKeyTime( $cKey1 );
+ $this->assertGreaterThanOrEqual( $priorTime, $t1, 'Check key 1 generated on miss' );
+ $t2 = $cache->getCheckKeyTime( $cKey2 );
+ $this->assertGreaterThanOrEqual( $priorTime, $t2, 'Check key 2 generated on miss' );
+ $this->assertEquals( 2, count( $curTTLs ), "Current TTLs array set" );
+ $this->assertLessThanOrEqual( 0, $curTTLs[$key1], 'Key 1 has current TTL <= 0' );
+ $this->assertLessThanOrEqual( 0, $curTTLs[$key2], 'Key 2 has current TTL <= 0' );
+
+ usleep( 1 );
+ $curTTLs = array();
+ $this->assertEquals(
+ array( $key1 => $value1, $key2 => $value2 ),
+ $cache->getMulti( array( $key1, $key2, $key3 ), $curTTLs, array( $cKey1, $cKey2 ) ),
+ "Result array still populated even with new check keys"
+ );
+ $this->assertEquals( 2, count( $curTTLs ), "Current TTLs still array set" );
+ $this->assertLessThan( 0, $curTTLs[$key1], 'Key 1 has negative current TTL' );
+ $this->assertLessThan( 0, $curTTLs[$key2], 'Key 2 has negative current TTL' );
+ }
+
+ /**
+ * @covers WANObjectCache::delete()
+ */
+ public function testDelete() {
+ $key = wfRandomString();
+ $value = wfRandomString();
+ $this->cache->set( $key, $value );
+
+ $curTTL = null;
+ $v = $this->cache->get( $key, $curTTL );
+ $this->assertEquals( $value, $v, "Key was created with value" );
+ $this->assertGreaterThan( 0, $curTTL, "Existing key has current TTL > 0" );
+
+ $this->cache->delete( $key );
+
+ $curTTL = null;
+ $v = $this->cache->get( $key, $curTTL );
+ $this->assertFalse( $v, "Deleted key has false value" );
+ $this->assertLessThan( 0, $curTTL, "Deleted key has current TTL < 0" );
+
+ $this->cache->set( $key, $value . 'more' );
+ $this->assertFalse( $v, "Deleted key is tombstoned and has false value" );
+ $this->assertLessThan( 0, $curTTL, "Deleted key is tombstoned and has current TTL < 0" );
+ }
+
+ /**
+ * @covers WANObjectCache::touchCheckKey()
+ * @covers WANObjectCache::resetCheckKey()
+ * @covers WANObjectCache::getCheckKeyTime()
+ */
+ public function testTouchKeys() {
+ $key = wfRandomString();
+
+ $priorTime = microtime( true );
+ usleep( 1 );
+ $t0 = $this->cache->getCheckKeyTime( $key );
+ $this->assertGreaterThanOrEqual( $priorTime, $t0, 'Check key auto-created' );
+
+ $priorTime = microtime( true );
+ usleep( 1 );
+ $this->cache->touchCheckKey( $key );
+ $t1 = $this->cache->getCheckKeyTime( $key );
+ $this->assertGreaterThanOrEqual( $priorTime, $t1, 'Check key created' );
+
+ $t2 = $this->cache->getCheckKeyTime( $key );
+ $this->assertEquals( $t1, $t2, 'Check key time did not change' );
+
+ usleep( 1 );
+ $this->cache->touchCheckKey( $key );
+ $t3 = $this->cache->getCheckKeyTime( $key );
+ $this->assertGreaterThan( $t2, $t3, 'Check key time increased' );
+
+ $t4 = $this->cache->getCheckKeyTime( $key );
+ $this->assertEquals( $t3, $t4, 'Check key time did not change' );
+
+ usleep( 1 );
+ $this->cache->resetCheckKey( $key );
+ $t5 = $this->cache->getCheckKeyTime( $key );
+ $this->assertGreaterThan( $t4, $t5, 'Check key time increased' );
+
+ $t6 = $this->cache->getCheckKeyTime( $key );
+ $this->assertEquals( $t5, $t6, 'Check key time did not change' );
+ }
+}
diff --git a/tests/phpunit/includes/parser/MagicVariableTest.php b/tests/phpunit/includes/parser/MagicVariableTest.php
index 17226113..cd54a9e3 100644
--- a/tests/phpunit/includes/parser/MagicVariableTest.php
+++ b/tests/phpunit/includes/parser/MagicVariableTest.php
@@ -10,6 +10,8 @@
* @copyright Copyright © 2011, Antoine Musso
* @file
* @todo covers tags
+ *
+ * @group Database
*/
class MagicVariableTest extends MediaWikiTestCase {
diff --git a/tests/phpunit/includes/parser/MediaWikiParserTest.php b/tests/phpunit/includes/parser/MediaWikiParserTest.php
index df891f5a..96ae3bec 100644
--- a/tests/phpunit/includes/parser/MediaWikiParserTest.php
+++ b/tests/phpunit/includes/parser/MediaWikiParserTest.php
@@ -91,7 +91,7 @@ class MediaWikiParserTest {
// enough to cause there to be separate names for different
// things, which is good enough for our purposes.
$extensionName = basename( dirname( $fileName ) );
- $testsName = $extensionName . '⁄' . basename( $fileName, '.txt' );
+ $testsName = $extensionName . '__' . basename( $fileName, '.txt' );
$escapedFileName = strtr( $fileName, array( "'" => "\\'", '\\' => '\\\\' ) );
$parserTestClassName = ucfirst( $testsName );
// Official spec for class names: http://php.net/manual/en/language.oop5.basic.php
diff --git a/tests/phpunit/includes/parser/NewParserTest.php b/tests/phpunit/includes/parser/NewParserTest.php
index 91aad10c..df7da98c 100644
--- a/tests/phpunit/includes/parser/NewParserTest.php
+++ b/tests/phpunit/includes/parser/NewParserTest.php
@@ -91,7 +91,7 @@ class NewParserTest extends MediaWikiTestCase {
);
$tmpGlobals['wgForeignFileRepos'] = array();
$tmpGlobals['wgDefaultExternalStore'] = array();
- $tmpGlobals['wgEnableParserCache'] = false;
+ $tmpGlobals['wgParserCacheType'] = CACHE_NONE;
$tmpGlobals['wgCapitalLinks'] = true;
$tmpGlobals['wgNoFollowLinks'] = true;
$tmpGlobals['wgNoFollowDomainExceptions'] = array();
@@ -106,7 +106,6 @@ class NewParserTest extends MediaWikiTestCase {
$tmpGlobals['wgAdaptiveMessageCache'] = true;
$tmpGlobals['wgUseDatabaseMessages'] = true;
$tmpGlobals['wgLocaltimezone'] = 'UTC';
- $tmpGlobals['wgDeferredUpdateList'] = array();
$tmpGlobals['wgGroupPermissions'] = array(
'*' => array(
'createaccount' => true,
@@ -160,10 +159,10 @@ class NewParserTest extends MediaWikiTestCase {
$this->djVuSupport = new DjVuSupport();
// Tidy support
$this->tidySupport = new TidySupport();
+ $tmpGlobals['wgTidyConfig'] = null;
$tmpGlobals['wgUseTidy'] = false;
- $tmpGlobals['wgAlwaysUseTidy'] = false;
$tmpGlobals['wgDebugTidy'] = false;
- $tmpGlobals['wgTidyConf'] = $IP . '/includes/tidy.conf';
+ $tmpGlobals['wgTidyConf'] = $IP . '/includes/tidy/tidy.conf';
$tmpGlobals['wgTidyOpts'] = '';
$tmpGlobals['wgTidyInternal'] = $this->tidySupport->isInternal();
@@ -185,6 +184,8 @@ class NewParserTest extends MediaWikiTestCase {
$wgNamespaceAliases['Image'] = $this->savedWeirdGlobals['image_alias'];
$wgNamespaceAliases['Image_talk'] = $this->savedWeirdGlobals['image_talk_alias'];
+ MWTidy::destroySingleton();
+
// Restore backends
RepoGroup::destroySingleton();
FileBackendGroup::destroySingleton();
@@ -454,6 +455,7 @@ class NewParserTest extends MediaWikiTestCase {
$GLOBALS[$var] = $val;
}
+ MWTidy::destroySingleton();
MagicWord::clearCache();
# The entries saved into RepoGroup cache with previous globals will be wrong.
diff --git a/tests/phpunit/includes/parser/ParserMethodsTest.php b/tests/phpunit/includes/parser/ParserMethodsTest.php
index 1790086a..af143caa 100644
--- a/tests/phpunit/includes/parser/ParserMethodsTest.php
+++ b/tests/phpunit/includes/parser/ParserMethodsTest.php
@@ -1,5 +1,9 @@
bar" ), array( "foo\nbar" ), array( "foo\rbar" ) );
}
- protected function setUp() {
- parent::setUp();
-
- $this->setMwGlobals( 'wgAlwaysUseTidy', false );
- }
-
/**
* @dataProvider provideValidNames
* @covers Parser::setHook
diff --git a/tests/phpunit/includes/parser/TidyTest.php b/tests/phpunit/includes/parser/TidyTest.php
index f656a74d..5db29080 100644
--- a/tests/phpunit/includes/parser/TidyTest.php
+++ b/tests/phpunit/includes/parser/TidyTest.php
@@ -7,8 +7,7 @@ class TidyTest extends MediaWikiTestCase {
protected function setUp() {
parent::setUp();
- $check = MWTidy::tidy( '' );
- if ( strpos( $check, '