3 require_once 'PHPUnit/Framework/TestCase.php';
5 class FormatTest extends PHPUnit_Framework_TestCase {
6 protected function setUp() {
8 'sfjp.group_name' => 'unittest',
9 'site_root_url' => 'http://sourceforge.jp',
10 'internal_url_regex' => '^http://sourceforge\.jp/',
11 'svn_base_url' => 'http://svn/view',
13 $this->p = new \sfjp\Wiki\Parser($context);
16 protected function tearDown() {
20 public function testNew() {
21 self::assertTrue(isset($this->p));
24 public function testParseSimpleRun() {
25 $this->try_parse('', '');
26 $this->try_parse('abc', '<p>abc</p>');
27 $this->try_parse("abc abc\nabc", "<p>abc abc\nabc</p>");
30 public function testParseHeadings() {
31 $this->try_parse('= abc =', '<h1 id="h1-abc">abc</h1>');
32 $this->try_parse("= 日本語 =\r\n", '<h1 id="h1-.E6.97.A5.E6.9C.AC.E8.AA.9E">日本語</h1>');
33 $this->try_parse('= abc', '<h1 id="h1-abc">abc</h1>');
34 $this->try_parse('= abc = ', '<h1 id="h1-abc">abc</h1>');
35 $this->try_parse('= abc ', '<h1 id="h1-abc">abc</h1>');
36 $this->try_parse('= abc = #moge', '<h1 id="moge">abc</h1>');
37 $this->try_parse('= abc #moge', '<h1 id="moge">abc</h1>');
38 $this->try_parse('=abc', '<p>=abc</p>');
39 $this->try_parse(' = abc', '<div class="indent">= abc</div>');
42 public function testParseListMark() {
56 $expect = '<ul><li>list1
63 </li></ul></li><li>level1 item
67 self::assertEquals($expect, $this->p->parse($text));
70 public function testParseMixedList() {
83 </li></ul><ol><li>ol num
84 </li></ol><ol style="list-style-type: lower-alpha;"><li>ol alpha
85 </li></ol><ol style="list-style-type: upper-alpha;"><li>ol ALPHA
87 </li></ul><ol style="list-style-type: lower-roman;"><li>ol roma
89 </li></ul><ol style="list-style-type: upper-roman;"><li>ol ROMA
91 self::assertEquals($expect, $this->p->parse($text));
104 * unordered in ordered
108 $expect = '<ul><li>list1
112 </li></ol></li><li>level1 item
113 <ul><li>level2 unordered
116 </li></ol></li><li>foo
117 </li></ul></li></ul><ol><li>level1 ordered
118 <ul><li>unordered in ordered
119 </li></ul></li><li>ordered list
121 self::assertEquals($expect, $this->p->parse($text));
125 public function testParseParagraph() {
126 self::assertEquals('yet', $this->p->parse('=abc'));
130 public function testParseListNum() {
141 $expect = '<ol><li>list1
143 </li><li>level2, too.
145 </li></ol></li><li>level1 item
149 self::assertEquals($expect, $this->p->parse($text));
153 public function testParseDefinitionList() {
154 self::assertEquals('yet', $this->p->parse('=abc'));
158 public function testParseHTMLEscape() {
159 $this->try_parse("'''>moge'''<", '<p><strong>>moge</strong><</p>');
162 public function testParseInlineBold() {
163 $this->try_parse("'''moge'''", '<p><strong>moge</strong></p>');
166 public function testParseInlineItalic() {
167 $this->try_parse("''abc''", '<p><em>abc</em></p>');
168 $this->try_parse("''ab", '<p><em>ab</em></p>');
169 $this->try_parse("ab ''bc\n''cd", "<p>ab <em>bc\n</em>cd</p>");
172 public function testParseInlineBolditalic() {
173 $this->try_parse("'''''moge'''''",
174 '<p><strong><em>moge</em></strong></p>');
175 $this->try_parse("'''''''''abc'",
176 "<p><strong><em><strong>'abc'</strong></em></strong></p>");
179 public function testParseInlineUndeline() {
180 $this->try_parse("__abc__",
181 '<p><span style="text-decoration: underline;">abc</span></p>');
184 public function testParseInlineStrike() {
185 $this->try_parse('~~abc~~', '<p><del>abc</del></p>');
186 $this->try_parse('~~~abcef~~~~~', '<p><del>~abcef</del><del>~</del></p>');
189 public function testParseInlineSuperscript() {
190 $this->try_parse('^ abc^', '<p><sup> abc</sup></p>');
191 $this->try_parse('^^^ abc ^^', '<p><sup></sup><sup> abc </sup><sup></sup></p>');
192 $this->try_parse("head ^ abc\ndef^tail", "<p>head <sup> abc\ndef</sup>tail</p>");
195 public function testParseInlineSubscript() {
196 $this->try_parse(',,abc ,,', '<p><sub>abc </sub></p>');
199 public function testParseLinks() {
200 $this->try_parse('http://url.com/path', '<p><a href="http://url.com/path" class="external" rel="nofollow">http://url.com/path</a></p>');
201 $this->try_parse('https://url.com/path', '<p><a href="https://url.com/path" class="external" rel="nofollow">https://url.com/path</a></p>');
204 public function testParseBlacketLink() {
206 '<p><a href="./a%2Fb%2F%E6%97%A5%E6%9C%AC%E8%AA%9E">a/b/日本語</a></p>',
207 $this->p->parse("[a/b/日本語]")
211 public function testParseLinkFragment() {
212 $this->try_parse('[test1#frag]', '<p><a href="./test1#frag">test1#frag</a></p>');
213 $this->try_parse('[test2#frag text]', '<p><a href="./test2#frag">text</a></p>');
214 $this->try_parse('wiki:test3#frag', '<p><a href="./test3#frag">wiki:test3#frag</a></p>');
216 $this->try_parse('wiki:"test4#frag"', '<p><a href="./test4#frag">wiki:"test4#frag"</a></p>');
217 $this->try_parse('["test5#frag" text]', '<p><a href="./test5#frag">text</a></p>');
218 $this->try_parse('[wiki:"test6#frag" text]', '<p><a href="./test6#frag">text</a></p>');
219 $this->try_parse('[wiki:"test7 page name#frag" text]', '<p><a href="./test7%20page%20name#frag">text</a></p>');
220 $this->try_parse('[#frag]', '<p><a href="#frag">#frag</a></p>');
221 $this->try_parse('["#frag" text]', '<p><a href="#frag">text</a></p>');
225 public function testParseQuote() {
227 "<blockquote class=\"citation\"><blockquote class=\"citation\"><p>abc
228 </p></blockquote><p>def
230 </p><blockquote class=\"citation\"><blockquote class=\"citation\"><p>jkl
231 </p></blockquote></blockquote></blockquote><p>normal</p>",
232 $this->p->parse(">> abc\n> def\n> ghi\n>>> jkl\nnormal")
234 $this->try_parse("> abc\n> > with space\n> > > 3rd", '<blockquote class="citation"><p>abc
235 </p><blockquote class="citation"><p>with space
236 </p><blockquote class="citation"><p> 3rd</p></blockquote></blockquote></blockquote>');
239 public function testParseIndent() {
240 $this->try_parse(" abc", '<div class="indent">abc</div>');
241 $this->try_parse(" abc\n def\nghi",
242 '<div class="indent">abc
245 self::assertEquals('<div class="indent">abc
247 </div><div class="indent"><div class="indent">2nd nest
248 </div></div><div class="indent"><div class="indent"><div class="indent">3rd
249 </div></div></div><div class="indent"><div class="indent">2nd
250 </div></div><ul><li>clear by list</li></ul>',
251 $this->p->parse(" abc\n def\n 2nd nest\n 3rd\n 2nd\n * clear by list"));
254 public function testParseInternalURIPrweb() {
255 $this->try_parse("prweb:/", '<p><a href="http://unittest.sourceforge.jp/" class="project-web">prweb:/</a></p>');
256 $this->try_parse("prweb:/path/to/file", '<p><a href="http://unittest.sourceforge.jp/path/to/file" class="project-web">prweb:/path/to/file</a></p>');
257 $this->try_parse("prweb:project-name:/url-to/the.page", '<p><a href="http://project-name.sourceforge.jp/url-to/the.page" class="project-web">prweb:project-name:/url-to/the.page</a></p>');
260 public function testParseInternalURIUser() {
261 $this->try_parse("user:sugi", '<p><a href="/users/sugi" class="user">user:sugi</a></p>');
262 $this->try_parse("id:sugi", '<p><a href="/users/sugi" class="user">id:sugi</a></p>');
263 $this->try_parse("users:sugi", '<p><a href="/users/sugi" class="user">users:sugi</a></p>');
266 public function testParseURIMailTo() {
267 $this->try_parse("mailto:sugi@osdn.jp", '<p><a href="mailto:sugi@osdn.jp" class="mail">mailto:sugi@osdn.jp</a></p>');
268 $this->try_parse("[mailto:a.b=c+d@e.f メール]", '<p><a href="mailto:a.b=c+d@e.f" class="mail">メール</a></p>');
269 $this->try_parse("mailto:bad@てすと", '<p>mailto:bad@てすと</p>');
272 public function testParseEscape() {
273 $this->try_parse("!`", '<p>`</p>');
274 $this->try_parse("!^てすと!^", '<p>^てすと^</p>');
275 $this->try_parse("!~~", '<p>~~</p>');
276 $this->try_parse("!__", '<p>__</p>');
277 $this->try_parse("!WikiName", '<p>WikiName</p>');
278 $this->try_parse("![[Plugin]]", '<p>[[Plugin]]</p>');
279 $this->try_parse("!!", '<p>!!</p>');
282 public function testParseEscapeBlock() {
283 $this->try_parse("!> Equote", '<p>> Equote</p>');
284 $this->try_parse("!------", '<p>------</p>');
285 $this->try_parse("!||escaped||table||", '<p>||escaped||table||</p>');
286 $this->try_parse("!= not header =", '<p>= not header =</p>');
287 $this->try_parse(" !* abc", '<div class="indent">* abc</div>');
290 public function testHttpUrl() {
291 self::assertTrue(!!$this->p->processor->gen_uri_link("http://てすと"));
292 self::assertTrue(!!$this->p->processor->gen_uri_link("http://abc"));
293 self::assertTrue(!$this->p->processor->gen_uri_link("http://"));
294 self::assertTrue(!$this->p->processor->gen_uri_link("http:// abc"));
297 public function testIsbnLink() {
298 $this->try_parse("isbn:123",
299 '<p><a href="http://www.amazon.co.jp/gp/product/123" class="isbnbook" rel="nofollow">isbn:123</a></p>');
300 $this->p->setContext(array('amazon_affiliate_id' => 'afid-test'));
301 $this->try_parse("isbn:123",
302 '<p><a href="http://www.amazon.co.jp/gp/product/123?tag=afid-test&linkCode=as2&camp=247&creative=1211&creativeASIN=123" class="isbnbook" rel="nofollow">isbn:123</a></p>');
305 public function testParseGroupWikiPage() {
306 $this->try_parse('wiki:groupname:PageName', '<p><a href="http://sourceforge.jp/projects/groupname/wiki/PageName" class="external-wiki">wiki:groupname:PageName</a></p>');
307 $this->try_parse('wiki:group-name:PageName', '<p><a href="http://sourceforge.jp/projects/group-name/wiki/PageName" class="external-wiki">wiki:group-name:PageName</a></p>');
308 $this->try_parse('wiki:group_name:PageName', '<p><a href="./group_name">wiki:group_name</a>:<a href="./PageName">PageName</a></p>');
312 public function testParseOrer() {
313 $this->try_parse('[PageName [[BR]]]',
314 '<p><a href="./PageName">[[BR</a>]]</p>');
315 /* do not support currently
316 $this->try_parse("abc'''def[PageName la''bee''eel]tex'''t",
317 '<p>abc<b>def<a href="./PageName">la<i>bee</i>eel</a>tex</b>t</p>');
319 $this->try_parse("abc'''def[PageName la''bee''eel]tex'''t",
320 "<p>abc<strong>def<a href=\"./PageName\">la''bee''eel</a>tex</strong>t</p>");
322 $this->try_parse('[__Page,,Name^^ label]', '<p><a href="./__Page%2C%2CName%5E%5E">label</a></p>');
323 $this->try_parse('["__Page,,Name^^" label]', '<p><a href="./__Page%2C%2CName%5E%5E">label</a></p>');
324 $this->try_parse('[wiki:"__Page,,Name^^" label]', '<p><a href="./__Page%2C%2CName%5E%5E">label</a></p>');
325 $this->try_parse('http://aaaa[bbb]ccc', '<p><a href="http://aaaa" class="external" rel="nofollow">http://aaaa</a><a href="./bbb">bbb</a>ccc</p>');
326 $this->try_parse('!http://aaaa[bbb]ccc', '<p>http://aaaa<a href="./bbb">bbb</a>ccc</p>');
327 $this->try_parse('http://aaaa![bbb]ccc', '<p><a href="http://aaaa" class="external" rel="nofollow">http://aaaa</a>[bbb]ccc</p>');
328 $this->try_parse('!http://aaaa![bbb]ccc', '<p>http://aaaa[bbb]ccc</p>');
331 public function testQuotedLink() {
332 $this->try_parse('["test page__ name"]', '<p><a href="./test%20page__%20name">test page__ name</a></p>');
333 $this->try_parse('["a b c" label]', '<p><a href="./a%20b%20c">label</a></p>');
334 $this->try_parse('[wiki:"a b c" label]', '<p><a href="./a%20b%20c">label</a></p>');
335 $this->try_parse('wiki:",,a b c__"', '<p><a href="./%2C%2Ca%20b%20c__">wiki:",,a b c__"</a></p>');
338 public function testBracket() {
339 $this->try_parse('[http://www label]', '<p><a href="http://www" class="external" rel="nofollow">label</a></p>');
340 $this->try_parse('[WikiName label]', '<p><a href="./WikiName">label</a></p>');
341 $this->try_parse('[normal text]', '<p><a href="./normal">text</a></p>');
344 public function testParseFalseLink() {
345 $this->try_parse("[0]", '<p><a href="./0">0</a></p>');
346 $this->try_parse('["0"]', '<p><a href="./0">0</a></p>');
347 $this->try_parse("[0 text]", '<p><a href="./0">text</a></p>');
348 $this->try_parse("[0#0]", '<p><a href="./0#badid-0">0#0</a></p>');
349 $this->try_parse('["0#0" text]', '<p><a href="./0#badid-0">text</a></p>');
350 $this->try_parse("wiki:0", '<p><a href="./0">wiki:0</a></p>');
351 $this->try_parse("wiki:0#0", '<p><a href="./0#badid-0">wiki:0#0</a></p>');
352 $this->try_parse("[#0]", '<p><a href="#badid-0">#0</a></p>');
353 $this->try_parse("[#0 text]", '<p><a href="#badid-0">text</a></p>');
356 public function testTableAndHr() {
364 '<hr /><table class="wikitable"><tbody><tr><td>table</td></tr></tbody></table><hr /><table class="wikitable"><tbody><tr><td>table</td></tr></tbody></table><hr />');
368 public function testBlock() {
369 $this->try_parse("{{{
374 $this->try_parse("{{{
380 public function testInlinePreformatted() {
381 $this->try_parse("''ab''c''d{{{ef g''}} }}}h''}}}i''j.",
382 "<p><em>ab</em>c<em>d<tt>ef g''}} </tt>h</em>}}}i<em>j.</em></p>");
385 public function testInternalLink() {
386 $this->try_parse("[http://www.yahoo.co.jp/ external]",
387 '<p><a href="http://www.yahoo.co.jp/" class="external" rel="nofollow">external</a></p>');
388 $this->try_parse("[http://sourceforge.jp/ internal]",
389 '<p><a href="http://sourceforge.jp/">internal</a></p>');
390 $this->try_parse("[http://sourceforge.jp/projects/test/moge internal]",
391 '<p><a href="http://sourceforge.jp/projects/test/moge">internal</a></p>');
392 $this->try_parse("[http://test.sourceforge.jp/ external]",
393 '<p><a href="http://test.sourceforge.jp/" class="external" rel="nofollow">external</a></p>');
396 public function testHeadingCounter() {
403 '<h2 id="h2-a">a</h2><h2 id="h2-b">b</h2><h2 id="h2-a-2">a</h2><h2 id="h2-a-3">a</h2>');
406 public function testUselessParagraph() {
407 $po_out = '<div class="pageoutline"><div class="pageoutline-title"><div class="action"><button type="button" onClick="javascript:togglePageOutline(this)"><img src="//static.sourceforge.jp/wiki/images/icons/roll-up.gif" border="0"></button></div>Outline</div></div>';
408 $this->try_parse("[[PageOutline]]
442 </p><i>html block</i>
448 public function testTableAndHTMLBlockBug() {
449 $this->try_parse('||table||
452 }}}', '<table class="wikitable"><tbody><tr><td>table</td></tr></tbody></table><ins>HTML</ins>
456 public function testSlashLinks() {
457 $this->try_parse('[/path/to/]', '<p><a href="/path/to/">/path/to/</a></p>');
458 $this->try_parse('[/path/to/ moge]', '<p><a href="/path/to/">moge</a></p>');
459 $this->try_parse('[//server.com/path moge]', '<p><a href="//server.com/path">moge</a></p>');
462 public function testTicketComment() {
463 $this->try_parse('comment:4:15142:1235097254',
464 '<p><a href="http://sourceforge.jp/ticket/browse.php?group_id=4&tid=15142#comment:4:15142:1235097254" class="ticket">comment:4:15142:1235097254</a></p>');
465 $this->try_parse('comment:1 comment:foo', '<p>comment:1 comment:foo</p>');
466 $this->try_parse('[comment:4:15142:1235097254 hiromichi-m] への返信',
467 '<p><a href="http://sourceforge.jp/ticket/browse.php?group_id=4&tid=15142#comment:4:15142:1235097254" class="ticket">hiromichi-m</a> への返信</p>');
468 $this->try_parse('[comment::123:456 グループID省略]なコメント', '<p><a href="http://sourceforge.jp/ticket/detail.php?id=123&cid=456" class="ticket">グループID省略</a>なコメント</p>');
469 $this->try_parse('[comment::123:456 グループID0]なコメントリンク', '<p><a href="http://sourceforge.jp/ticket/detail.php?id=123&cid=456" class="ticket">グループID0</a>なコメントリンク</p>');
470 $this->try_parse('[comment:123:456 2引数]なコメントリンク', '<p><a href="http://sourceforge.jp/ticket/detail.php?id=123&cid=456" class="ticket">2引数</a>なコメントリンク</p>');
473 public function testIRI() {
474 $iri = 'http://假定された有機交流電燈の.ひとつの青い照明です/';
475 $url = 'http://%E5%81%87%E5%AE%9A%E3%81%95%E3%82%8C%E3%81%9F%E6%9C%89%E6%A9%9F%E4%BA%A4%E6%B5%81%E9%9B%BB%E7%87%88%E3%81%AE.%E3%81%B2%E3%81%A8%E3%81%A4%E3%81%AE%E9%9D%92%E3%81%84%E7%85%A7%E6%98%8E%E3%81%A7%E3%81%99/';
476 $this->try_parse("$iri ひかりはたもち、その電燈は失はれ", "<p><a href=\"{$url}\" class=\"external\" rel=\"nofollow\">$iri</a> ひかりはたもち、その電燈は失はれ</p>");
477 $this->try_parse("[$iri]", "<p><a href=\"$url\" class=\"external\" rel=\"nofollow\">$iri</a></p>");
478 $this->try_parse("[$iri ひかりはたもち、その電燈は失はれ]", "<p><a href=\"$url\" class=\"external\" rel=\"nofollow\">ひかりはたもち、その電燈は失はれ</a></p>");
479 $this->try_parse('[/納豆.html ひきわり]', '<p><a href="/%E7%B4%8D%E8%B1%86.html">ひきわり</a></p>');
482 public function testSVNRev() {
483 $a_attr = 'href="http://svn/view?view=rev&root=unittest&revision=123" class="svn"';
484 $this->try_parse('r123', "<p><a $a_attr>r123</a></p>");
485 $this->try_parse('abcr123', '<p>abcr123</p>');
486 $this->try_parse('r123abc', '<p>r123abc</p>');
487 $this->try_parse('lead r123 trail', "<p>lead <a $a_attr>r123</a> trail</p>");
488 $this->try_parse('日本語r123テキスト', "<p>日本語<a $a_attr>r123</a>テキスト</p>");
492 public function testWithUTF8() {
493 ini_set('default_charset', 'utf-8');
494 ini_set('mbstring.internal_encoding', 'utf-8');
495 ini_set('mbstring.detect_order', 'EUC-JP,UTF-8,SJIS,JIS');
496 ini_set('mbstring.language', 'Japanese');
497 $input = '!SourceForge.JPシステムのバグを見つけた場合には [/projects/sourceforge/ticket?type%5B%5D=113&status%5B%5D=1 バグ]、
498 CVSリポジトリの調整やアカウント削除等のサポート要求は [/projects/sourceforge/ticket?type%5B%5D=114&status%5B%5D=1 サポートリクエスト]へ、システムへの追加機能の要望等は [/projects/sourceforge/ticket?type%5B%5D=115&status%5B%5D=1 機能リクエスト]へ登録いただくようお願いいたします。その他の問い合わせについては、[/docs/SourceForge.JP%E3%81%AE%E9%80%A3%E7%B5%A1%E5%85%88 連絡先についての文書]をよくお読みください。';
499 $exp = '<p>SourceForge.JPシステムのバグを見つけた場合には <a href="/projects/sourceforge/ticket?type%5B%5D=113&status%5B%5D=1">バグ</a>、
500 CVSリポジトリの調整やアカウント削除等のサポート要求は <a href="/projects/sourceforge/ticket?type%5B%5D=114&status%5B%5D=1">サポートリクエスト</a>へ、システムへの追加機能の要望等は <a href="/projects/sourceforge/ticket?type%5B%5D=115&status%5B%5D=1">機能リクエスト</a>へ登録いただくようお願いいたします。その他の問い合わせについては、<a href="/docs/SourceForge.JP%E3%81%AE%E9%80%A3%E7%B5%A1%E5%85%88">連絡先についての文書</a>をよくお読みください。</p>';
501 $this->try_parse($input, $exp);
504 public function testTracKeepNewLineMode() {
505 $this->p->setContext(array('trac.keep_newline' => true));
527 <br /></p><p>パラグラフは適切に分割される必要がある
528 <br /></p><blockquote class="citation"><p>block
531 <br /></p></blockquote><p>さて
537 ', '<ul><li>リストでも改行保持
543 public function testInlinePluginAtStartOfLine() {
544 $this->try_parse('[[br]]test!', '<p><br />test!</p>');
547 public function testHashTrackerLink() {
548 $this->try_parse('#10', '<p><a href="http://sourceforge.jp/tracker.php?id=10" class="tracker">#10</a></p>');
549 $this->try_parse('#50010', '<p><a href="http://sourceforge.jp/ticket/detail.php?id=50010" class="tracker">#50010</a></p>');
553 public function testDisabledLinkWithExclamation() {
555 'sfjp.group_name' => 'unittest',
556 'site_root_url' => 'http://sourceforge.jp',
557 'internal_url_regex' => '^http://sourceforge\.jp/',
558 'svn_base_url' => 'http://svn/view',
559 'disable.link.CamelCase' => true,
561 $p = new \sfjp\Wiki\Parser($context);
562 self::assertEquals('<p>CamelCase</p>', $p->parse('!CamelCase'));
566 protected function try_parse($text, $expect) {
567 self::assertEquals($expect, $this->p->parse($text));
572 // vim: set sts=4 sw=4 expandtab: